OLE Automation with Delphi part II
Going on with my previous post (OLE Automation with Delphi part I) where I was able to use the invocation of the "Word.Application" service using COM. In this post I am going to show you how to detect if a service is available using OLE Automation. First of all, I'm going to give you a brief overview of the windows Registry and where are all these COM class objects allocated, and then I will move forward to show the Delphi code that is used for this purpose.
COM class objects are identified by a CLSID key:
A CLSID is a globally unique identifier that identifies a COM class object. If your server or container allows linking to its embedded objects, you need to register a CLSID for each supported class of objects
source: msdn.
If we have installed Microsoft Word and look for "Word.Application" inside the registry, we will find the following information under \HKEY_CLASSES_ROOT\Word.Application:
This entry has the CLSID key = {000209FF-0000-0000-C000-000000000046}. This CLSID key has been set when the component was registered. We can look it up and check what executable or routine is invoking in the next key entry: HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLSID}.
As we can see, it shows the path of Microsoft word and with the option /Automation. Now that we know how to deal with the windows registry and how are set out CLSID keys, let's move on how to use this information with Delphi.
Check if the COM Class Object is registered:
To ensure that the service is available, we can use the OLE32 methods available through ActiveX and ComObj units.
unit Activex; function CLSIDFromProgID; external ole32 name 'CLSIDFromProgID';
Example of use:
uses ActiveX, ComObj; procedure TForm1.CheckCLSIDClick(Sender: TObject); var clsid: TCLSID; sCLSID: string; result: hResult; begin // initialize COM CoInitialize(nil); // Get CLSID from Microsoft Word result := CLSIDFromProgID('Word.Application', clsid); sCLSID := GUIDToString(clsid); try OleCheck(result); ShowMessage('Class Word.Application recognized with CLSID ' + sCLSID); except on e: EOleSysError do begin ShowMessage('Class Word.Application not recognized CLSID ' + sCLSID); end; end; // deinitialize COM CoUninitialize; end;
Invoking the COM Class Object:
Now that we are sure the COM Class is registered, we can cater the CoCreateInstance method to invoke the class with the proper context properties. dwClsContext is the context in which the code that manages the newly created object will run. The values are taken from the enumeration CLSCTX.
We can find this enumerators in the ActiveX unit with the following values:
{$EXTERNALSYM CLSCTX_INPROC_SERVER} CLSCTX_INPROC_SERVER = 1; {$EXTERNALSYM CLSCTX_INPROC_HANDLER} CLSCTX_INPROC_HANDLER = 2; {$EXTERNALSYM CLSCTX_LOCAL_SERVER} CLSCTX_LOCAL_SERVER = 4; {$EXTERNALSYM CLSCTX_INPROC_SERVER16} CLSCTX_INPROC_SERVER16 = 8; {$EXTERNALSYM CLSCTX_REMOTE_SERVER} CLSCTX_REMOTE_SERVER = $10; {$EXTERNALSYM CLSCTX_INPROC_HANDLER16} CLSCTX_INPROC_HANDLER16 = $20; {$EXTERNALSYM CLSCTX_INPROC_SERVERX86} CLSCTX_INPROC_SERVERX86 = $40; {$EXTERNALSYM CLSCTX_INPROC_HANDLERX86} CLSCTX_INPROC_HANDLERX86 = $80;
Example of use:
If we take a look again at the Registry picture above, we will notice that our COM Class uses a LOCAL_SERVER context, and that's the value that we will have to set in the API method.
This simple example will use the COM CLSID to invoke Microsoft Word and open it:
uses ActiveX, ComObj, Ole2; {$R *.dfm} procedure TForm1.InvokeCLSIDClick(Sender: TObject); var clsid: TCLSID; sCLSID: string; result: hresult; localCLSCTX: Integer; IWordApp: IUnknown; dispIWord: IDispatch; AttrName: POleStr; paramArgument: VARIANTARG; disparam: DISPPARAMS; dispIDs: TDispID; did: TDispID; begin // initialize COM CoInitialize(nil); localCLSCTX := CLSCTX_LOCAL_SERVER; try // Get CLSID from Microsoft Word result := CLSIDFromProgID('Word.Application', clsid); // sCLSID := GUIDToString(clsid); OleCheck(result); // create Microsoft Word instance result := CoCreateInstance(clsid, nil, localCLSCTX, IID_IUnknown, IWordApp); OleCheck(result); // get IDispatch interface of received object IWordApp.QueryInterface(IID_IDispatch, dispIWord); // Invoke Microsoft Word AttrName := 'Visible'; paramArgument.vt := VT_BOOL; paramArgument.vbool := true; disparam.cArgs := 1; disparam.rgvarg := @paramArgument; dispIDs := DISPID_PROPERTYPUT; disparam.cNamedArgs := 1; disparam.rgdispidNamedArgs := @dispIDs; dispIWord.GetIDsOfNames(GUID_NULL, @AttrName, 1, LOCALE_SYSTEM_DEFAULT, @did); result := dispIWord.Invoke(did, GUID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, disparam, nil, nil, nil); OleCheck(result); except on e: EOleSysError do begin ShowMessage('Class Word.Application not found CLSID ' + sCLSID); end; end; // release unused objects dispIWord.Release; IWordApp.Release; // deinitialize COM CoUninitialize; end;
Related links:
Comments
Post a Comment