У меня есть код, который пытается загрузить Dll.
Я столкнулся со странной «ошибкой» с этим. При попытке загрузить dll по абсолютному пути, я получаю ненулевой HMODULE, который не дает никаких оконных кодов ошибок при вызове GetLastError (т.е. GetLastError возвращает ‘0’ или успех в соответствии с MSDN). При вызове функции в этой DLL я получаю неправильные значения.
Это странное поведение, потому что, если вместо этого я переключаю текущий каталог на каталог моей текущей библиотеки DLL с помощью SetCurrentDirectory и использую относительный путь к LoadLibrary, я получаю правильные значения.
Вот фрагмент, описывающий ситуацию:
Используя абсолютный путь:
std::string libLoc = get_dll_location(); // Get the directory of this dll
HMODULE myDLL = LoadLibraryA(libLoc.c_str()); // Non-null value
DWORD lastError = GetLastError(); // returns 0
MyObj * value = UseDLL(myDLL); // bad value
Используя относительный путь:
SetCurrentDirectory("c:\\path\\containing\\dll\\"); // hard coded path to dll's folder
HMODULE myDLL = LoadLibrary("myDll.dll"); // Non-null value
MyObj * value = UseDLL(myDLL); // Good value
Я действительно хотел бы избежать необходимости использовать SetCurrentDirectory, потому что приложение, использующее этот Dll, может быть многопоточным и требовать, чтобы каталог оставался прежним.
Любое понимание этого вопроса будет высоко ценится. Надеюсь, это просто небольшая ошибка с моей стороны.
Обновить: С помощью LoadLibraryEx кажется, не может быть и речи, так как флаги LOAD_LIBRARY_SEARCH_ * не доступны для меня (я уже пытался установить Обновление KB2533623).
Скорее всего проблема в том, что MyDll.dll
имеет зависимости от других библиотек DLL, которые находятся в той же папке, что и MyDll.dll
, Когда ваше приложение находится в другой папке, MyDll.dll
эти зависимости не будут разрешены из папки, содержащей MyDll.dll
, Вместо этого они разрешаются системой Порядок поиска DLL.
Ваше использование SetCurrentDirectory
влияет на системный порядок поиска DLL. А это значит, что зависимости MyDll.dll
разрешены из каталога, который содержит MyDll.dll
,
Вы можете проверить эту гипотезу, используя, например, Dependency Walker в режиме профиля. Это скажет вам, как зависимости MyDll.dll
разрешаются во время выполнения.
Вы вправе не любить использование SetCurrentDirectory
, Лучшее решение — поместить все библиотеки DLL в один каталог с приложением.
Конечно, другая возможность состоит в том, что призыв к UseDLL
имеет зависимость от рабочего каталога. Вы можете исключить это, изменив рабочий каталог на его первоначальное значение после вызова LoadLibrary
,
Попробуйте установить SetDllDirectory или AddDllDirectory вместо SetCurrentDirectory и использовать LoadLibraryEx с флагом LOAD_LIBRARY_SEARCH_USER_DIRS вместо LoadLibrary. Полезную информацию можно найти на MSDN Вот.
Обновление: пример AddDllDirectory и связанных вызовов в Windows 7 (требуется KB2533623)
#include "stdafx.h"#include <iostream>
#include <Windows.h>
typedef DLL_DIRECTORY_COOKIE (WINAPI *ADD_DLL_PROC)(PCWSTR);
typedef BOOL (WINAPI *REMOVE_DLL_PROC)(DLL_DIRECTORY_COOKIE);
#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS
#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400
#endif
int main()
{
ADD_DLL_PROC lpfnAdllDllDirectory = (ADD_DLL_PROC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory");
REMOVE_DLL_PROC lpfnRemoveDllDirectory = (REMOVE_DLL_PROC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "RemoveDllDirectory");
if(lpfnAdllDllDirectory && lpfnRemoveDllDirectory)
{
DLL_DIRECTORY_COOKIE cookie = ((ADD_DLL_PROC)lpfnAdllDllDirectory)(L"c:\\windows\\system32\\");
std::cout << cookie << std::endl;
HMODULE module = LoadLibraryEx(L"cabview.dll", NULL, LOAD_LIBRARY_SEARCH_USER_DIRS);
if(module)
{
std::cout << "Locked and loaded" << std::endl;
FreeLibrary(module);
}
if(cookie && ((REMOVE_DLL_PROC)(cookie)))
{
std::cout << "Added and removed cookie" << std::endl;
}}
std::cin.get();
return 0;
}