Using Windows' COM

Component Object Model (COM) is a Microsoft technology used for interoperability between Windows programs. D has built-in support for basic COM, and using its features, we can also automate the implementation of advanced COM features.

Here, we'll write a COM server and client with the help of a library and look at the implementation.

Getting ready

Download the Win32 bindings from http://dsource.org/projects/bindings and the comhelpers.d file from http://github.com/adamdruppe/com.

How to do it…

COM, like shared libaries, uses a client-server model. First, we'll write a COM server and then write its corresponding COM client.

COM server

Let's write a COM server by executing the following steps:

  1. Generate GUIDs for your interface and class using a GUID generation tool.
  2. Import win32.unknwn and comhelpers.
  3. Write your interface definition, inheriting from IUnknown and marking all methods extern(Windows). Attach the IID (interface's GUID) to the interface with the ComGuid attribute. Each method should return HRESULT.
  4. Add the CLSID to the interface file as a constant.

    The code for the preceding steps is as follows:

    import win32.basetyps;
    import win32.unknwn;
    
    import comhelpers;
    
    @ComGuid(GUID(0x00421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46]))
    interface IHello : IUnknown {
        extern (Windows) :
        int Print();
    }
    
    
    // this is the class id that we can use to instantiate in the client and attach to the
    // class in the implementation
    enum GUID CLSID_Hello = GUID(0x30421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46]);
  5. Create a separate file with the class definition. Inherit this class from the interface you defined and attach the CLSID to the class using the ComGuid attribute.
  6. Use the mixin ComObject!() method in your class and implement your interface.
  7. To enable COM automation on your object, for example, to make it usable from VBScript or JScript, also inherit from IDispatch when defining your class and add mixin IDispatchImpl!() to the class body.
  8. At the bottom of the file, add mixin ComServerMain!(YourClass, "ProgId", "1.0") class, where "ProgId" is your desired Program ID (for example, "MSXML2.XmlHttp") and 1.0 is your version number. The program ID and version number are used by clients to locate your object.
  9. You may have to compile with dmd –d to enable deprecated features because the Win32 bindings are infrequently updated. The code for this is as follows:
    import win32.winuser;
    
    import comhelpers;
    import ihello;
    
    @ComGuid(CLSID_Hello)
    class CHello : IHello, IDispatch {
            mixin ComObject!();
            mixin IDispatchImpl!();
    
            extern(Windows)
            public override HRESULT Print() {
                    import std.stdio; writeln("cool?");
                    MessageBoxA(null, "CHello.Print()", null, MB_OK);
                    return NOERROR;
            }
    }
    
    mixin ComServerMain!(CHello, "Hello", "1.0");
  10. Create a module definition file (yourname.def) with the following contents:
    LIBRARY         yourname
    EXETYPE         NT
    SUBSYSTEM       WINDOWS
    EXPORTS
            DllGetClassObject   = _DllGetClassObject@12
            DllCanUnloadNow     = _DllCanUnloadNow@0
            DllRegisterServer   = _DllRegisterServer@0
            DllUnregisterServer = _DllUnregisterServer@0
  11. Compile your interface file, class file, module definition file, and the downloaded comhelpers.d file together to generate your DLL.
  12. Register your server with regsvr32 yourdll.dll (this will require administrator access on the computer), or use a manifest file to enable registration-free COM in your client application.

COM client

Let's write a COM client by executing the following steps:

  1. Import comhelpers.d and the interface file you created for the server.
  2. Create the object with createObject!interface(CLSID). If you are using an object without the ComGuid attribute, you can specify it manually in the compile-time argument list after the interface. Alternatively, you may call CoCreateInstance from the Windows API directly.
  3. Use it. The createObject object of comhelper returns a wrapper object that automatically handles calling AddRef and Release.

The code is as follows:

import comhelpers;
import ihello;
void main() {
        auto obj = createObject!(IHello)(CLSID_Hello);
        obj.Print();
}

How it works…

D has some built-in understanding of COM—it recognizes the IUnknown interface. Anything derived from it is known to be a COM object. This is a bit rudimentary and D can do better with the help of a library—that's where comhelpers.d comes in. It is not necessary, nor part of the standard library; you can always call the Windows functions yourself. It handles some boilerplate code (with mixin templates) and binds GUIDs to interfaces and classes with a D feature called user-defined attributes to make the code easier to write.

There's more…

If you are on a 64-bit Windows system and building a 32-bit DLL, you'll have to register the COM server using the 32-bit version of regsrv32.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.145.82