Next: , Up: Using COM objects with GNAT   [Contents][Index]


3.1 The Static Method

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: , Up: Using COM objects with GNAT   [Contents][Index]