Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows/C++: how to use a COM dll which is not registered

Tags:

c++

windows

dll

In our application, we need to use a COM dll (namely msdia100.dll) which was not registered in the system before.

Earler, we have just called the DLL by calling its DllRegisterServer via this code:

// Register DIA DLL required by Breakpad
std::string diaLibPath = "msdia100";    
HMODULE diaLib = LoadLibrary(diaLibPath.c_str());
if( diaLib == NULL )
{
    errors << "Cannot load DLL " << diaLibPath << endl;
    return;
}

typedef HRESULT ( __stdcall * regServer_t )(void);

regServer_t regServer = (regServer_t)GetProcAddress(diaLib, "DllRegisterServer");
if( regServer == NULL )
{
    errors << "Cannot get method DllRegisterServer from " << diaLibPath << endl;
    FreeLibrary(diaLib);
    return;
}
if( regServer() != S_OK )
{
    errors << "Cannot call DllRegisterServer from " << diaLibPath << endl;
}
FreeLibrary(diaLib);

This doesn't work anymore on Windows 7 (maybe also Vista, didn't tried) because to call this function, it needs Administrator privileges.

All solutions to this problem I have found where about getting those Admin rights. That is no possible solution for us because our application must also work if the user is not able to get those Admin rights.

It is also no solution for us to suddenly need an installer for our application which registeres this DLL.

So, what possibilities are there? How can I use this DLL without Admin rights? Do I have to recode COM which works without the need to register a DLL first?


The code where I uses this lib looks like this:

CComPtr<IDiaDataSource> data_source;
if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) {
  fprintf(stderr, "CoCreateInstance CLSID_DiaSource failed "
          "(msdia80.dll unregistered?)\n");
  return false;
}

(Btw., for those who are interested: That is part of Google Breakpad.)

like image 768
Albert Avatar asked Mar 17 '10 21:03

Albert


1 Answers

A simple approach is to use LoadLibrary("msdia100.dll") to load the DLL directly. Then use GetProcAddress("DllGetClassObject"). You can then use IClassFactory to do the equivalent of CoCreateInstance.

So something like the following. (Disclaimer: I haven't compiled this...)

HRESULT CoCreateDiaDataSource(CComPtr<IDiaDataSource>& data_source)
{
    HMODULE hmodule = LoadLibrary("MSDIA100");
    if (!hmodule)
        return HRESULT_FROM_WIN32(GetLastError()); // library not found

    BOOL (WINAPI*DllGetClassObject)(REFCLSID,REFIID,LPVOID*) =
        (BOOL(WINAPI*)(REFCLSID,REFIID,LPVOID*))GetProcAddress(hmodule, "DllGetClassObject");

    if (!DllGetClassObject) 
        return HRESULT_FROM_WIN32(GetLastError());

    CComPtr<IClassFactory> pClassFactory;
    HRESULT hr = DllGetClassObject(CLSID_DiaSource, IID_IClassFactory, &pClassFactory);
    if (FAILED(hr))
        return hr;

    hr = pClassFactory->CreateInstance(NULL, IID_IDiaDataSource, (void**)&data_source);
    if (FAILED(hr))
        return hr;

    return S_OK;
}

Notes:

  1. In the LoadLibrary call, you may have to supply a path. I don't know where MSDIA100.DLL normally lives.

  2. I don't know what MSDIA100.DLL does. Not all COM DLLs will work with this method, particularly if they rely on COM free threaded marshalling and horrible stuff like that. However, most COM DLLs are simple apartment threaded and work fine in my experience.

like image 125
richb Avatar answered Oct 01 '22 09:10

richb