Using Native COM Support in Microsoft Visual C++

Microsoft Visual C++ version 5.0 or later has native COM support through the #import statement. Using this statement allows you to automatically add type information contained in a type library into your project. The generated files normally have the same name as the component DLL with the extensions .tlh and .tli.

When using the #import statement, make sure to import the ActiveX Data Objects type information before the Microsoft CDO for Windows 2000 type information. The following examples demonstrate using the #import statement:

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace raw_interfaces_only rename("EOF", "EndOfFile")#import <cdosys.dll> no_namespace raw_interfaces_only#include "cdosysstr.h"#include "cdosyserr.h"void main() {  CoInitialize(NULL);  IMessage* pMsg = NULL;  HRESULT hr =     CoCreateInstance( __uuidof(Message),                      NULL,                      CLSCTX_INPROC_SERVER,                      __uuidof(IMessage),                     (void**) &pMsg                     );  ...  CoUninitialize();}

Note

You must have the ADO 2.5 type information in the same namespace as CDO type information. CDO interfaces make use of ADO types in arguments. These types are not qualified using namespaces in the CDO interface definitions. If these types are not in the same namespace, errors will occur. You can do one of the following to solve this problem:

  • Rename the default ADODB ADO namespace to CDO.
  • Import type information into the global namespace, if feasible.
  • Rename both CDO and ADODB to another namespace, such as CDOSYS.

The GUID definitions for ADO and CDO types can be retrieved using the __uuidof operator supported by Visual C++. You can use #import flags to specify the CLSID_XXX and IID_XXX definitions if this format is desired.

Consider the following issues when using the #import statement:

  1. The header file generated by the #import directive does not contain the module constant definitions contained within the type library. However, the Platform SDK provides two separate headers that can be included within your project so that these constants are available. These files are cdosysstr.h and cdosyserr.h. The first contains the field name constants, and the second includes the CDO custom HRESULT error codes. If you do not include these, you will have to manually insert these values. For example, the field "urn:schemas:httpmail:to" has an associated constant called cdoTo in the string constant header file cdosysstr.h.
  2. The #import statement strips the default values for arguments when generating the header files. If you use #import, you will need to explicitly specify the defaults. For example:
    hr = pBp->AddBodyPart(-1); // the -1 is the default value in cdosys.h

Using Interface Pointer Wrapper Classes with Import

The raw_interfaces_only flag to #import directive suppresses the creation of "smart pointer" C++ wrapper classes. However, in many cases these wrappers simplify working with CDO in C++. The following example demonstrates using the wrapper classes produced by the #import statement:

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "EndOfFile")#import <cdosys.dll> no_namespace#include "cdosysstr.h"#include "cdosyserr.h"void main() {  CoInitialize(NULL);  {  try {   IMessagePtr iMsg(__uuidof(Message));   FieldsPtr Flds;   Flds = iMsg->Fields;   Flds->Item[cdoTo]->Value      = _variant_t("example@example.com");   Flds->Item[cdoFrom]->Value    = _variant_t("example@example.com");   Flds->Item[cdoSubject]->Value = _variant_t("a test");   Flds->Item[cdoTextDescription]->Value = _variant_t("this is a test");   Flds->Update();   iMsg->Send();  }  catch( _com_error err) {   //  ... }  }  CoUninitialize();  return 1;}

Using the CDO Namespace

You can use namespaces with the #import statement. However, when you import the ADO type information, you must make sure to add it to the CDO namespace, or suppress the namespace by adding it to the global namespace. If you do not do this, all ADO type information will reside in the ADODB namespace by default, and CDO arguments that are ADO types will not resolve at compile time. The following example demonstrates this:

#import "c:\program files\common files\system\ado\msado15.dll" rename("ADODB","CDO") rename("EOF", "EndOfFile")#import <cdosys.dll>#include "cdosysstr.h"#include "cdosyserr.h"void main() {  CoInitialize(NULL);  {  try {   CDO::IMessagePtr iMsg(__uuidof(CDO::Message));   CDO::FieldsPtr Flds;   Flds = iMsg->Fields;   Flds->Item[cdoTo]->Value      = _variant_t("example@example.com");   Flds->Item[cdoFrom]->Value    = _variant_t("example@example.com");   Flds->Item[cdoSubject]->Value = _variant_t("a test");   Flds->Item[cdoTextDescription]->Value = _variant_t("this is a test");   Flds->Update();   iMsg->Send();  }  catch( _com_error err) {   //  ...  }}  }  CoUninitialize();  return 1;}