SAS 9.1.3 Integration Technologies » Developer's Guide

Developing Windows Clients
Client Requirements
Client Installation
Selecting a Windows Programming Language
Programming with Visual Basic
Programming in the .NET Environment
Using VBScript
Programming with Visual C++
Using the Object Manager
Creating an Object
Object Manager Interfaces
Using a Metadata Server with the Object Manager
Metadata Configuration Files
Error Reporting
Code Samples
Using Connection Pooling
Choosing Integration Technologies or COM+ Pooling
Using Integration Technologies Pooling
Using Com+ Pooling
Pooling Samples
Using the IOM Data Provider
Using the Workspace Manager
Class Documentation
Windows Clients

Programming with Visual C++

All SAS IOM interfaces are designed to work well with Microsoft Visual C++.

As is the custom with ActiveX components, the documentation is written in terms of Visual Basic. This means that the default interface of a component is listed as if it were the interface of the COM object (coclass) itself—even though in pure COM terms, the default interface is just one of many interfaces implemented by the object. Thus, a C++ programmer would program to the "IWorkspace" interface, even though the Visual Basic documentation shows the methods as belonging to the "Workspace" object. This section discusses issues with which Visual C++ programmers must be concerned (in addition to the material covered in Programming with Visual Basic).

All IOM interfaces implemented by SAS are COM dual interfaces. This means methods and property get and set routines can be called as direction entry points with positional parameters. Although they implement an IDispatch interface at the beginning of each v-table, this is only for compatibility with older OLE Automation controllers. Visual C++ programs should not make calls using IDispatch::Invoke; but should instead call through the v-table entry for the specific method that they want to call. This further implies that the ClassWizard-generated wrappers for IDispatch (with COleDispatchDriver) should not be used in IOM programming. This feature of Visual C++ is now useful only for interfaces containing only IDispatch.

All event (also called source) IOM interfaces are COM custom interfaces. This means that callers to the Advise method should pass interfaces that only derive from IUnknown, not IDispatch. All parameters to the event interfaces are only in parameters, which means that none of the interfaces support the ability to return data to SAS through the event interface.

To use the IOM interface in your Visual C++ program, you should "#import" the IOM interface type library. Here is an example:

   #import "sas.tlb"

In order for this to work, you must make sure that the type library directory is listed in your include path.

The import statement causes everything in the type library to be placed in a namespace. The fully qualified name for IWorkspace would be SAS::IWorkspace. Also see the "using" directive in Visual C++, and the "-no_namespace" attribute on the import statement.

When you import a type library, the Visual C++ compiler creates a comprehensive set of definitions specific to that type library and using the helper classes in COM compiler support (as defined through <comdef.h>). The helper classes perform many useful functions including the following:

  • Provide smart pointers for interface references
  • Map COM HRESULTs to C++ exceptions
  • Use helper classes for BSTRs
  • Create wrapper functions the return the IDL-defined return value instead of an HRESULT
  • Provide create instance helpers

Programming with the Visual C++ COM compiler support is almost as easy as calling the functions in Visual Basic.

Unfortunately, as of Visual C++ V6, the COM compiler support is lacking in one important area. There are no wrapper functions for handling SAFEARRAYs. You must deal with the OLE Automation SAFEARRAY API directly.

Dealing with dimensions in this API requires care. You must be particularly careful if you are dealing with two-dimensional arrays. The APIs that deal with SAFEARRAYs take a dimension number that is 1-based. In a two-dimensional array, the rows are indexed in dimension 1 and the columns by dimension 2. When you create an input array using SafeArrayCreate(), the bounds are also passed in this order (the row bounds are passed in "rgsabound[0]" and the column bounds are passed in "rgsabound[1]"). Do not be confused by the ordering that you see when you display a SAFEARRAY structure in the debugger.

Finally, keep in mind that for IOM method calls, lower bounds must always be zero.