Как вы инициализируете незарегистрированную COM DLL?
Недавно некоторые наши клиенты потеряли свои файлы XAudio2_7.dll из своего каталога C:/Windows/System32, и теперь они не могут слышать звук. Переустановки DirectX или регистрации DLL обычно достаточно для решения этой проблемы, но мы ищем решение, которое не требует прав администратора. Это для Windows 7. Приложения написаны на CPP, и некоторые из них являются 32-разрядными, а остальные - 64-разрядными.
Локальная копия XAudio2_7.dll находится в том же каталоге exe, но она не загружается, если эта dll не зарегистрирована, поскольку это COM dll. Регистрация для текущего пользователя (с использованием "Regsvr32.exe /n /i:user XAudio2_7.dll") не работает, так как DLL не реализует требуемый интерфейс "DllInstall".
Один из подходов, которые я попробовал, состоит в том, чтобы статически связать.lib XAudio вместо использования динамической ссылки. Microsoft не распространяет XAudio2_7.lib с DirectX SDK. "Никакие версии DirectX SDK не содержат библиотеку импорта xaudio2.lib. Версии DirectX SDK используют COM для создания нового объекта XAudio2". msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.xaudio2.xaudio2create%28v=vs.85%29.aspx
Конечно, это говорит о том, что может быть невозможно использовать статическую библиотеку XAudio, даже если я ее создал, поскольку она звучит так, как будто она зависит от внешних объектов, определенных в других библиотеках. Это все еще стоило проверить на случай, если моя гипотеза неверна.
Выполните шаги, указанные в этой ссылке: adrianhenke.wordpress.com/2008/12/05/create-lib-file-from-dll/
Я не очень далеко продвинулся с этим методом. За исключением статей, которые были датированы, с этим была пара проблем. Ссылка MS в блоге упоминает, что это для 32-битных библиотек. Даже для 32-битных библиотек dumpbin не работал, поскольку он экспортировал только функции интерфейса. Дамп файла C:\XAudioTest\32Bit\XAudio2_7.dll
File Type: DLL
Section contains the following exports for xaudio2.dll
00000000 characteristics
4C064181 time date stamp Wed Jun 02 07:33:21 2010
0.00 version
1 ordinal base
4 number of functions
4 number of names
ordinal hint RVA name
1 0 00030AA0 DllCanUnloadNow
2 1 00031150 DllGetClassObject
3 2 00031470 DllRegisterServer
4 3 000314D0 DllUnregisterServer
Summary
C000 .data
1000 .no_bbt
4000 .reloc
1000 .rsrc
7B000 .text
Позже я нашел эту цитату из другой статьи MSDN. "Стандарт COM требует, чтобы библиотеки DLL DLL экспортировали DllCanUnloadNow, DllGetClassObject, DllRegisterServer и DllUnregisterServer. Обычно они больше ничего не экспортируют. Это означает, что вы не можете получить информацию об объекте или методе COM с помощью dumpbin.exe". msdn.microsoft.com/en-us/library/aa446532.aspx
Я также пытался использовать стороннюю программу, которая утверждает, что она способна создать.lib из COM DLL. www.binary-soft.com/dll2lib/dll2lib.htm
Хотя это сгенерировало 32-битный файл.lib, компиляция с файлом lib генерировала неразрешенные внешние символы. Эта утилита поставляется с методами для обработки неразрешенных символов, но ввод чего-либо в Symbol Finder или Advanced Conversion Options может привести к сбою. Просматривая последние заметки о выпуске (3.00), я обнаружил, что они добавили поддержку Vista и не упоминают о Windows 7. Также это не работает для 64-битных DLL.
Я попробовал другой подход, чтобы изменить последовательность инициализации для использования незарегистрированной COM DLL, описанной в этой ссылке: Использовать COM-объект из DLL без регистрации Код инициализации выглядит примерно так:
HMODULE audioLib = LoadLibrary(TEXT("XAudio2_7.dll"));
if (audioLib == NULL)
{
debugf(TEXT("Failed to create COM object. Unable to load XAudio2_7.dll library. GetLastError: %d"), GetLastError());
return;
}
typedef HRESULT (WINAPI* Function_DllGCO) (REFCLSID, REFIID, LPVOID*);
Function_DllGCO processAddress = (Function_DllGCO)GetProcAddress(audioLib, "DllGetClassObject");
if (processAddress == NULL)
{
debugf(TEXT("COM DLL failed to find the process address to interface function 'DllgetClassObject' within the XAudio2_7.dll. GetLastError: %d"), GetLastError());
return;
}
class __declspec(uuid("{5a508685-a254-4fba-9b82-9a24b00306af}")) xAudioGUID;
REFCLSID classID = __uuidof(xAudioGUID);
class __declspec(uuid("{00000001-0000-0000-c000-000000000046}")) classFactoryGUID;
REFIID classFactoryID = __uuidof(classFactoryGUID);
IClassFactory* ClassFactory = NULL;
if (processAddress(classID, classFactoryID, reinterpret_cast<LPVOID*>(&ClassFactory)) != S_OK)
{
debugf(TEXT("Failed to execute function pointer to DLLGetClassObject. GetLastError: %d"), GetLastError());
return;
}
class __declspec(uuid("{00000000-0000-0000-C000-000000000046}")) unknownGUID;
REFIID unknownID = __uuidof(unknownGUID);
if (ClassFactory->CreateInstance(NULL, unknownID, reinterpret_cast<void**>(&ClassFactory)) != S_OK)
{
debugf(TEXT("Class factory for XAudio2_7 failed to create an object instance. GetLastError: %d"), GetLastError());
ClassFactory->Release();
return;
}
if( XAudio2Create( &XAudio2, 0, AUDIO_THREAD) != S_OK ) //Fails here with error number: 1008 (An attempt was made to reference a token that does not exist.)
{
debugf( NAME_Init, TEXT( "Failed to create XAudio2 interface: GetLastError: %d" ), GetLastError());
return;
}
//Do other things
Все вызовы функций WinAPI прошли, кроме функции XAudio2Create. Я не уверен, почему XAudio2Create не использует объект, созданный на фабрике, и я не знаю, что мне нужно сделать, чтобы заставить его использовать этот объект. Я все еще исследую, что я могу сделать здесь, но трудно отлаживать библиотеки с закрытым исходным кодом.
До того, как я узнал о COM DLL, я пытался использовать метод перенаправления DLL, чтобы заставить приложение использовать определенную DLL. Используя описанный здесь процесс: перенаправление DLL с использованием манифестов XAudio2Create все еще не удалось. У меня нет сильной стратегии в определении того, что не так с манифестом. Я также не нашел много современной документации относительно манифестов для перенаправления DLL. Судя по всему, это в основном используется для загрузки определенной версии DLL. Я не думаю, что перенаправление DLL- это метод, который мне нужен, так как локальная копия XAudio2_7 уже есть в том же каталоге exe, что означает, что она должна иметь приоритет над XAudio2_7 в системном каталоге в соответствии с: msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx
Примечание. Я удалил гиперссылки для некоторых адресов, поскольку у меня недостаточно очков репутации, чтобы опубликовать более 2 ссылок.