LoadLibrary with Absolute Path returns Incorrect HMODULE with No Error
Solution 1
Most likely the problem is that MyDll.dll
has dependencies on other DLLs that reside in the same folder as MyDll.dll
. When your application lives in a different folder from MyDll.dll
, those dependencies will not be resolved from the folder that contains MyDll.dll
. Instead they are resolved by the system DLL search order.
Your use SetCurrentDirectory
influences the system DLL search order. And it means that the dependencies of MyDll.dll
are resolved from the directory that contains MyDll.dll
.
You can test this hypothesis by using, for example, Dependency Walker in profile mode. That will tell you how the dependencies of MyDll.dll
are resolved at runtime.
You are right to dislike the use of SetCurrentDirectory
. The best solution would be to put all the DLLs in the same directory as the application.
Of course, the other possibility is that the call to UseDLL
has a dependency on the working directory. You can rule that out by changing the working directory back to its original value after the call to LoadLibrary
.
Solution 2
Try setting SetDllDirectory or AddDllDirectory instead of SetCurrentDirectory, and use LoadLibraryEx with flag LOAD_LIBRARY_SEARCH_USER_DIRS instead of LoadLibrary. Useful information can be found on MSDN here.
Update: Example of AddDllDirectory and associated calls on Windows 7 (requires 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;
}
Related videos on Youtube
funseiki
Python wrestler, by day. High-fiber eating, app-developing, video game playing being, by night.
Updated on June 29, 2022Comments
-
funseiki almost 2 years
I have some code which is trying to load a Dll.
I have encountered an odd 'error' with this. When trying to load the dll from an absolute path, I get a Non-Null HMODULE that gives no windows error codes on a GetLastError call (i.e. GetLastError returns '0' or success according to msdn). When calling into a function in this dll, I get incorrect values.
This behavior is peculiar, because if, instead, I switch the current directory to be that of my current dll using SetCurrentDirectory and use a relative path call to LoadLibrary, I get correct values.
Here is a snippet describing the situation:
Using absolute path:
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
Using relative path:
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
I'd really like to avoid having to use SetCurrentDirectory, because the application using this Dll may be multi-threaded and require that the directory stays the same.
Any insight on this issue would be much appreciated. Hopefully, this is just a minor bug on my part.
Update: Using LoadLibraryEx seems to be out of the question, as the LOAD_LIBRARY_SEARCH_* flags don't appear to be available to me (I've already tried installing the KB2533623 update).
-
WhozCraig over 11 yearsLoadLibraryEx with alternate search path is likely your best bet.
-
WhozCraigOnly slightly related, but did you intend to include the DLL name in your SetCurrentDirectory() path call ?
-
-
funseiki over 11 yearsI think you're right, should have realized that. Now I need to figure out how to get myDll.dll's dependencies to load from the new directory - LoadLibraryEx looks promising.
-
funseiki over 11 yearsHmm, I have kernel32.lib referenced, but AddDllDirectory and many of the flags for LoadLibraryEx are missing. Are there other dependencies required to use these?
-
Anthill over 11 yearsWhat's your development environment (for instance Visual Studio) and version?
-
Anthill over 11 yearsTry adding #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0502 #endif to your stdafx.h file. I take it you have included Windows.h?
-
Anthill over 11 yearsHmm it's the Windows version. Use GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddlDllDirectory"); The function looks like DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory( In PCWSTR NewDirectory ); Alternatively, SetDllDirectory should do without the hoops (AddDllDirectory is useful when you have several search paths to add). Does that work?
-
funseiki over 11 yearsI believe AddDllDirectory is only available on Windows 8 according to the msdn
-
Anthill over 11 years
-
David Heffernan over 11 yearsIs SetDllDirectory process wide, or per thread? If the former then its use could lead to problems.
-
Anthill over 11 yearsSetDllDirectory and AddDllDirectory are process-wide as far as I am aware, so yes, it is associated with quite a few potential pitfalls.
-
funseiki over 11 years@Anthill I was able to get it to work - a non-dll file was being loaded from a local directory, so I needed to change that. As far as using AddDllDirectory, GetProcAddress was returning a NULL handle. I believe the error I received was 127 - procedure not found :/.