Windows / C ++: как использовать COM dll, который не зарегистрирован - PullRequest
5 голосов
/ 18 марта 2010

В нашем приложении нам нужно использовать COM dll (а именно msdia100.dll), который ранее не был зарегистрирован в системе.

Ранее, мы только что вызвали DLL, вызвав ее DllRegisterServer через этот код:

// 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);

Это больше не работает в Windows 7 (возможно, также Vista, не пробовал), потому что для вызова этой функции нужны привилегии администратора.

Все решения этой проблемы я нашел где получить права администратора. Это невозможное решение для нас, потому что наше приложение также должно работать, если пользователь не может получить эти права администратора.

Мы также не можем решить, что вдруг понадобится установщик для нашего приложения, который регистрирует эту DLL.

Итак, какие есть возможности? Как я могу использовать эту DLL без прав администратора? Нужно ли перекодировать COM, который работает без необходимости сначала регистрировать DLL?


Код, в котором я использую эту библиотеку, выглядит следующим образом:

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

(Кстати, для тех, кому интересно: это часть Google Breakpad.)

Ответы [ 2 ]

8 голосов
/ 18 марта 2010

Простой подход заключается в использовании LoadLibrary ("msdia100.dll") для прямой загрузки DLL. Затем используйте GetProcAddress ("DllGetClassObject"). Затем вы можете использовать IClassFactory, чтобы сделать эквивалент CoCreateInstance.

Так что-то вроде следующего. (Отказ от ответственности: я не скомпилировал это ...)

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;
}

Примечания:

  1. В вызове LoadLibrary вам может потребоваться указать путь. Я не знаю, где обычно живет MSDIA100.DLL.

  2. Я не знаю, что делает MSDIA100.DLL. Не все библиотеки COM DLL будут работать с этим методом, особенно если они полагаются на сортировку без использования COM и такие ужасные вещи. Тем не менее, большинство COM-библиотек имеют простую многопоточность и, по моему опыту, работают нормально.

5 голосов
/ 18 марта 2010

Я думаю, вам стоит попробовать регистрацию свободного COM. Смотри: http://msdn.microsoft.com/en-us/library/ms973913.aspx

[править] Кроме того, я нашел ссылку на обсуждение, где утверждается, что подойдет LoadLibrary Однако я не могу подтвердить, что это работает из моего собственного опыта. Смотри: http://www.eggheadcafe.com/forumarchives/win32programmerole/Dec2005/post25120399.asp

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...