CoCreateInstanceEx()

First, we have a CoCreateInstanceEx() call to specifically create an object instance on a remote machine, and also optimize on the performance of the QueryInterface() mechanism across the network by handling multiple QueryInterface() operations during the CoCreateInstanceEx() call (utilizing only one network round-trip). The prototype is shown here:

HRESULT CoCreateInstanceEx( REFCLSID  rclsid,
                            IUnknown *  punkOuter,
                            DWORD * dwClsCtx,
                            COSERVERINFO* pServerInfo,
                            ULONG  cmq,
                            MULTI_QI  rgmqResults   );

The parameters are explained below:

Function Parameters Description
REFCLSID rclsid The CLSID of the COM class from which the object instance is to be created.
IUnknown * punkOuter If NULL, indicate that the object is not being aggregated. If non-NULL, the object being created is part of an aggregate. Note that out-of-process aggregation isn’t supported in the currently available version of DCOM. CoCreateInstanceEx() is guaranteed to return CLASS_E_NOAGGREGATION if a non-NULL value is passed, and the instance to be created is remote.
DWORD * dwClsCtx A value from the CLSCTX (execution context) enumeration, it can be:

CLSCTX_INPROC_SERVER,

CLSCTX_INPROC_HANDLER,

CLSCTX_LOCAL_SERVER,

CLSCTX_REMOTE_SERVER,

CLSCTX_SERVER or

CLSCTX_ALL

Note that the last three values include CLTSCTX_REMOTE_SERVER, which means that they will also allow creation of a remote instance. Recall that it’s still possible to create a remote server by external registry configuration, potentially overriding the use of this parameter by the client.

COSERVERINFO * pServerInfo Pointer to a COSERVERINFO structure that specifies the machine on which to create the object instance. The COSERVERINFO structure is defined to be:

typedef struct _COSERVERINFO

{

   DWORD dwReserved1;

   LPWSTR pwszName;

   COAUTHINFO __RPC_FAR *pAuthInfo;

   DWORD dwReserved2;

} COSERVERINFO;

The pwszName should be pointing to a wide string containing the server’s name. When using DCOM over TCP/IP, this can contain the IP address of the node, or a DNS name such as WWW2.ABC.COM. Otherwise, a UNC name such as \\MACHINE is allowed. The COAUTHINFO member contains a security blanket definition (see Chapter 9) structure:

typedef struct _COAUTHINFO

{

   DWORD dwAuthnSvc;

   DWORD dwAuthzSvc;

   LPWSTR pwszServerPrincName;

   DWORD dwAuthnLevel;

   DWORD dwImpersonationLevel;

   COAUTHIDENTITY __RPC_FAR *pAuthIdentityData;

   DWORD dwCapabilities;

} COAUTHINFO;

In most cases, when an NT Domain server is used to authenticate a user (using NTLMSSP), this member of the COSERVERINFO should be set to NULL rather than a pointer to COAUTHINFO. We'll cover security in more detail in Chapter 9.

If this parameter, COSERVERINFO, is NULL, the SCM will be asked to do its job to determine how to create an instance of the class by examining the registry.

ULONG cmq The number of the MULTI_QI structures being passed in as the rgmqResults parameter. Combined with rgmqResults, this parameter allows the DCOM runtime to save network round-trips by specifying multiple QueryInterface() calls to perform on the object immediately after creation. This must be at least 1 (i.e. you must get at least one interface for the remote object, otherwise why create it?).
MULTI_QI rgmqResults Contains an array of MUTLI_QI structures, which is defined as:

typedef struct _MULTI_QI

{

   const IID* pIID;

   IUnknown * pItf;

   HRESULT hr;

} MULTI_QI;

Upon calling, the pIID portion contains a pointer to the IID of each interface to QueryInterface() for. Upon call return, the pItf member will contain the interface pointer requested if the hr member is S_OK. If the hr member for a specified interface is E_NOINTERFACE, the pItf member is invalid, and the object doesn't support the interface requested.


The possible return values from CoCreateInstanceEx() are:

Return Code Description
S_OK The object instance was created successfully.
E_INVALIDARG One or more arguments passed in were invalid.
E_NOINTERFACE None of the specified interfaces in the rqmqResults was available from the object.
CO_S_NOTALLINTERFACES Not all of the specified interfaces in the rqmqResults were available, but at least one entry contains a valid interface.