| Importing ActiveX Components | ||
|
In Visual C++ 6.0, the #import compiler directive was included as an alternative to adding the component to a project through the IDE. Similar to how header files are included in an application, this directive incorporates information from a type library, automatically creating wrapper classes for its interfaces. These classes use smart pointers which handle things like reference counting automatically, and make using the component's interface much simpler. Creating ObjectsTo use this method of referencing a component, the first thing that needs to be done is to import the component into the module where it will be used. This is done using the #import directive which can be placed in an appropriate header file. For example, to import the File Transfer Protocol component, you would use:
The no_namespace attribute specifies that the interface classes should not be defined in a namespace. Normally, a namespace is created which is based on the name of the component. The named_guids attribute tells the compiler to initialize the GUID variables using the standard naming convention. The next step is to declare a variable that is used to reference an instance of the component. For example, the following could be included in the definition of a class:
Note that the member variable is declared as type IFtpObjectPtr, which is a specialization of the smart pointer _com_ptr_t template class. If errors are encountered when compiling the application indicating that the compiler cannot instantiate an abstract class (because the class contains pure virtual functions) then most likely the member variable was declared as type IFtpObject, which is incorrect. Don't forget the "Ptr" on the end of the name. To use the component, an instance of the component must be created using the CreateInstance function. However, before that can be done, the COM subsystem must be initialized by the application. For MFC based applications, this is accomplished by calling the function AfxOleInit which is essentially a wrapper around CoInitializeEx. This should be done fairly early in the application, typically in the InitInstance function of the CWinApp derived application class. Next, the component's CreateInstance member function must be called before it is used:
The HRESULT return value should be 0, which indicates that an instance of the component was created successfully. If an error is returned, this typically means that AfxOleInit (or CoInitializeEx) was not called first, or the component has not been registered on the system. InitializationAfter an instance of the object has been created, the next step that you need to take is to call the Initialize method. This will prepare the component for use, validating the runtime license, loading any required networking libraries and allocating the system resources that it requires. The Initialize method has several optional arguments, however in most cases the only argument that is required is the runtime license key. This is a string of characters which is used to validate your development license. It is important to note that the runtime key is not your product serial number. For more information, refer to the section on Component Initialization. The following code demonstrates how the FTP component can be initialized:
The runtime license key is created by converting it to Unicode and then calling SysAllocString to create a BSTR string. Because the component methods use variants, this key is assigned to a variant. Note that the _variant_t type is used, which is a COM support class which encapsulates a variant. The Initialize method returns a long integer variant which specifies an error code. A value of zero indicates that the component was successfully initialized, while a non-zero value is an error code. Once the component has been created and initialized, other properties and methods can be accessed. The following code demonstrates how a connection could be established to download a file:
Note that the component's properties, such as TransferBytes, can be accessed as if they are member variables of the class rather than using accessor functions like GetTransferBytes. This is a bit of slight-of-hand being performed by the interface class using the __declspec(property) extension. For example, the TransferBytes member is declared as:
This tells the compiler whenever the TransferBytes member is read, it should call the GetTransferBytes function to return the value. So, in effect the above code is changed by the compiler into:
Either method may be used, so it is generally up to the personal preferences of the developer as to which is used. |
||
|
Copyright © 2008 Catalyst Development Corporation. All rights reserved. |
||