tags:

views:

383

answers:

2

Hi,

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.)

+3  A: 

I think you should try Registration free COM. See: http://msdn.microsoft.com/en-us/library/ms973913.aspx

[edit] In addition, I found back a link to a discussion where it is claimed that just LoadLibrary will do. Can't confirm that it works from my own experience however. See: http://www.eggheadcafe.com/forumarchives/win32programmerole/Dec2005/post25120399.asp

jdv
+1, really interesting article.
Matteo Italia
Registration free COM really seems too complicated for us. Also because we want to avoid these manifests (we only had problems with them).But the discussion is really interesting. It seems that I could call CoRegisterClassObject(CLSCTX_INPROC_SERVER) somehow and it would work without having it registered. Can you maybe say how the command would look like? (I added some information in the initial question.)
Albert
Don't avoid "the manifests". Learn how they work and can help you. The can be, and are, extremely helpful.
Chris Becke
Well, this is a cross platform application and we are planning to get away from any MS dependencies as far as possible. We have many troubles esp with MSVC in our cross build environment on Linux. The plan is to get rid of MSVC after all and move to mingw as the main build system for Windows. We would like a solution which works pretty much on all systems and takes the less work to maintain as possible (i.e. the less extra work for some specific system). Windows right now is already by far on the top in required work to maintain. And I am not sure if we would have less work with Manifests.
Albert
+3  A: 

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.

richb
Thanks a lot for this hint! I added some code snippet in my initial question where I use this lib. How would it look like?
Albert
I added sample code for you.
richb
Thanks a lot! Sorry if I don't put the "accepted" mark right now as I don't have time to test this until next week.
Albert
I deliver msdia100.dll together with my EXE (so it is in the same directory). LoadLibrary should find it there if I don't specify a path, shouldn't it?
Albert
msdia is a lib from MS to read debugging information (from pdb or exe) and to get debugging information for some mini coredump. Google Breakpad uses it.
Albert