Configuring COM Objects for Distributed Use

The location of a COM object is transparent to a COM client and can be located on remote machines. It is possible to request remote connections, but alternately an OS supporting COM can be configured to look for the object at a remote location.

This sample application is used to configure a remote machine to access a host machine that has been configured with the beep com object. The BeepCom example can be used to test the object from a remote machine.

In addition to the regular configuration of the beep com object on the host machine you will have to run the DCOM configuration program dcomcnfg. In dcomcnfg you need to select the Beep Class application then click properties. Under the security tab, you will need to add permissions for users that will be using the COM object to the access and launch settings. Finally, under the identity tab, you need to set the application to run as the interactive user. Normally it would not be necessary to modify the identity, but since the example COM object pops up a dialog box on the host machine, it needs to run as the interactive user.

Compile this example and then run it on a remote machine on your network. (Windows 95 machines require DCOM for Win95 from Microsoft). Then you can run the BeepCom sample to test it. The dialog box and beep should show up on the host machine.

ObjectAda Notes:

To compile under ObjectAda remove the pragma Linker_Options and insure that your project includes the following directories in the project search path:

Also, since ObjectAda comes with the Microsoft import libraries, you can ignore the comment before the Linker_Options pragmas.
with Win32.objbase; use Win32.objbase;
with Win32.winerror; use Win32.winerror;
with Win32.oleauto;
with win32.winnt;
with win32.winbase;
with Win32.Winreg;
with Win32.WinMain;
with Win32;

with Ada.Text_IO; use Ada.Text_IO;
with interfaces.c; use interfaces.c;
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Unchecked_Conversion;
with Ada.Characters.Handling;
with System;

procedure BeepRemote is

   pragma Linker_Options ("beeprc.rbj");

    -- If you don't have the Microsoft import lib then use:
    -- pragma Linker_Options ("-loleaut32") and delete all
    -- code relating to unregistering the COM object

   pragma Linker_Options ("oleaut32.lib");
   pragma Linker_Options ("-lole32");
   pragma Linker_Options ("-luser32");

   function To_PCBYTE is
      new Ada.Unchecked_Conversion (System.Address, Win32.PCBYTE);
   function To_PCCH is
      new Ada.Unchecked_Conversion (System.Address, Win32.PCCH);
   function To_PCWSTR is
      new Ada.Unchecked_Conversion (System.Address, Win32.PCWSTR);
   function To_PWSTR is
      new Ada.Unchecked_Conversion (System.Address, Win32.PWSTR);
   function To_PCHAR is
      new Ada.Unchecked_Conversion (System.Address, Win32.PCHAR);

   procedure Register(KeyName, ValueName, Value : String) is
         hkey       : aliased Win32.Winreg.HKEY;
         err        : Win32.Long;
         cKeyName   : aliased char_array := To_C(KeyName);
         cValueName : aliased char_array := To_C(ValueName);
         cValue     : aliased char_array := To_C(Value);

      err := Win32.Winreg.RegCreateKey(Win32.Winreg.HKEY_CLASSES_ROOT,
                                       To_PCCH(cKeyName'Address), hkey'Unchecked_Access);
      err := Win32.Winreg.RegSetValueEx(hkey, To_PCCH(cValueName'Address), 0, Win32.Winnt.REG_SZ,
                                        To_PCBYTE(cValue'Address), cValue'Length);
      err := Win32.Winreg.RegCloseKey(hkey);
   end Register;

   function UnRegisterTypeLib(
            libid     : access Win32.Objbase.IID;
            wVerMajor : Win32.WORD;
            wVerMinor : Win32.WORD;
            lcid      : Win32.Winnt.LCID;
            syskind   : Win32.Oleauto.SYSKIND) return Win32.Objbase.HRESULT;
   pragma Import(Stdcall, UnRegisterTypeLib, "UnRegisterTypeLib");

   procedure Unregister(KeyName : String) is
      err : Win32.Long;
      cKeyName   : aliased char_array := To_C(KeyName);
      err := Win32.Winreg.RegDeleteKey(Win32.Winreg.HKEY_CLASSES_ROOT, To_PCCH(cKeyName'Address));
   end Unregister;

   hr                : Win32.Winerror.HRESULT;
   com_error         : exception;

   -- Type library ID for our COM Object
   LIBID_BeepLibrary : aliased IID := (16#0FE0EE20#,16#8AA2#,16#11d2#,
                         Char'Val(16#00#),Char'Val(16#01#)) );

   -- Check command line for RegServer/UnRegServer
   if Argument_Count /=1 then

      put_line(" To register component on remote machine use: BeepRemote HostName");
      put_line(" To unregister component use: BeepRemote /UnregServer");

   elsif (Argument(1) = "/UnregServer") or (Argument(1) = "-UnregServer") then
      hr := UnRegisterTypeLib(LIBID_BeepLibrary'Unchecked_Access, 1, 0,
               Win32.Winnt.LANG_NEUTRAL, Win32.OleAuto.SYS_WIN32);


      put_line("The COM object BeepClass has been unregistered.");
         dr        : Win32.DWORD;
         MAX_PATH  : constant := 1024;
         ExePath   : aliased char_array(1..MAX_PATH);
         pTypeLib  : aliased Win32.OleAuto.LPTYPELIB;
         refcount  : Win32.Ulong;

         dr:=Win32.Winbase.GetModuleFileName(Win32.WinMain.Get_Hinstance, To_PCHAR(ExePath'Address), MAX_PATH);
            wFilePath : aliased wchar_array := To_C
                     (ada.characters.handling.to_wide_string (To_Ada(ExePath)));
            hr:=Win32.OleAuto.LoadTypeLib(To_PCWSTR(wFilePath'Address), pTypeLib'Unchecked_Access);
            hr:=Win32.OleAuto.RegisterTypeLib(pTypeLib, To_PWSTR(wFilePath'Address), To_PWSTR(System.Null_Address));
            refcount := pTypeLib.lpVtbl.Release(pTypeLib);

         Register("CLSID\{0FE0EE21-8AA2-11d2-81AA-444553540001}", "", "Beep Class" );
         Register("CLSID\{0FE0EE21-8AA2-11d2-81AA-444553540001}", "AppID", "{0FE0EE21-8AA2-11d2-81AA-444553540001}" );
         Register("CLSID\{0FE0EE21-8AA2-11d2-81AA-444553540001}\ProgID", "", "BeepLibrary.BeepClass.1");
         Register("CLSID\{0FE0EE21-8AA2-11d2-81AA-444553540001}\VersionIndependentProgID", "", "BeepLibrary.BeepClass");
         Register("BeepLibrary.BeepClass", "", "Beep Class" );
         Register("BeepLibrary.BeepClass\CLSID", "", "{0FE0EE21-8AA2-11d2-81AA-444553540001}" );
         Register("BeepLibrary.BeepClass\CurVer", "", "BeepLibrary.BeepClass.1" );
         Register("BeepLibrary.BeepClass.1", "", "Beep Class" );
         Register("BeepLibrary.BeepClass.1\CLSID", "", "{0FE0EE21-8AA2-11d2-81AA-444553540001}" );
         Register("AppID\{0FE0EE21-8AA2-11d2-81AA-444553540001}", "", "Beep Class" );
         Register("AppID\{0FE0EE21-8AA2-11d2-81AA-444553540001}", "RemoteServerName", Argument(1) );

         put_line("The COM object BeepClass has been registered.");

   end if;

end BeepRemote;

Contributed by: David Botton
Contributed on: March 18, 1999
License: Public Domain