Next: The Dynamic Method, Up: Using COM objects with GNAT [Contents][Index]
Step 1 - Create Binding
The first step in using COM objects from GNAT is to create an Ada binding to the interfaces supported by the COM Object and to the needed GUIDs for the object and the interfaces. The author of the object provides this information in source format, or as a Type Library. There are a number of tools that can read Type Libraries and provide the needed information including COMScope (see http://www.gnavi.org) and Microsoft’s OLE/COM object viewer distributed with the Win32 platform development kit.
An aliased CLSID should be created for the GUID of the object to be created and IIDs for each interface.
For example:
-- CLSID of COM object to create
-- {45F9F481-787C-11D3-821C-52544C1913DE}
CLSID_GNATCOMClass : aliased CLSID :=
(16#45F9F481#, 16#787C#, 16#11D3#,
(char'Val (16#82#), char'Val (16#1C#),
char'Val (16#52#), char'Val (16#54#),
char'Val (16#4C#), char'Val (16#19#),
char'Val (16#13#), char'Val (16#DE#)));
-- IID of the IGNATMessage interface
-- {45F9F482-787C-11D3-821C-52544C1913DE}
IID_IGNATMessage : aliased IID :=
(16#45F9F482#, 16#787C#, 16#11D3#,
(char'Val (16#82#), char'Val (16#1C#),
char'Val (16#52#), char'Val (16#54#),
char'Val (16#4C#), char'Val (16#19#),
char'Val (16#13#), char'Val (16#DE#)));
|
Then create access methods for the members of the interface you are planning to create and any inherited methods. Note that the first parameter of every function should be a pointer back to the interface itself. This provides the C++ style this pointer to the COM methods being called.
For example:
-- Inherited methods from IUnknown
type af_IGNATStat_QueryInterface is access
function (This : access IGNATStat;
riid : in REFIID;
ppvObj : access Win32.PVOID)
return Win32.Winerror.HRESULT;
pragma Convention (StdCall, af_IGNATStat_QueryInterface);
type af_IGNATStat_AddRef is access
function (This : access IGNATStat)
return Win32.ULONG;
pragma Convention (StdCall, af_IGNATStat_AddRef);
type af_IGNATStat_Release is access
function (This : access IGNATStat)
return Win32.ULONG;
pragma Convention (StdCall, af_IGNATStat_Release);
-- Methods of IGNATMessage
type af_IGNATStat_Calls is access
function (This : access IGNATStat;
NumberOfTimes : access Interfaces.C.int)
return Win32.Winerror.HRESULT;
pragma Convention (StdCall, af_IGNATStat_Calls);
-- Return number of times methods of the IGNATMessage interface
-- were called
|
Then construct the interface and the table of functions used to access the methods.
For example:
type IGNATStat is record
lpVtbl : Pointer_To_IGNATStatVtbl;
end record;
pragma Convention (C_Pass_By_Copy, IGNATStat);
type IGNATStatVtbl is record
QueryInterface : af_IGNATStat_QueryInterface;
AddRef : af_IGNATStat_AddRef;
Release : af_IGNATStat_Release;
Calls : af_IGNATStat_Calls;
end record;
pragma Convention (C_Pass_By_Copy, IGNATStatVtbl);
|
Step 2 - Initialize COM
Initialize the COM libraries with a call to CoInitialize:
hr : Win32.Winerror.HRESULT; hr := CoInitialize (System.Null_Address); |
Step 3 - Create Object
Create the object using CoCreateInstance that will return and access to
the requested interface in the COM object.
For example:
-- The requested interfaces is IID_IGNATMessage
hr := CoCreateInstance (CLSID_GNATCOMClass'Unchecked_Access,
null,
Win32.DWORD (CLSCTX_ALL),
IID_IGNATMessage'Unchecked_Access,
RetPointer'Unchecked_Access);
GnatMessage_Ref := To_Pointer_To_IGNATMessage (RetPointer);
|
Step 4 - QueryInterface
Use methods in the returned interface or request alternate interfaces
using QueryInterface.
For example:
-- To call a method
hr := GnatMessage_Ref.lpvtbl.Beep (GnatMessage_Ref);
-- To access a different interfaces of the object
-- in this case IID_IGNATStat
hr := GnatMessage_Ref.lpvtbl.QueryInterface
(GnatMessage_Ref,
IID_IGNATStat'Unchecked_Access,
RetPointer'Unchecked_Access);
GnatStat_Ref := To_Pointer_To_IGNATStat (RetPointer);
|
Step 5 - Release
When any interface is no longer needed a call to Release should be made.
For example:
refcount : Win32.ULONG; refcount := GnatStat_Ref.lpvtbl.Release (GnatStat_Ref); |
The reference count that is returned can be bogus and should not be relied upon for any purpose.
Step 6 - Unitialize COM
Shutdown the COM libraries with a call to CoUninitialize.
CoUninitialize; |
The client code should be compiled with the linker option -lole32 and
-loleaut32 to include the needed linker libraries. See the GNAT example
com_static.adb for a complete example of using COM objects.
Next: The Dynamic Method, Up: Using COM objects with GNAT [Contents][Index]