Managing Objects in ActiveX Applications
CA_ServerCreateObject creates an ActiveX object programmatically. ActiveX clients cannot create sub-objects (objects that are not top-level) directly. The server creates sub-objects and returns the object interface pointer to ActiveX clients through method/property calls. Consider the following example: the application object of an SDI application normally has an interface member, such as a method called GetDocument or a Document property, that can be used to access the document object. In this example, the application object is the top-level object, and the document object is the sub-object. Use CA_ServerCreateObject when the server needs to create a sub-object to return to the client. This function takes the CLSID of the object to be created and returns a pointer to the requested interface, if that object implements the interface.
You can create an object as an aggregate of another object by passing the IUnknown pointer of the aggregating (outer) object to CA_ServerCreateObject. Aggregation is used by an ActiveX object, called the outer object or aggregator, to expose functionality that is actually present in another ActiveX object, called the inner object or aggregatee. Aggregation is a form of binary reuse of COM objects. The outer object exposes an interface, representing the reused functionality, that actually belongs to the inner object. Calls to the outer object through the aggregated interface are delegated to the inner object. After creating the inner object using CA_ServerCreateObject, call CA_ServerAggregateObject to aggregate it in the outer object. Pass the CAServerObjHandle of the aggregating object in the Server Object Handle parameter, and pass the IUnknown pointer of the aggregatee in the Inner Object IUnknown parameter. Pass the IID of the inner object interface to be exposed by the outer object in the Interface Id To Aggregate parameter. The inner object can be any ActiveX object that supports aggregation.
For example, in the following image, Obj1 is the outer object and implements interface IFoo, and Obj2 is the inner object and implements IBar. Using aggregation, Obj1 exposes the IBar interface of Obj2 as its own interface.

The following code demonstrates aggregation:
HRESULT CVIFUNC OuterObjCb (CAServerObjHandle objHandle, const CLSID *pClsid, int
event, void *callbackData)
{
HRESULT hr = S_OK;
IUnknown *pUnkAgg = NULL;
IUnknown *pUnk = NULL;
if (event == CA_SERVER_EVENT_OBJECT_CREATE) {
caErrChk (CA_ServerGetIfaceFromObjHandle (objHandle,&IID_IUnknown,&pUnk));
caErrChk (CA_ServerCreateObject (&CLSID_InnerObj, pUnk,&IID_IUnknown,&pUnkAgg));
caErrChk (CA_ServerAggregateObject (objHandle,&IID_IAggregatedIface,pUnkAgg));
}
Error:
if (pUnk)
pUnk->lpVtbl->Release (pUnk);
if (pUnkAgg)
pUnkAgg->lpVtbl->Release (pUnkAgg);
return hr;
}
Managing Object-Owned Data
The CA_ServerSetObjData, CA_ServerGetObjData, and CA_ServerReleaseObjData functions are similar to the corresponding functions that manage global data. These functions manage object-owned data. The per-object data can be any data required by an ActiveX object implementation. For example, the ActiveX properties of an object are normally stored on a per-object basis. In some cases, the object data might not be an ActiveX property. For example, an ActiveX object that represents an instrument stores the configuration information of that instrument in object-specific data. Notice that while the ActiveX properties of an object are exposed to ActiveX clients through interfaces, the object-specific data is internal to the server. The data pointer passed to these functions should be object specific and should be stored in the heap (dynamic memory). Place all the object-specific data in a structure. You must allocate an instance of the structure with the CA_SERVER_EVENT_OBJECT_CREATE event in the object callback function when you call the function during object creation. You also must pass the allocated pointer to CA_ServerSetObjData. When the code needs to access the object data, call CA_ServerGetObjData with the object handle. After using the pointer of the object data returned by CA_ServerGetObjData, call CA_ServerReleaseObjData to relinquish the pointer. Every function that calls CA_ServerGetObjData also must call CA_ServerReleaseObjData. Free the memory for the allocated data when the object is destroyed, that is, in the CA_SERVER_EVENT_OBJECT_DESTROY case of the object callback function. Advanced users can choose to manage their object data using synchronization primitives based on the threading model of their ActiveX server.
Refer to the CA_ServerSetObjData topic for example code demonstrating the use of the object data functions.
Managing Objects Using Interface Pointers
You can use CA_ServerGetObjHandleFromIface to get object handles from interface pointers and CA_ServerGetIfaceFromObjHandle to get interface pointers from object handles. Because an ActiveX object can implement more than one interface, the CA_ServerGetIfaceFromObjHandle function takes an IID that identifies the interface to return. Use these functions only with the object handles and interface pointers of server objects created in LabWindows/CVI. These functions can be useful in the following situations:
- Sometimes the clients might pass a server object interface pointer to another server object. When that happens,
you can use CA_ServerGetObjHandleFromIface to get the object handle from the interface pointer, as shown
in the following sample code:
HRESULT CVIFUNC ObjIFooCacheObject (CAServerObjHandle objHandle, IUnknown* srvrObj)
{
CAServerObjHandle hObj = 0;
if (srvrObj == NULL)
return E_INVALIDARG; // Check input
// Get object handle from interface pointer
if (SUCCEEDED (CA_ServerGetObjHandleFromIface (srvrObj, &hObj))) {
CacheObjectHandle (hObj); // Cache the handle
return S_OK; // Return success
}
else
return E_FAIL; // If cannot get handle return failure
} - Some ActiveX objects might have an interface with a method that returns a pointer to another interface implemented by the same object to requesting ActiveX clients. In this case, use
CA_ServerGetIfaceFromObjHandle to get the interface pointer to return, as shown in the following sample code:
HRESULT CVIFUNC ObjIFooGetIBar (CAServerObjHandle objHandle, IBar** barIface)
{
if (barIface == NULL)
return E_INVALIDARG; // Check input
// Get IBar interface using object handle
if (SUCCEEDED (CA_ServerGetIfaceFromObjHandle (objHandle, &IID_IBar, barIface)))
return S_OK; // Return success
else
return E_FAIL; // If cannot get interface return failure
}