Dynamic Com

Dynamic Com

This article was contributed byAnthony 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
      }
    }
    else
    {
      /// registering the dll failed
    }
  }
  else
  {
    /// 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, 
                     FALSE, 
                     CREATE_NEW_CONSOLE, 
                     NULL, NULL, 
                     &stInfo, 
                     &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 immeadiately 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.

Downloads

Download demo project - 69 Kb
Download source - 3 Kb



Comments

  • Windows 2000 Administrative Priviledges

    Posted by Legacy on 09/29/2001 12:00am

    Originally posted by: JL

    Does this require administrative access under Win 2000?

    I remember reading that write access to HKEY_LOCAL_MACHINE (which is needed ro register a COM object) requires admin priviledges?

    Could you clarify

    Reply
  • Error code is defined

    Posted by Legacy on 09/28/2001 12:00am

    Originally posted by: Ian Brumby

    The error code is defined. It is REGDB_E_CLASSNOTREG in winerror.h

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds