Dynamic Com

Dynamic Com

This article was contributed by Anthony Roach

Environment: Developed and tested under win 2000 and win 9x

There is a standard way of working with Com components where you develop a component and then you run your install program that calls Register Type Library for you. This all works nicely because the latest version of the component is registered and everyone is happy. The problem is that most of us don't get to work in that type of environment. In fact in seven years of developing software I have only a handful of times found myself in the position where software was not only being sold directly to the users but it had a full setup program with which to install it. Most of my work and I suspect, the work of a large number of other people has been for in house projects that where the code is either run from a single computer or the programmer goes to the computer and sets it up themselves.

This leads to multiple versions of DLL's on the same computer because the version that the developer wrote the code on is more up to date than the computer that is expected to run the code. So in order not to break everything else on the target computer the programmer has to include the required DLL's and place them in the directory of the executable. Because as everyone who finds themselves working in this kind of position soon learns that windows searches the current working directory first for required DLL's before it even searches the windows directory. The idea behind com that can remove this problem is that once a control is registered on a computer it doesn't matter where the binary file is located on the computer, or in the case of DCom, it could be on any other computer on the network. Windows will load the registered dll and the correct code will run. But this of course relies on the registration of the com component on the computer which is not always guaranteed when there is no official setup program and no control over the code.

The way around this is to build into the code a defensive coding technique which will attempt to load the required component and if the call to cocreateinstance fails because the component is not registered then the code will register the component on the computer. This requires that the component is located in the same place as your executable so that the component can be found by the code. The class CRegisterComObject provides four functions,

 bool UnRegisterDll( CString strDll );
 bool RegisterDll( CString strDll );
 bool UnRegisterExe( CString strExe );
 bool RegisterExe( CString strExe );

These functions work as there names imply. With the name of the dll/exe to be registered/unregistered passed as a parmeter. It should be noted here that the name to pass is the dll or executable name of the binary file which is not necassarily the name of the Component interface that you were trying to load.

Using the Class

First of all the value returned from CoCreateInstance when a class is not defined is

#define CLASS_NOT_REGISTERED -2147221164

which I usually define as above. Second, in order to call CoCreateInstance you must also include the _i.c file that was generated when the component/s were built.

Once you have included these you can try to load your components. There are two similar ways you can do this. You can use the typelibrary defined pointer or the CComPtr template the code styles are very similar.

The first way is:

CComPtr< IMyInterface > pMyInterface;

HRESULT hResult = pMyInterface.CoCreateInstance(CLSID_MyInterface);
If( FAILED( hResult ) )
  if( hResult == CLASS_NOT_REGISTERED )
    /// try to register the class.
    CRegisterComObject register;
    if( register.RegisterDll( _T( "DllName.dll" ) ) )
      hResult = pMyInterface.CoCreateInstance( CLSID_MyInterface );
      If( FAILED( hResult ) )
        /// abort nothings working
      /// registering the dll failed
    /// CoCreateInstance failled for a different reason

/// use the com pointer as normal

The Second way would be with the type library defined pointer which would read:

IMyInterfacePtr pMyInterface;
HRESULT hResult = pMyInterface.CreateInstance(CLSID_MyInterface);

Internally the code gets the current windows path so that it can call regsvr32.exe. It then sets up the parameters to pass to the regsvr32 program including the dll./exe name, if required.

if( ::CreateProcess( strRegServer, 
                     strParam.GetBuffer( 0 ), 
                     NULL, NULL, 
                     NULL, NULL, 
                     &piInfo ) )
   ::WaitForSingleObject( piInfo.hProcess, WAITFOR );

   ::CloseHandle( piInfo.hProcess );
   ::CloseHandle( piInfo.hThread );
   return true;

The code then calls CreateProcess creating a new background process to handle the registration of the component. The code then waits for the process to finish using the specified time WAITFOR which is defined as:

#define WAITFOR 10000

In the RegisterComObject cpp file.

All the functions work on this system of setting up the required string to pass to the regsvr32.exe file and then waiting for it to complete.

The demo project that comes with the class allows the tester to register, remove and test components as they go along. Although it must be pointed out that even though the example works perfectly regarding the executable, the same cannot be said for the dll. It appears that the dll isn't unloaded from memory immediately so that if you try to unregister it after having tested it or registered it the code reports a success but then if you test the code for the dll, this also reports a success. Having said that it isnt recommended that anyone registers and deletes components as they go, this code was written to get around the stumbling block of the component not being registered and the unregister functions were added for the sake of completeness rather than being able to think of a single reason why using them would be a good idea.


Download demo project - 69 Kb
Download source - 3 Kb

This article was originally published on September 26th, 2001

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date