Using AppConn COM from C++ Using an Import Statement

To begin using AppConn in your C++ project, the AppConn COM control must be imported into the project using the VC++ compiler. To import the appConn.dll, installed to the \Winnt\System32 folder by default, place the following import statement at the beginning of the source file that will be using the AppConn component:


#import "appconn.dll"


The import command will generate two new files, appconn.tlh and appconn.tli, which are automatically included in the source file. The appconn.tlh file defines wrapper classes for each of the AppConn interfaces, smart pointers for the wrapper classes, and all of the AppConn constants inside of the namespace AppConnLib. To use the AppConn definitions, the AppConn definition must be prefaced with AppConnLib:: or by including a using namespace statement:


using namespace AppConnLib;

Accessing AppConn Using the Smart Pointer and Wrapper Class

AppConn objects are accessed using the smart pointer to the wrapper class. The smart pointer will perform all of the life time management for the object. When an object is assigned to the smart pointer, the smart pointer will call AddRef on the object. When the pointer is reassigned, the smart pointer will call Release on the object, and when the smart pointer is destroyed it will call Release on the object. The smart pointer's name is the name of the interface with the suffix "Ptr". For example, declare an interface pointer with the following statement:


IAppConnTablePtr pTable;


To create an AppConn object, use the smart pointer CreateInstance method passing the class Id, which can be obtained using the __uuidof keyword with the class name. CreateInstance will return an HRESULT, which can be checked for success or failure.


hr = pSession.CreateInstance(__uuidof(AppConnTable));


The wrapper class creates a wrapper method for each object method. The methods do not return an HRESULT the way COM method normally do, but will throw the exception _com_error if the call fails, so all calls should be placed inside a try/catch block. The _com_error exception contains the ErrorInfo for the error that occurred. Optional parameters which are declared as _variant_t have a default parameter, so they may be omitted. The wrapper class replaces BSTR parameters with the wrapper class _bstr_t and VARIANT parameters with the wrapper class _variant_t. _bstr_t contains a BSTR and will automatically convert from char *, wchar_t *, BSTR, and _variant_t. _bstr_ will call SysAllocString to create the internal string, and will call SysFreeString to destroy the string when a new value is assigned or when it is destroyed. _variant_t contains a VARIANT and will automatically convert values that can be stored as a VARIANT. _variant_t will call VariantClear to destroy the variant when a new value is assigned or when it is destroyed. By changing BSTR and VARIANT to the wrapper classes, parameters can be passed to the method as primitive COM pointer or printf type and the compiler will handle conversion and life type management. Methods will return the COM return value directly instead of as the last parameter of the parameter list as COM methods normally do.

  try {
     pSession->ConnectToModel("localhost","CCSDemo","bjones","bjones");
  }
  catch (_com_error &err) {
     printf("Error: %s\n", OLE2A((LPOLESTR) err.Description()));
  }

Return values from the wrapper class method are returned directly to the caller. BSTR values are returned as _bstr_t, VARIANT values are returned as _variant_t, and pointers to COM interfaces are returned as smart pointers, so life management will be handled automatically by the returning object.

  _bstr_t bstrString;
  try {
     bstrString = pSession->GetStringAtOffset(10, 5);
  }
  catch (_com_error &err) {
     printf("Error: %s\n", OLE2A((LPOLESTR) err.Description()));
  }


The wrapper class also declares properties which the compiler treats as data members by changing their references into function calls. The properties can be treated like data members.

VARIANT_BOOL bConnect = pSession->IsConnected


The wrapper class also declares properties with parameters. In the following example, Item is a property of AppConnStringMap which handles both get and put with an index that can be either a string or an number. Put with a string will add the key/value if the key does not exist and replace the value if the key does exist. Put with a number will replace the value if the index exists and throw an error if it does not.

IAppConnStringMapPtr pAttributes;

pAttributes.CreateInstance(__uuidof(AppConnStringMap));
pAttributes->Item["LastName"] = "S";
bstrt bstrLastName = pAttributes->Item[1];


The following example demonstrates the different ways the wrapper classes can be used to simplify using the AppConn objects. The first line inside the try block creates an instance of AppConnStringList assigned to pSelectFields. Because pSelectFields is declared as a smart pointer life time management will be done automatically and the object will be destroyed when pSelectFields goes out of scope. The second line inside the try block adds an entry to pFilter with the key "LastName" and value "Brown". Because the parameters to Add are declared as _bstr_t in the wrapper class the parameters will automatically be converted from char * to BSTR and cleaned up. The third line inside the try block executes the PerformTableProcedure method which will return an AppConnRecordSet. The value is assigned to pRecords which is a smart pointer. If the return value is not assigned to a variable the AppConnRecordSet will be destroyed automatically. The first two parameters of PerformTableProcedure are declared as _bstr_t, so AppConn will automatically convert the parameters from char * to BSTR and clean up the values after the method call. The next five parameters are optional so they could be omitted and are declared as _variant_t in the wrapper class. The fourth parameter is included in the method call, so all the parameters up to the fourth parameter must be included. The third parameter is declared inline as an instance of _variant_t, which will create an empty parameter and be handled as if it is omitted. The fourth parameter is passed as a smart pointer which _variant_t will automatically convert to a VARIANT and clean up the value when it is done. The for loop will iterate over each of the records in the recordset using the Count property declared in the AppConnRecordSet wrapper class to get number of records. The Item property declared in the AppConnRecordSet is used to assign each record to pRecord. The Detach method must be called on the smart pointer before assigning a value to pRecord; otherwise, it will cause an assert.

 IAppConnRecordSetPtr pRecords;
 IAppConnStringMapPtr pFilter;
 IAppConnModelRecordPtr pRecord;
 try {
     pFilter.CreateInstance(__uuidof(AppConnStringMap));
     pFilter ->Add("LastName", "Brown");
     pRecords = pSession->PerformTableProcedure("Person", "GetPerson", 
     _variant_t(), pFilter);
     for (long i = 0; i < pRecords->Count; i++) {
         pRecord = pRecords->Item[i];
         pRecord.Detach();
        }
  }
  catch (_com_error &err) {
      printf("Error: %s\n", OLE2A((LPOLESTR) err.Description()));
  }