Defining and Instantiating ADO Objects with #import
Manipulating an Automation object takes two steps:
Define and instantiate a variable to be used to manipulate a COM object.
Instantiate an actual instance of a COM object and assign it to the variable.
With #import you can accomplish both steps in a single line of code, using the smart pointer's (_com_ptr_t) constructor to pass in a valid CLSID, or PROGID. You could also declare an instance of the object, and then
use the _com_ptr_t::CreateInstance() method to instantiate the object. Both techniques are demonstrated in Listing 4.
Listing 4: Instantiating an ADO Connection object with #import
#import <msado15.dll> rename( "EOF", "adoEOF" )
...
struct InitOle {
InitOle() { ::CoInitialize(NULL);
}
~InitOle() { ::CoUninitialize();
}
} _init_InitOle_;
...
// Method #1: Declaring and instantiating a Connection object
_ConnectionPtr Conn1( __uuidof( Connection ) );
// Method #2: Declaring and instantiating a Connection object
_ConnectionPtr Conn1 = NULL;
HRESULT hr = S_OK;
hr = Conn1.CreateInstance( __uuidof( Connection ) );
The recommended technique is the second one because the constructor of _com_ptr_tdo
es not return a failed HRESULT if something goes wrong. The first method is flawed because it cannot test if the creation of the ADO Connection object succeeded or failed.
In both cases, use the Visual C++ extension __uuidof( Connection), which in this case retrieves a GUID defined by #import in the .tlh file corresponding to the ADO Connection object. By passing it to CreateInstance, you create a valid ADO Connection object for the Connection smart pointer. There are other forms you could pass into either the constructor or CreateInstance to reference the ADO Connection object and accomplish the same result. For more information, see the Visual C++do
cumentation for topics about #import.
The only flaw with the code above is that it assumes you have imported only ADO. If you import multiple libraries and one or more of those libraries have an object with the same name, you must provide some differentiation between the two. For example, both ADO and DAO contain an object named Recordset.
Another attribute of #import, no_namespace, prevents the compiler from qualifying the classes in a namespace, which is to say the name of the library the type library defines. In the case of ADO, this is ADODB. Using no_namespace means youdo
n't have to reference the namespace when initializing or defining variables whose types are defined by what #import generates. However, if you have many type libraries imported into your application, it is safer to omit the no_namespace attribute.
Listings 5 and 6 show the difference in your code with and without the no_namespace clause. While it may be more work to omit no_namespace, itdo
es ensure your code will be more robust in case it uses other Automation servers whose objects might share the same name as an object found in ADO.
Listing 5: Using #import with the no_namespace attribute
#import <msado15.dll> no_namespace rename( "EOF", "adoEOF" )
void main()
{
HRESULT hr = S_OK;
_ConnectionPtr Conn1 = NULL;
hr = Conn1.CreateInstance( __uuidof( Connection ) );
Conn1 = NULL;
}
Listing 6: Using #import without the no_namespace attribute
#import <msado15.dll> rename( "EOF", "adoEOF" )
void main()
{
HRESULT hr = S_OK;
ADODB::_ConnectionPtr Conn1 = NULL;
hr = Conn1.CreateInstance( __uuidof( ADODB::Connection ) );
Conn1 = NULL;
}