- Referencing a COM Component in Visual Studio .NET
- Referencing a COM Component Using Only the .NET Framework SDK
- Example: A Spoken Hello, World Using the Microsoft Speech API
- The Type Library Importer
- Using COM Objects in ASP.NET Pages
- An Introduction to Interop Marshaling
- Common Interactions with COM Objects
- Using ActiveX Controls in .NET Applications
- Deploying a .NET Application That Uses COM
- Example: Using Microsoft Word to Check Spelling
- Conclusion
Using ActiveX Controls in .NET Applications
The terms ActiveX control and COM component are often used interchangeably, but in this book an ActiveX control is a special kind of COM component that supports being hosted in an ActiveX container. Such objects typically implement several interfaces such as IOleObject, IOleInPlaceObject, IOleControl, IDataObject, and more. They are typically registered specially as a control (as opposed to a simple class) and are marked with the [control] IDL attribute in their type libraries. They also usually have a graphical user interface.
The .NET equivalent of ActiveX controls are Windows Forms controls. Just as it's possible to expose and use COM objects as if they are .NET objects, it's possible to expose and use ActiveX controls as if they are Windows Forms controls. First we'll look at the process of referencing an ActiveX control in Visual Studio .NET, then how to do it with a .NET Framework SDK utility. Finally, we'll look at an example of hosting and using the control on a .NET Windows Form. For these examples, we'll use the WebBrowser control located in the Microsoft Internet Controls type library (SHDOCVW.DLL).
Referencing an ActiveX Control in Visual Studio .NET
If you referenced the Microsoft Internet Controls type library as you would any other type library, then the WebBrowser class could only be used like an ordinary object; you wouldn't be able to drag and drop it on a form. Using ActiveX controls as Windows Forms controls requires these steps:
Start Visual Studio .NET and create either a new Visual Basic .NET Windows application or a Visual C# Windows application. The remaining steps apply to either language.
-
Select Tools, Customize Toolbox... from the menu, or right-click inside the Toolbox window and select Customize Toolbox... from the context menu. There are two kinds of controls that can be referenced: COM Components and .NET Framework Components. The default COM Components tab shows a list of all the registered ActiveX controls on the computer. This dialog is shown in Figure 3.12.
Select the desired control, then click the OK button.
Figure 3.12 Adding a reference to an ActiveX control in Visual Studio .NET.
If these steps succeeded, then an icon for the control should appear in the Toolbox window. Select it and drag an instance of the control onto your form just as you would with any Windows Forms control. At this point, at least two assemblies are added to your project's referencesan Interop Assembly for the ActiveX control's type library (and any dependent Interop Assemblies), and an ActiveX Assembly that wraps any ActiveX controls inside the type library as special Windows Forms controls. This ActiveX Assembly always has the same name as the Interop Assembly, but with an Ax prefix. Figure 3.13 shows these two assemblies that appear in the Solution Explorer window when referencing and using the WebBrowser ActiveX control.
Figure 3.13 The Solution Explorer after an ActiveX control has been added to a Windows Form.
Referencing an ActiveX Control Using Only the .NET Framework SDK
Now, let's look at how to accomplish the same task using only the .NET Framework SDK. The following example uses the .NET ActiveX Control to Windows Forms Assembly Generator (AXIMP.EXE), also known as the ActiveX importer. This utility is the TLBIMP.EXE of the Windows Forms world, and can be used as follows:
-
From a command prompt, type the following (replacing the path with the location of SHDOCVW.DLL on your computer):
AxImp C:\Windows\System32\shdocvw.dll
This produces both an Interop Assembly (SHDocVw.dll) and ActiveX Assembly (AxSHDocVw.dll) for the input type library in the current directory. Unlike TLBIMP.EXE, AXIMP.EXE does not search for the input file using the PATH environment variable.
-
Reference the ActiveX Assembly just as you would any other assembly, which depends on the language. Depending on the nature of your application, you might also have to reference the Interop Assembly, the System.Windows.Forms assembly, and more.
The Interop Assembly created by AXIMP.EXE is no different from the one created by TLBIMP.EXE. If a Primary Interop Assembly for the input type library is registered on the current computer, AXIMP.EXE references that assembly rather than generating a new one.
If no ActiveX control can be found in an input type library, AXIMP.EXE reports:
AxImp Error: Did not find any registered ActiveX control in '...'.
In order for AXIMP.EXE to recognize a COM class as an ActiveX control, it must be registered on the current computer with the following registry value:
HKEY_CLASSES_ROOT\CLSID\{CLSID}\Control
Being marked in the type library with the [control] attribute is irrelevant.
Example: A Simple Web Browser
Now that we know how to generate and reference an ActiveX Assembly that wraps an ActiveX control as a Windows Forms control, we'll put together a short example that uses an ActiveX control in managed code. Listing 3.4 demonstrates the use of the WebBrowser control to create a simple Web browser application, pictured in Figure 3.14. Parts of the listing are omitted, but the complete source code is available on this book's Web site.
Figure 3.14 The simple Web browser.
Listing 3.4 MyWebBrowser.cs. Using the WebBrowser ActiveX Control in C#
1: using System; 2: using SHDocVw; 3: using System.Windows.Forms; 4: 5: public class MyWebBrowser : Form 6: { 7: ... 8: object m = Type.Missing; 9: 10: // Constructor 11: public MyWebBrowser() 12: { 13: // Required for Windows Form Designer support 14: InitializeComponent(); 15: // Start on the home page 16: axWebBrowser1.GoHome(); 17: } 18: 19: // Clean up any resources being used 20: protected override void Dispose( bool disposing ) 21: { 22: if (disposing) 23: { 24: if (components != null) 25: { 26: components.Dispose(); 27: } 28: } 29: base.Dispose(disposing); 30: } 31: 32: // Required method for Designer support 33: private void InitializeComponent() 34: { 35: ... 36: this.axWebBrowser1 = new AxSHDocVw.AxWebBrowser(); 37: ... 38: ((System.ComponentModel.ISupportInitialize) 39: (this.axWebBrowser1)).BeginInit(); 40: ... 41: this.axWebBrowser1.OcxState = ((System.Windows.Forms.AxHost.State) 42: (resources.GetObject("axWebBrowser1.OcxState"))); 43: ... 44: ((System.ComponentModel.ISupportInitialize) 45: (this.axWebBrowser1)).EndInit(); 46: ... 47: } 48: 49: [STAThread] 50: static void Main() 51: { 52: Application.Run(new MyWebBrowser()); 53: } 54: 55: // Called when one of the toolbar buttons is clicked 56: private void toolBar1_ButtonClick(object sender, 57: ToolBarButtonClickEventArgs e) 58: { 59: if (e.Button.Text == "Back") 60: { 61: try { axWebBrowser1.GoBack(); } 62: catch {} 63: } 64: else if (e.Button.Text == "Forward") 65: { 66: try { axWebBrowser1.GoForward(); } 67: catch {} 68: } 69: else if (e.Button.Text == "Stop") 70: { 71: axWebBrowser1.Stop(); 72: } 73: else if (e.Button.Text == "Refresh") 74: { 75: axWebBrowser1.CtlRefresh(); 76: } 77: else if (e.Button.Text == "Home") 78: { 79: axWebBrowser1.GoHome(); 80: } 81: } 82: 83: // Called when "Go" is clicked 84: private void goButton_Click(object sender, System.EventArgs e) 85: { 86: axWebBrowser1.Navigate(navigateBox.Text, ref m, ref m, ref m, ref m); 87: } 88: }
Line 8 declares a Missing instance used for optional parameters in Line 86. The constructor in Lines 1117 first calls the standard InitializeComponent method to initialize the form's user interface, then calls GoHome on the ActiveX control to browse to the user's home page.
Lines 3347 contain a few of the lines inside InitializeComponent that relate to the ActiveX control. Although the class is called WebBrowser, the class created by the ActiveX importer always begins with an Ax prefix. Therefore, Line 36 instantiates a new AxWebBrowser object. Lines 5681 contain the event handler that gets called whenever the user clicks on one of the buttons across the top of the form. Whenever the Back and Forward buttons are clicked, the GoBack and GoForward methods are called, respectively. Because these methods throw an exception if there is no page to move to, any exception is caught and ignored. This is not the ideal way to implement these buttons, but it will have to wait until Chapter 5.
Notice that Line 75 calls a method called CtlRefresh, although the original WebBrowser control doesn't have such a method. What happens here is that any class created by the ActiveX importer ultimately derives from System.Windows.Forms.Control, and this class already has a property called Refresh. To distinguish members of the ActiveX control from members of the wrapper's base classes, the ActiveX importer places a Ctl prefix (which stands for control) on any members with conflicting names. The AxWebBrowser class has many other renamed members due to name conflictsCtlContainer, CtlHeight, CtlLeft, CtlParent, CtlTop, CtlVisible, and CtlWidth.
Finally, Lines 8487 call the ActiveX control's Navigate method when the user clicks the Go button.