I have modified the above posted functions to return an IDispatch pointer.
' ========================================================================================
' If the requested object is in an EXE (out-of-process server), such Office applications,
' and it is running and registered in the Running Object Table (ROT), AfxGetCom will
' return a pointer to its interface. AfxAnyCom will first try to use an existing, running
' application if available, or it will create a new instance if not.
' Be aware that AfxGetCom can fail under if Office is running but not registered in the ROT.
' When an Office application starts, it does not immediately register its running objects.
' This optimizes the application's startup process. Instead of registering at startup, an
' Office application registers its running objects in the ROT once it loses focus. Therefore,
' if you attempt to use GetObject or GetActiveObject to attach to a running instance of an
' Office application before the application has lost focus, you might receive an error.
' See: https://support.microsoft.com/en-us/help/238610/getobject-or-getactiveobject-cannot-find-a-running-office-application
' ========================================================================================
PRIVATE FUNCTION AfxGetCom OVERLOAD (BYREF wszProgID AS CONST WSTRING) AS IDispatch PTR
DIM classID AS CLSID, pUnk AS IUnknown PTR, pDisp AS IDispatch PTR
CLSIDFromProgID(wszProgID, @classID)
IF IsEqualGuid(@classID, @IID_NULL) THEN RETURN NULL
GetActiveObject(@classID, NULL, @pUnk)
IF pUnk THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
END IF
RETURN pDisp
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxGetCom OVERLOAD (BYREF classID AS CONST CLSID) AS IDispatch PTR
DIM pUnk AS IUnknown PTR, pDisp AS IDispatch PTR
GetActiveObject(@classID, NULL, @pUnk)
IF pUnk THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
END IF
RETURN pDisp
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxAnyCom OVERLOAD (BYREF wszProgID AS CONST WSTRING) AS IDispatch PTR
DIM classID AS CLSID, pUnk AS IUnknown PTR, pDisp AS IDispatch PTR
CLSIDFromProgID(wszProgID, @classID)
IF IsEqualGuid(@classID, @IID_NULL) THEN RETURN NULL
' // Check if there is an instance already running
IF GetActiveObject(@classID, NULL, @pUnk) = S_OK THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
RETURN pDisp
END IF
' // Otherwise, create a new instance
CoCreateInstance(@classID, NULL, CLSCTX_INPROC_SERVER, @IID_IUnknown, @pUnk)
IF pUnk THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
END IF
RETURN pDisp
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxAnyCom OVERLOAD (BYREF classID AS CONST CLSID) AS IDispatch PTR
DIM pUnk AS IUnknown PTR, pDisp AS IDispatch PTR
' // Check if there is an instance already running
IF GetActiveObject(@classID, NULL, @pUnk) = S_OK THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
RETURN pDisp
END IF
' // Otherwise, create a new instance
CoCreateInstance(@classID, NULL, CLSCTX_INPROC_SERVER, @IID_IUnknown, @pUnk)
IF pUnk THEN
pUnk->lpVtbl->QueryInterface(pUnk, @IID_IDispatch, @pDisp)
pUnk->lpVtbl->Release(pUnk)
END IF
RETURN pDisp
END FUNCTION
' ========================================================================================