Lately I received some COM-automation related questions which I answered by referring to this blog post: CreateObject Peculiarities (part 1). It advised to use the CoCreateInstance() API with the IID_IUnknown parameter to connect to an automation server. However, after re-reading I realized I could have demonstrated how to use CoCreateInstance. Below is an example that replaces the GB32 CreateObject() function with the custom made CreateObject2() function. It provides the same functionality as CreateObject and more. Where CreateObject only returns an object if it supports the IDispatch inteface, the CreateObject2() function has an optional parameter that takes any interface you want to request from the server. By default, it returns an object that supports the IDispatch interface, and if that fails it returns the IUnknown interface.
The code is heavily commented, so I hope you will be able to understand it. As an example, CreateObject2 is used to obtain the IDispatch interface of the Scripting's FileSystemObject.
$Library "gfawinx" $Library "UpdateRT" UpdateRuntime ' Patches GfaWin23.Ocx Dim FSO As Object ' CreateObject2(ClsID [, IID]) replaces CreateObject(ClsID). Set FSO = CreateObject2("Scripting.FileSystemObject", IID_IDispatch) MsgBox0("Successfully created object.") ' FSO object is released when it goes out-of-scope. Function CreateObject2(ClassID As String, Optional IID_Interface As Long) As Object '------------------------------------------------------------------- ' Like CreateObject creates an Instance of an OLE Server. ' The ClassID argument creates a class & specifies the OLE Server. ' The IID_Interface argument specifies the interface to create. ' There are two formats for the ClassID class argument: ' 1. PROGID: "Excel.Application" ' 2. CLSID: "{00000010-0000-0010-8000-00AA006D2EA4}" ' If a ProgID is used, the client's registry is used to get the CLSID ' If the optional IID_Interface parameter isn't used, a reference ' to the IDispatch interface is created. If that fails, a reference ' to the IUnknown interface is created. ' The IID_Interface is pointer to GUID type, created by GUID command. '------------------------------------------------------------------- Dim wProgId As Variant = ClassID ' to Unicode Dim Ptr_ProgID As Long = {V:wProgId + 8} ' string address Dim HResult As Long ' COM error code Dim ClsID_ProgID As GUID ' GUID is built-in type Dim fAskDispatch ' set if II_IDispatch is asked ' Get CLSID (GUID) type from either GUID$ or ProgID$ If Left(ClassID) = "{" && Right(ClassID) = "}" && Len(ClassID) = 38 HResult = CLSIDFromString(Ptr_ProgID, ClsID_ProgID) Else HResult = CLSIDFromProgID(Ptr_ProgID, ClsID_ProgID) End If If HResult != S_OK Then _ Err.Raise HResult, "CreateObject2", "Wrong CLSID" ' The default is to ask for IDispatch (like CreateObject) If IID_Interface = 0 Then IID_Interface = IID_IDispatch ' Remember whether IID_IDispatch is asked fAskDispatch = IsEqualGUID(IID_Interface, IID_IDispatch) ' Create a single instance of an object (ClsID_ProgID) on ' the local machine that supports the requested interface. ' Store the instance in the local function-return variable. HResult = CoCreateInstance(ClsID_ProgID, Null, CLSCTX_ALL, _ IID_Interface, V:CreateObject2) // Only if asked for IID_IDispatch and it failed, try IID_IUnknown If HResult == E_NOINTERFACE && fAskDispatch IID_Interface = IID_IUnknown HResult = CoCreateInstance(ClsID_ProgID, Null, CLSCTX_ALL, _ IID_Interface, V:CreateObject2) EndIf // If all requests for an interface have failed raise error If HResult != S_OK Then _ Err.Raise HResult, "CreateObject2", "No interface" ' ------------------------------------------------------ ' Global declarations section ' ------------------------------------------------------ Global Const E_NOTIMPL = 0x80004001 Global Const E_NOINTERFACE = 0x80004002 ' ------------------------------------------------------- ' GUID Identifier = value (global declaration command) ' Generates a pointer to a 128 bit memory block containing ' a GUID value. So, IID_IUnknown is a Long holding the ' address of the GUID value. ' ------------------------------------------------------- GUID IID_IUnknown = 00000000-0000-0000-c000-000000000046 GUID IID_IDispatch = 00020400-0000-0000-c000-000000000046 Global Enum CLSCTX, CLSCTX_INPROC_SERVER, CLSCTX_INPROC_HANDLER = 2, _ CLSCTX_LOCAL_SERVER = 4, CLSCTX_REMOTE_SERVER = 16, _ CLSCTX_SERVER = CLSCTX_INPROC_SERVER + CLSCTX_LOCAL_SERVER + _ CLSCTX_REMOTE_SERVER, _ CLSCTX_ALL = CLSCTX_INPROC_SERVER + CLSCTX_INPROC_HANDLER + _ CLSCTX_LOCAL_SERVER + CLSCTX_REMOTE_SERVER ' ------------------------------------------------------- ' CoCreateInstance note. ' The GB GUID is a pointer to a GUID type in memory. ' To make it possible to use a GB-GUID, we should adjust ' the Declare to receive a Long holding the address. ' ------------------------------------------------------- Declare Function CoCreateInstance Lib "OLE32" _ (ByRef rclsid As GUID, ByVal pUnkOuter As Long, _ ByVal dwContent As Long, ByVal pIID As Long, _ ByVal ppv As Long) As Long Declare Function CLSIDFromString Lib "OLE32" _ (ByVal lpszCLSID As Long, pclsid As GUID) As Long Declare Function CLSIDFromProgID Lib "OLE32" _ (ByVal lpszProgID As Long, pclsid As GUID) As Long Declare IsEqualGUID Lib "ole32" (ByVal prguid1 As Long, ByVal prguid2 As Long) As Bool EndFunc
No comments:
Post a Comment