views:

686

answers:

5

An application I have recently started work on has to register two dll's, "because of ActiveX".

This makes it difficult to have multiple version of the application present on your machine - say the installed product version, and Debug and Release versions of the latest development sources.

What are the alternatives to registration for ActiveX.

A: 

None that I can think of. That's the whole rationale behind COM (thus ActiveX).

Otávio Décio
A: 

If you control the code that loads the ActiveX control, and nobody else needs to load it, you could skip the registration and manually handle your own CreateInstance calls: LoadLibrary, get a pointer to the Factory object, and create instances directly.

Did that on a project about 10 years ago and it worked great.

However, if you can't do that (maybe you don't control the code calling CreateInstance), then just create two batch files and put them on your desktop: One to register Debug, and one to register the Release DLLs. Switching back and forth then becomes pretty easy.

DougN
the .bat trick is a horrible idea - you may unregister other version of the applications installed on that system.
Francis
A: 

You can version ActiveX controls using the ProgID.

jeffamaphone
+1  A: 

If your application loads the ActiveX objects, there are a couple of options. The first option if you are using XP or newer, it to use a Registration-Free COM with a Manifest file as explained on MSDN. The idea is to declare your COM (ActiveX) components in a manifest file instead of the registry. So for MyApp.exe, create MyApp.exe.manifest with the following (using your DLL file name and CLSID):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="MyApp_ActiveX" version="1.0.0.1" 
        processorArchitecture="x86" publicKeyToken="0000000000000000" />

  <file name="MyActiveX.dll">
    <comClass clsid="{0000000-0000-0000-0000-000000000000}" threadingModel="Both" />
  </file>
</assembly>

The other option as DougN mentioned is to roll your own CoCreateInstance() to create the object. The following C++ (plus ATL) code should do it (going from memory so double check the code):

typedef int (__stdcall *LPDLLGETCLASSOBJECT)(REFCLSID, REFIID, void**);

// LoadInterface() - Load COM Interface from DLL without using registry.
//
// USAGE:   
//   HMODULE hModule = 0;
//   CComPtr<IMyActiveX> pActiveX;
//   if(SUCCEEDED(LoadInterface("C:\\Debug\\MyActiveX.dll", CLSID_MyActiveX, IID_IMyActiveX, (void**)&pActiveX, &hModule)))
//   {
//      // TODO: use pActiveX
// 
//      // caller must call FreeLibrary(hModule) when done
//      pActiveX = 0;
//      FreeLibrary(hModule); 
//   }
//
HRESULT LoadInterface(LPCTSTR pDllPath, REFCLSID rClsid, REFIID riid, LPVOID* ppv, HMODULE *pModule)
{
    if(pModule == 0 || ppv == 0) return E_POINTER;
    HMODULE hModule = LoadLibrary(pDllPath);
    if(hModule == 0) return E_FAIL;

    HREUSLT hr = E_POINTER;
    CComPtr<IClassFactory> classFactory;
    LPDLLGETCLASSOBJECT pGetClassObject = (LPDLLGETCLASSOBJECT)GetProcAddress(hModule, "DllGetClassObject");
    if(pGetClassObject)
    {
        hr = pGetClassObject(rClsid, IID_IClassFactory, (void**)&classFactory);
        if(SUCCEEDED(hr))
        {
            hr = classFactory->CreateInstance(0, riid, (void**)ppv);
            if(SUCCEEDED(hr))
            {
                *pModule = hModule;
                return S_OK;
            }
        }
    }

    // unload library on error
    if(hModule)  
    {
        FreeLibrary(hModule);
    }
    return hr;
 }
Jeff Youel
A: 

I don't think the .bat solution is necessarily horrible. Most simple ActiveX controls are self-registering/unregistering. But it still limits you to running either a debug version or a release version at a time, not both simultaneously.

It is a big problem (it's the essence of "DLL Hell"), and a big part of the reason for the popularity of .NET and Java.

I believe .NET takes advantage of side-by-side sharing, a feature introduced with Windows 2000 and Windows 98 SE. I don't think you need .NET to use it (you didn't say you were doing COM Interop).

There's a somewhat lengthy article on MSDN at http://msdn.microsoft.com/en-us/library/ms811700.aspx, "Implementing Side-by-Side Component Sharing in Applications" which suggests creating a .local file. I'm not completely clear on how that works, but I think that's the right approach.

Alan McBee