
by Ronald W. Terry
Based on the Component Object Model, an ActiveX component exposes its objects for use by another unit of executable code. This implies a client/server relationship in that a client requests objects from the ActiveX server, which in turn performs services for the client. The client itself can be an ActiveX component, which in turn acts as a server and exposes objects to another client.
This relationship can be carried out on a single machine where the client and the server reside locally, or the client and server can be on separate machines in which the server is called a remote server. This chapter discusses the techniques of using the various types of ActiveX components in a client/server environment with the two most prominent client/server development tools today: Visual Basic and Visual C++. Visual Basic has been a highly successful front-end development tool dealing with capturing and displaying information for users. Although Visual C++ can equally develop the forms and dialog boxes that comprise a user interface, its niche in the client/server development environment has been in the business rules tier. This tier is comprised of objects with little or no user interface and with the primary task of performing the computationally intensive algorithms for data transformations.
ActiveX components come in a wide variety of functionality that seems to be limited only by component developers' imaginations. From user interfaces that capture and display data in an elegant manner to complex behind-the-scenes business calculations, an ActiveX component can become a versatile building block in developing client/server applications.
As with any building block--whether it's a brick for a building or an object for a software application--it's not as important for you to learn the innermost workings or how the building block was produced to be an effective user. Instead, learning the behavior and limitations of the building block, along with being proficient with the techniques and tools used to adhere multiple blocks together, is of utmost importance in producing an effective composite structure.
The following sections focus on the different types of ActiveX components typical in a client/server application, their key characteristics, and in which tier they're most effective. The techniques of installing and registering components are also covered. How the component is registered in the Windows Registry determines where the component is located and the security factors involved for client access. You also see how to access remote components (executed on a separate machine) by using the Remote Automation and DCOM transports.
You can categorize components used in a client/server environment into three types: ActiveX controls, ActiveX documents, and ActiveX code components. Figure 9.1 shows a typical three-tiered client/server application depicting where each type normally would be incorporated. The front-end or user-interface tier would be composed of forms and dialog boxes consisting of ActiveX controls. These controls would capture or display data for the user and pass/retrieve it to the business tier. The components on the business tier massage the data, perform calculations, and provide results back to the components in the user interface tier. Also, the business components can pass the data to the data tier. Components in the data tier contain the necessary logic to set and retrieve data from the database.
FIG. 9.1
ActiveX component types in a client/server environment.
These components can all reside on the client machine, creating what's known as a fat client, or be distributed among many machines. For instance, the user-interface tier would reside on the client machine, the business-tier objects would reside on a dedicated machine chosen for performance, and the data-tier objects would reside on the same machine as the database engine.
Deciding how the components will be distributed involves trade studies based on the environment in which they'll be used. Consider these key issues when distributing components:
The following sections explain in more detail the three different categories of ActiveX components and their uses. A how-to guide in installing and registering components for use by clients locally or remotely follows.
ActiveX Controls ActiveX controls are components that provide some form of interface between users and the application, such as a text box or a command button. ActiveX controls are assembled on forms or dialog boxes and are part of the user-interface tier. They expose properties that can be set at design time to adjust the look and feel of the control. Properties can also be accessed at runtime, as well as the controls' methods and events, which allows controls to respond to different needs of the application as it's executing. ActiveX controls are the most common components. Although they're easily created with any of the Visual Studio development tools (as you've seen in earlier chapters), they're more commonly provided by third-party developers. ActiveX controls are in-process servers that are compiled into files with the extensions of .ocx (most common) or .dll. These files are copied to the client machine hard drive and expose functions that enable the control to register itself through the use of special utilities.
ActiveX Documents ActiveX documents are special components hosted in document containers such as a web browser, Microsoft Office Binder, Visual Basic 5.0 IDE, or a container that you created. Through an additional set of interfaces supported by the ActiveX document, containers can provide a view port into the document's data. Unlike ActiveX controls, documents are displayed full frame in their host (see Figure 9.2) and can take control of their host to some extent. When a document is viewed, the document menus are merged with those of the containers to give users the impression that they're working with an application rather than a container.
FIG. 9.2
ActiveX documents can reside in many different containers. As shown here, a Word
document can reside in Internet Explorer or Office Binder.
With the popularity of web-based applications, it's no wonder that the focus of implementing ActiveX documents was placed on web browsers. Although a container can be easily created by using the SHDOCVW.DLL file installed by Internet Explorer 4.0, working with documents is addressed in Chapter 11, "An Inside Look at Web-Based Applications," where ActiveX components in the Internet environment are addressed.
ActiveX Code Components ActiveX code components, formerly referred to as OLE Automation servers, have little or no user interface. Code components are used primarily to implement business rules behind the scenes and can reside in all tiers of a client/server application. Client applications use objects created from the classes exposed by the components and manipulate them through the properties, methods, and events provided. Through the properties, methods, and events exposed to the client--collectively called the class interface--components are "glued" together to produce an application.
ActiveX code components can be packaged as in-process or out-of-process servers, with the former residing in files with the .dll extension and the latter in .exe files. Like ActiveX controls, code components expose self-registration functions and are accompanied by a type library (.tlb) file. Visual Basic and Visual C++ development tools use this type library file to obtain information on the components interface at design time.
ActiveX components are normally installed by a setup program, provided with the application that uses the component, and placed in the System32 directory. If a component isn't associated with any setup program, simply copy the file containing the component to the hard drive. Locating files containing ActiveX components in one location (such as the System32 directory) is a good idea.
According to ActiveX standards, ActiveX components must be self-registering, which, for an in-process control or code component, means implementing and exporting the DllRegisterServer and DllUnregisterServer functions. If the components were installed with an application such as Visual Basic or Visual C++, they most likely were placed in the \Windows\System or System32 directory by their respective setup program and registered with the system Registry behind the scenes.
If the in-process component was developed locally or copied to the local machine without a setup program, the component will need to be registered manually. This is accomplished with the Regsvr32.exe command-line utility located in the \Windows\System or \System32 directory. Regsvr32 takes advantage of several command-line arguments (see Figure 9.3).
FIG. 9.3
The Regsvr32 utility's command-line arguments.
To register an ActiveX in-process component, simply choose Run from the Start menu and enter the following:
Regsvr32.exe <DLL or OCX File Name>
Similarly, to unregister the component, enter the following:
Regsvr32.exe <DLL or OCX File Name> /u
TIP: If you're registering in-process ActiveX components often, associate DLL and OCX files with the Regsvr32 utility. By doing so, you can just double-click a DLL or OCX file in Explorer to automatically launch the Regsver32 utility with the file as the command-line argument.To associate a DLL or OCX with the Regsvr32 utility, locate the file in Explorer. Right-click the file, and then choose Open With. In the dialog box that appears, click Other and select Regsvr32 to open the component file with the Regsvr32 utility and subsequently register the component. If the Always Use This Program to Open This File checkbox is selected, all files with the same extension are associated with the utility.
For out-of-process servers, the components are automatically registered by executing the server.
ActiveX clients and out-of-process ActiveX servers communicate via a proxy/stub mechanism automatically supplied by COM. Distributed COM (DCOM) extends this mechanism across a network, allowing the out-of-process code component to be instantiated and executed on a remote machine and thus distributing the computational load across multiple machines.
DCOM shipped with Windows NT 4.0, and a service pack is available to provide DCOM for Windows 95. For machines not running Windows NT 4.0 or Windows 95 with the DCOM upgrade, Remote Automation is available to provide the same functionality as DCOM. Remote Automation was introduced before DCOM and shipped with Visual Basic 4.0. Although DCOM is slowly taking over the role Remote Automation held, Remote Automation is still supported by Visual Basic 5.0's Enterprise Edition for backward compatibility and for situations in which the client process resides on a 16-bit machine.
The following steps are necessary to implement a remote server. Use of DCOM is assumed and, where different, Remote Automation is indicated.
Figure 9.4 shows the Racmgr32 utility, which is found in the Visual Basic program group. The Remote Automation Control Manager window consists of a list of the classes in your Windows Registry as potential ActiveX components. Two tabbed pages appear on the right: one to configure client access, and the other to configure server connection. The Client Access page is for configuring the remote server's access privileges, which is performed on the server machine.
FIG. 9.4
The Racmgr32 utility is used on the server machine to configure client access to
remote components.
Remote Automation provides four levels of access security:
When invoking the Remote Automation Control Manager on the client machine, click the Server Connection tab. The Server Connection page has two option buttons and three drop-down boxes that you can use to configure the network connection (see Figure 9.5). When you're selecting a class for the first time, the connection icon toward the top of the page will indicate Local. To change this to Remote, right-click the class or the icon and select Remote. However, the type of remote transport and network connection still needs to be configured.
FIG. 9.5
The Server Connection page of the Racmgr32 utility is used on the client machine
to configure the connection to out-of-process ActiveX components.
In the Remote Transport section, choose Distributed COM or Remote Automation. If you choose DCOM, notice that only the Network Address drop-down box is enabled (DCOM uses its own network protocol and security). All three drop-down boxes become enabled with the Remote Automation selection. Figure 9.6 shows a sample entry for the selected remote server by using Remote Automation.
FIG. 9.6
The MyRemoteServer.Server connection. This component will be accessed on
the network machine named REMCOMP with the TCP/IP protocol.
Because the Racmgr32.exe utility is extremely easy to use, you can quickly configure component servers. You can select the local connection and run the client application, and the local component will be used. Then select Remote along with Remote Automation, and the component will be accessed from the specified network machine by using Remote Automation. Finally, keep the selection at Remote and select DCOM, and the component will be accessed on the remote machine by using the DCOM protocol. It's as easy as that.
Another utility is provided for DCOM-enabled machines (Windows NT 4.0 and Windows 95 with DCOM upgrade) that facilitates configuring DCOM access. You can find this utility, dcomcnfg.exe, in the Windows \System32 directory. Executing this application displays the dialog box shown in Figure 9.7.
FIG. 9.7
The dcomcnfg.exe utility is used to configure the properties and security of components
running under DCOM.
This dialog box consists of three tabbed pages:
Use dcomcnfg.exe to configure a component to run on a remote machine with the DCOM transport.
NOTE: Make sure that the component is installed and registered on the remote machine and registered on the local machine.
Follow these steps:
Likewise, to configure a remote server, follow these steps with the dcomcnfg utility:
Now that you've seen the different types of components and how they're installed and registered, it's time to cover how they're glued together into a working application. For client/server applications, the most popular tools for performing this task are Visual Basic and Visual C++, both part of the Visual Studio suite. The rest of this chapter is devoted to using ActiveX components with these two development tools.
To learn the techniques of using ActiveX controls and code components, you'll develop a simple dialog box-based application first with Visual Basic and then with Visual C++. This application will prompt for an URL and, on the user's request, navigate to the web site and display the associated web page. The following controls and components (installed on your machine when the Visual Studio development tools were installed) will be used:
The two controls, Microsoft Rich Text Box and Sheridan 3-D Command Button, will be discussed first in the "ActiveX Controls" section. Then, the Internet Explorer Automation object will be incorporated to provide the web-navigation capability that will be covered in the "ActiveX Code Components" section.
After you use an ActiveX component within Visual Basic, you'll come to appreciate the ease at which you can rapidly build component-based applications with this highly successful development tool. What's more, after you work with a particular component and become familiar with the basic steps of incorporating one into a Visual Basic project, using other components will become second nature to you.
You use ActiveX controls by selecting the control from the toolbox and placing it on a form. You can set the control's design-time properties to adjust the look and feel. Properties and methods can also be accessed programmatically. Event-handler functions are incorporated into the form's code to provide logic that needs to be executed in response to a particular event from a control.
Using ActiveX code components requires declaring a variable that's an object of the component. When a call is made to instance the object, properties and methods can then be accessed.
These procedures are discussed in detail in the following sections. Now create a project for the sample application. With Visual Basic running, choose File, New Project from the menu, and select Standard exe.
Using an ActiveX control involves these general steps, explained in more detail in the following sections:
Loading the Control To use an ActiveX control in a project, you need to add the control to the toolbox. Choose Project, Components from the menu to open the Components dialog box. In the list of controls registered with the Windows Registry, select a control and click OK. An icon representing the control appears in the toolbox. If the control you're interested in doesn't appear in the list box but the .ocx file is installed on your machine (the control may not be registered), click the Browse button on the Components dialog box. In the Add ActiveX Control dialog box, locate the .ocx file and select it to load the control into the project. With the control added to the toolbox, you can use it just like any other control provided with Visual Basic.
Follow these steps to load the Microsoft Rich Textbox and Sheridan 3D Command Button controls into your sample application:
FIG. 9.8
The toolbox reflects the components loaded into the projects.
You can now assemble the controls on your form.
Place a Microsoft Rich Textbox and a Sheridan 3D Command Button on the form of your sample application. Also place a common label control next to the text box. Your project should look like Figure 9.9.
FIG. 9.9
The Microsoft Rich Textbox and Sheridan 3D ActiveX controls positioned on the main
form.
Accessing Properties and Methods With the control loaded, the properties and methods exposed by the component are most easily viewed with the Object Browser (see Figure 9.10). The list on the left contains the classes or components that are part of the type library selected in the top drop-down box. Selecting the component will cause its properties, methods, and events to appear in the right list. The pane at the bottom of the dialog box displays information about the item selected in either list--a convenient way to familiarize yourself with a component before using it in code.
FIG. 9.10
Use the Object Browser to review an ActiveX component's properties and methods.
Another way to display control properties that are available at design time is through the Properties window, which normally appears between the Project and Form Layout windows at the right of the IDE. You can use the Properties window to set component properties at design time. Selecting the property displays information about it in the bottom pane of the window. With the property selected, the value can be entered in the column directly to the right of it.
For the example, you'll want to set the Caption properties for the Label and CommandButton controls. Also, you'll need to set the Text property of the TextBox control to a blank string:
FIG. 9.11
The final appearance of the sample application with the appropriate properties set.
Properties and methods of an ActiveX control can be accessed programmatically. An object of a control is identified by the (Name) property in the Properties window. For example, to obtain the text value of the Rich Textbox identified by the name RichTextBox1, the following code segment would be added:
Dim sText As String sText = RichTextBox1.Text
Setting the text value is accomplished with this statement:
RichTextBox1.Text = "Hello World"
Methods are accessed in the same manner. For example, if you wanted to invoke the LoadFile function of the Rich Textbox, the following code would be inserted:
Dim sFile As String = "MyFile.rtf" RichTextBox1.LoadFile(sFile)
This code would load an .rtf file into a RichTextBox control.
Run the sample application. Notice that the only operation that can be performed is entering text into the text box. What you really want to happen is the application navigating to the entered URL at the user's command. You'll use the click event fired by the Sheridan 3D Command Button to tell the program to access the text in the text box and navigate to the URL. This leads to a discussion of handling events from ActiveX controls with Visual Basic.
Handling Events ActiveX controls will fire events predefined by the control's developer, notifying the client process of important events. ActiveX controls provided by vendors usually provide information to be displayed with Visual Basic help documenting what events they fire. You can view exposed events from a control loaded into the project in various ways:
FIG. 9.12
Viewing the Sheridan 3D Command Button's Click event.
FIG. 9.13
The Command Button event handler prototype inserted into the form's code.
Returning to the sample application, enter the bold line of code in the Command Button Click event:
Private Sub SSCommand1_Click()
MsgBox RichTextBox1.Text
End Sub
Run the application, type some text into the text box, and click the Navigate button. Did the text in the text box appear in the message box?
You'll now want to add web-navigation capability to your application via the Internet Explorer component. Using ActiveX code components is the next topic of discussion.
Using ActiveX code components involves the following steps, which are covered in more detail in the following sections:
Loading the Code Component Code components aren't child windows like controls. Subsequently, they're not dropped onto forms from the toolbox. However, you can load code components into the project, similar to a control. This pulls the type library information into the project, allowing you to view the component's properties and methods. To add a code component, choose Project, References from the menu. The list box in the References dialog box contains ActiveX components registered with the Windows Registry. Selecting a component allows its properties and methods to be accessed at design time.
If the component doesn't appear in the list box, click the Browse button to open the Add Reference dialog box. Locate the file containing the type library information and select it to register the type library with the Registry and provide access to the properties and methods exposed by the component.
Follow these steps to load the Internet Explorer code component into your sample project:
Accessing Properties and Methods With the code components type library loaded, the properties and methods exposed by the component are most easily viewed through the Object Browser, the same as for ActiveX controls. To view the Internet Explorer code component properties and methods, do the following:
ActiveX components are created and manipulated programmatically. These are the basic steps in using a code component within Visual Basic code:
To incorporate the Internet Explorer component into your example, follow these steps:
Dim m_oInternetExplorer As Object
Private Sub Form_Load()
Set m_oInternetExplorer = CreateObject("InternetExplorer.Application")
End Sub
Private Sub SSCommand1_Click()
m_oInternetExplorer.Navigate (RichTextBox1.Text)
m_oInternetExplorer.Visible = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set m_oInternetExplorer = Nothing
End Sub
Handling Events Some ActiveX code components will raise events similar to ActiveX controls. Visual Basic allows you to provide event handling for ActiveX components with the WithEvents keyword used in the dimension statement. This tells Visual Basic up front that you want to handle events exposed by the component. To see how to use the WithEvents keyword, handle the Quit event from Internet Explorer and place the reference releasing code there, as follows:
Dim WithEvents m_oInternetExplorer As InternetExplorer
Private Sub m_oInternetExplorer_Quit(Cancel As Boolean)
m_oInternetExplorer.Visible = False
MsgBox "Exiting Internet Explorer"
Set m_oInternetExplorer = Nothing
End Sub
Private Sub SSCommand1_Click()
Set m_oInternetExplorer = CreateObject("InternetExplorer.Application")
m_oInternetExplorer.Navigate (RichTextBox1.Text)
m_oInternetExplorer.Visible = True
End Sub
You would create an executable of your application that uses ActiveX components as you would for any application. Your application, however, will require the .ocx and .dll files that package the components used to be distributed and registered on the target machine. Just as Visual Basic uses the registered .ocx and .dll files, your application also will use them and will generate a runtime error if the file isn't found. Therefore, your application's installation procedure should copy all files that package the components as well as automatically register them.
NOTE: If you're using components obtained from a third party, consulting the accompanying documentation regarding distribution licenses is always a good idea.
When you're ready to distribute your application, you should use Visual Basic's Application Setup Wizard to create the installation program.
NOTE: If your application will use remote server components and you want the servers registered without copying the executable to the target machine, ensure that a .vbr file exists for each server. A .vbr file is created when the server project (ActiveX executable) is compiled with the Remote Server Files option selected on the Component page from the Project Properties dialog box (Project, Project Properties).
To create an installation program, follow these steps:
FIG. 9.14
The Select Projects and Options dialog box of the Setup Wizard.
FIG. 9.15
When the Setup Wizard finds reference to a type library file, it asks whether
this refers to a Remote Automation component.
FIG. 9.16
If the Setup Wizard finds files with missing dependencies, it asks for verification
that no dependency information is available.
FIG. 9.17
The Setup Wizard's ActiveX Server Components dialog box provides the means to add
remote servers to the setup program.
FIG. 9.18
The Setup Wizard's Remote Connection Details dialog box prompts for the necessary
remote transport and connection information.
NOTE: Selecting DCOM as the remote transport disables the Network Protocol and Authentication Level drop-down boxes because DCOM has its own protocol and security. If you use Remote Automation, however, you would have to supply this information.
FIG. 9.19
The ActiveX Server Components dialog box, showing the addition of a remote server.
As mentioned earlier, when you become comfortable with using one component, using others of the same type becomes second nature. Using ActiveX components with Visual C++ is no exception. After you use an ActiveX control with the resource editor or use a code component programmatically, you'll use the same techniques repeatedly with each and every ActiveX component you use.
Using ActiveX controls in Visual C++ is similar to that of Visual Basic when you become familiar with Visual C++'s resource editor. With the control loaded into the project, an icon representing the control appears on the editor toolbar for "dropping" onto dialog boxes and forms in a similar manner. Visual C++ exposes design-time tools that enable viewing and setting control properties, as well as a test container that allows a control to be tested and its behavior monitored before you incorporate it into applications.
ActiveX code components, on the other hand, are incorporated a little differently in Visual C++ in that they aren't loaded into the project for early binding, as was the case in Visual Basic. To use an ActiveX code component, a container class must be created to encapsulate the interface provided by the component. Before Visual C++ 5.0, this was accomplished by the ClassWizard, which created source code that was included into your project that implemented the container class. With Visual C++ 5.0, special support for COM has been added to the compiler. By using the new #import directive to import a type library, the preprocessor generates the C++ header file describing the interface and a second file containing the implementation, thus eliminating the need to maintain container source code as before.
Now is a good time to open the project in which you'll be working with the components. You'll be developing the same sample application as you did with Visual Basic in the earlier discussion. Follow these steps to create a dialog box-based MFC application:
FIG. 9.20
The last dialog box of the MFC AppWizard summarizes the classes that will be added
to your project.
FIG. 9.21
Execution of the skeleton project.
FIG. 9.22
Editing the dialog box resource with the resource editor.
You're now ready to proceed with adding the ActiveX controls that will be used in the application. Save your project.
Using an ActiveX control within Visual C++ involves the following steps, which are discussed in detail in the following sections:
Loading the Control To load a control into a project, use the Component Gallery (choose Project, Add to Project, Components and Controls from the menu). The Component Gallery stores shortcuts as well as Registry information about registered controls. If you've installed and registered an ActiveX control and it doesn't appear in the Component Gallery, you must create the shortcut yourself. In Explorer, use the right mouse button to drag the .ocx file containing the control to the Registered ActiveX Controls folder. Choose Create Shortcut(s) Here from the pop-up menu.
To load the two ActiveX controls into your application, follow these steps:
FIG. 9.23
The project's resource editor's toolbar after loading the Microsoft Rich Textbox
and Sheridan 3D Command Button controls.
FIG. 9.24
The dialog box resource after placing the Microsoft Rich Textbox and Sheridan 3D
Command Button controls on it.
NOTE: The label control to the left of the text box is placed on the dialog box in the same way. You can change the label's caption by right-clicking the label and then choosing Properties. On the General page, enter the new caption in the appropriate text box.
TIP: To reposition controls in the dialog box, drag them with the mouse or, with the control selected, use the arrow keys. Likewise, you can resize the control with the arrow keys while holding down the Shift key.
With the ActiveX controls loaded into the project and placed in the dialog box resource, you now can use the properties, methods, and events exposed by each.
Accessing Properties and Methods The ActiveX control's developer designated certain properties to be accessed at design time. You can view these properties and set their values from the control's property page displayed by the resource editor. To access the property page of the Sheridan 3D Command Button control in your application, do the following:
FIG. 9.25
The property sheet for the Sheridan 3D Command Button.
The properties for the Microsoft Rich Text control are accessed in the same way. It's a good idea to go ahead and view what properties are exposed by this control for future reference, but you won't need to change any values for this application. You will, however, need to access the Text property of the Microsoft Rich Text control at runtime.
If you remember back to when the controls were inserted via the Component Gallery, several classes were generated and placed into your project. These wrapper classes wrap the interfaces to the controls and have member functions for all properties and methods. You can view these member functions through the Class View or by editing the class implementation file. To view the member functions for the Microsoft Rich Text control wrapper class, follow these steps:
CString CRichText::GetText()
{
CString result;
InvokeHelper(DISPID_TEXT, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);
return result;
}
To make use of the properties and methods exposed by an ActiveX control at runtime, the dialog box class needs a data member that's an object of the control's wrapper class. The ClassWizard provides the support for adding data members of type <control wrapper class> to the dialog box class. You'll want to add a data member of type CRichText to your dialog box to have access to the text property by following these steps:
FIG. 9.26
Adding member variables with the MFC ClassWizard.
Listing 9.1 Adding a Member Variable
// InterNavVCPPDlg.h : header file // //{{AFX_INCLUDES() #include "richtext.h" //}}AFX_INCLUDES #if !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_) #define AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 class CInterNavVCPPDlgAutoProxy; ///////////////////////////////////////////////////////////////////////////// // CInterNavVCPPDlg dialog class CInterNavVCPPDlg : public CDialog { DECLARE_DYNAMIC(CInterNavVCPPDlg); friend class CInterNavVCPPDlgAutoProxy; // Construction public: CInterNavVCPPDlg(CWnd* pParent = NULL); // standard constructor virtual ~CInterNavVCPPDlg(); // Dialog Data //{{AFX_DATA(CInterNavVCPPDlg) enum { IDD = IDD_INTERNAVVCPP_DIALOG }; CRichText m_oRichText; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CInterNavVCPPDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL . . . #endif // !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_)
void CInterNavVCPPDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CInterNavVCPPDlg)
DDX_Control(pDX, IDC_RICHTEXTCTRL1, m_oRichText);
//}}AFX_DATA_MAP
}
CString strText; strText = m_oRichText.GetText();
Handling Events The ClassWizard maps an ActiveX control's events to dialog box class handler functions. The wizard displays all the events that the control can fire. By selecting the events you want your dialog box class to handle, the ClassWizard will place the class into an event sink map that connects the event to its handler function. If you went ahead and compiled and executed the sample application, you would see the dialog box appear and be able to enter an URL into the text control. But that's about all the functionality the application has at this point. What you really want the program to do is navigate to the URL when you click the Navigate button. Clicking the Command Control button fires an event. The dialog box class handles the event by providing a member function that gets invoked when the event is fired. It's within this member function that you'll want to incorporate the necessary logic to retrieve the text from the text control and navigate to the URL.
Because the navigation logic will be handled by the Internet Explorer component (which is covered later in the "ActiveX Code Components" section), an intermediate step will be followed. When the event is handled, logic is put into place to receive the text from the text control and display it in a message box.
To handle the click event, follow these steps:
NOTE: This procedure is the same for mapping all events for all ActiveX controls.
FIG. 9.27
The events fired by the Sheridan 3D Command Button.
void CInterNavVCPPDlg::OnClickSscommand1()
{
CString sDisplay;
sDisplay = "The URL You Entered: " + m_oRichText.GetText();
AfxMessageBox(sDisplay);
}
You also can view and directly maintain the message/event map through the ClassWizard dialog box. Follow these steps:
FIG. 9.28
The MFC ClassWizard's Message Maps page is used to add and maintain event handlers.
Using an ActiveX code component in a Visual C++ project is similar to using ActiveX controls in that a class that wraps the components interface is inserted into a project. It's this wrapper class in which the rest of your application accesses the properties and methods the component developer exposed. What's different is that the ActiveX code component isn't inserted into the project through the Component Gallery, and the component isn't visually edited with the resource editor.
Various techniques are available for loading and using ActiveX code components within Visual C++. To learn these techniques, you'll add the Internet Explorer Automation object to the sample application that you created earlier in the "ActiveX Controls" section to provide the web navigation functionality this application needs.
Now is a good time to become familiar with the interface to the Internet Explorer component. To obtain information about the component (or any registered component), use the OLE/COM Object Viewer utility provided with Visual C++. This utility will display Registry as well as type library information about the selected component. To view the Internet Explorer component, do the following:
FIG. 9.29
The Internet Explorer automation object's Registry entry as viewed by the OLE/COM
Object Viewer.
There are two ways to create and insert a wrapper class for an ActiveX code component in Visual C++:
FIG. 9.30
The IWebBrowserApp interface implementation.
The ClassWizard Provided an ActiveX code component's type library, the ClassWizard will generate a class that encapsulates each interface listed in the library. The member functions of these classes are tailored to access each property and method included in the library. To create and insert a class for the Internet Explorer component, follow these steps:
The #import Directive A new feature introduced with Visual C++ 5.0 is compiler support for COM. By using the #import directive with a type library file, the preprocessor generates two header files: one describing the interface to the wrapper class and the other containing the implementation. What's nice is that no source code is added to your project, which subsequently means less code to maintain. The syntax for using the #import directive is
#import <filename> [attributes] using namespace <library name>;
<filename> is the name of the file containing the type library information. This file can be any of the following or any other file format that the LoadTypeLib API can understand:
NOTE: Refer to Visual C++'s online documentation for a description of all the available attributes.
To prevent name collisions between the imported component and your existing code, the compiler defines a namespace identified by the type library name. A namespace is a declarative region that attaches an additional identifier to any names declared inside it. To identify a member of a namespace, the scope resolution operator is used:
<namespace>::<member>
To avoid typing the scope resolution throughout your code, the using namespace line directly after the #import line is incorporated and includes the library name.
To incorporate the Internet Explorer component into your application by using the #import directive, follow these steps:
#import "C:\WINNT\System32\shdocvw.dll" rename("tagREADYSTATE", "tagIEREADYSTATE")
using namespace SHDocVw;
NOTE: You need to rename tagREADYSTATE to tagIEREADYSTATE to prevent a name collision inside the compiler-generated implementation files.
IWebBrowserAppPtr m_oIWebBrowserAppPtr;
Classes Created by the ClassWizard If you used the ClassWizard to incorporate the code component into your project, you'll be creating an object of the class that was derived from the COleDispatchDriver class. Member functions inherited from this class provide the means of instantiating the COM object and retrieving and releasing its dispatch interface. The following are the basic steps of using a class derived from COleDispatchDriver:
NOTE: Assume that IChildClass, a class created by the ClassWizard, exists for these steps.
In the sample application, the ClassWizard created and inserted IWebBrowserApp into your project. You use the Internet Explorer component in your application as follows:
Listing 9.2 Adding the Internet Explorer Component as an IWebBrowserApp Object
// InterNavVCPPDlg.h : header file // //{{AFX_INCLUDES() #include "richtext.h" //}}AFX_INCLUDES #include "shdocvw.h" //Contains the declaration of the IWebBrowserApp class #if !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_) #define AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_ . . . // Implementation protected: CInterNavVCPPDlgAutoProxy* m_pAutoProxy; HICON m_hIcon; VARIANT vDummy; //Argument for //IWebBrowserApp::Navigate() IWebBrowserApp m_oInternetExplorer; //Declaration IWebBrowserApp object BOOL CanExit(); . . .#endif // !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_)
CInterNavVCPPDlg::CInterNavVCPPDlg(CWnd* pParent /*=NULL*/)
: CDialog(CInterNavVCPPDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CInterNavVCPPDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pAutoProxy = NULL;
//Initial the dummy argument that will be passed to the
//IWebBrowserApp::Navigate function
vDummy.vt = VT_EMPTY;
//Create an instance of the InternetExplorer.Application object
//and retrieve its dispatch interface
m_oInternetExplorer.CreateDispatch("InternetExplorer.Application.1");
}
CInterNavVCPPDlg::~CInterNavVCPPDlg()
{
// If there is an automation proxy for this dialog, set
// its back pointer to this dialog to NULL, so it knows
// the dialog has been deleted.
if (m_pAutoProxy != NULL)
m_pAutoProxy->m_pDialog = NULL;
//Release the dispatch interface and decrement the object's
//reference count
m_oInternetExplorer.ReleaseDispatch();
}
void CInterNavVCPPDlg::OnClickSscommand1()
{
m_oInternetExplorer.Navigate(m_oRichText.GetText(),
&vDummy,
&vDummy,
&vDummy,
&vDummy);
m_oInternetExplorer.SetVisible(TRUE);
}
Classes Created by the #import Directive If you've used the #import directive to create your dispatch interface wrapper class, you'll be using the _com_ptr_t template class to access the component's members. _com_ptr_t, known as a smart pointer, encapsulates a raw interface pointer and handles the creating, reference adding, and releasing of the component object automatically. The _com_ptr_t class is hidden in the _COM_SMARTPTR_TYPEDEF macro located in the .tlh file created by the #import directive. For example, in the shdocvw.tlh file, the following macro is found for the IWebBrowserApp interface:
COM_SMARTPTR_TYPEDEF(IWebBrowserApp, __uuidof(IWebBrowserApp));
This will get expanded by the compiler to the following:
typedef _com_ptr_t<_com_IIID<IWebBrowserApp, __uuidof(IWebBrowserApp)>
IWebBrowserAppPtr;
You'll use this class, IWebBrowserAppPtr, in your code to use the Internet Explorer component.
Returning to the sample application, follow these steps to incorporate the Internet Explorer component:
Listing 9.3 Adding the Internet Explorer Component as an IWebBrowserAppPtr Object
// InterNavVCPPDlg.h : header file // //{{AFX_INCLUDES() #include "richtext.h" //}}AFX_INCLUDES #import "C:\WINNT\System32\shdocvw.dll" rename ("tagREADYSTATE", "tagIEREADYSTATE") using namespace SHDocVw; #if !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_) #define AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_ . . . // Implementation protected: CInterNavVCPPDlgAutoProxy* m_pAutoProxy; HICON m_hIcon; VARIANT vDummy; //Argument for //IWebBrowserApp::Navigate() IWebBrowserAppPtr m_oInternetExplorer; //Declaration IWebBrowserApp object BOOL CanExit(); . . . n //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately //before the previous line. #endif // !defined(AFX_INTERNAVVCPPDLG_H__FF98D69A_FFDE_11D0_83C1_000000000000__INCLUDED_)
CInterNavVCPPDlg::CInterNavVCPPDlg(CWnd* pParent /*=NULL*/)
: CDialog(CInterNavVCPPDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CInterNavVCPPDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pAutoProxy = NULL;
//Initial the dummy argument that will be passed to the
//IWebBrowserApp::Navigate function
vDummy.vt = VT_EMPTY;
//Create an instance of the InternetExplorer.Application object
//and retrieve its dispatch interface
m_oInternetExplorer.CreateInstance("InternetExplorer.Application.1");
}
NOTE: When an object of the _com_ptr_t class leaves scope, the Release method of the interface pointer is called automatically. There's no need to explicitly release the reference as was the case for the class derived from COleDispatchDriver.
void CInterNavVCPPDlg::OnClickSscommand1()
{
m_oInternetExplorer ->Navigate((LPCSTR)m_oRichText.GetText(),,
&vDummy,
&vDummy,
&vDummy,
&vDummy);
m_oInternetExplorer ->PutVisible(TRUE);
}
In this chapter, you've been introduced to the types of ActiveX components typical in a client/server environment. Also, you've learned the techniques to install and register ActiveX components to be accessed on a local or remote machine. You've also seen the steps necessary in incorporating ActiveX components into Visual Basic and Visual C++ applications.
© Copyright, Macmillan Computer Publishing. All rights reserved.