Consider the following file organization on Windows:
[app folder]
app.exe
[folder 'sub']
com_server.dll
regular.dll
helper.dll
Also assume the following:
Both com_server.dll and regular.dll are statically linked to a function in helper.dll, so that helper.dll is loaded when they are.
app.exe has no static dependencies.
The com_server.dll COM objects are registered with Windows
folder 'sub' is not in the system Path.
Consider the following cases:
app.exe calls LoadLibrary( "sub/regular.dll" ). This will fail because Windows will be unable to find helper.dll, consistent with the documented DLL search procedure.
app.exe calls CoCreateInstance to create an object implemented in com_server.dll. This succeeds and helper.dll is loaded.
The main questions: Why does case 2 work? What are the details of the dependent DLL search procedure for the COM server case?
It would appear that when creating a com object with CoCreateInstance, the implementing dll's folder is somehow added to the search path for dependencies. Is this what is happening, and is this guaranteed? I cannot find any documentation anywhere that discusses this case.
Let's look at the documentation for LoadLibrary on MSDN:
If the string specifies a full path, the function searches only that path for the module.
If the string specifies a relative path or a module name without a path, the function uses a standard search strategy to find the module; for more information, see the Remarks.
Ok, so that explains the behavior of #1 above. If you had said:
LoadLibrary("C:\\program files\\AppFolder\\Sub\\com_server.dll")
Then that would have found your dependent DLLs, and LoadLibrary would have succeeded.
As for how COM succeeds with #2, that really depends on how com_server.dll is registered in the registry for the InProcServer32 key. If it's a full path to the file, then LoadLibrary would just work as described above. If it's a relative path, then I would suspect COM could be doing any number of things to make finding DLLs like yours work.
One likely possibility is that CoCreateInstance is calling LoadLibraryEx with the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag set. It may even call LoadLibrary(Ex) multiple times with different combination of flags.
Also, given that CoCreateInstance is a system API, it's entirely possible it has a private internal version of LoadLibrary that allows for alternate search paths.
Related
Often one wants to LoadLibrary a system DLL like Kernel32.dll, handily LoadLibraryEx has a dwFlags parameter that allows you to specify LOAD_LIBRARY_SEARCH_SYSTEM32.
For security reasons, this can be very important as malicious attackers can subvert the default search paths that LoadLibrary looks through.
However Windows XP, which I must still support, cannot use LOAD_LIBRARY_SEARCH_SYSTEM32 as it didn't exist eons ago. This leads me to the following conclusion: I need to come up with a fully qualified path and pass that to LoadLibrary.
However, a robust implementation of this is tricky due to WoW64 and file-system redirection.
I have to worry about this possibility because the code in question lives in a library and can be called in strange environments.
My current thoughts are something like the following pseudo-code:
string Path;
BOOL Wow64Process;
if (IsWow64Process(CurrentProcess(), &Wow64Process) && Wow64Process &&
WoW64FSRedirectionIsDisabled)
Path = GetSystemWow64Directory();
else
Path = GetSystemDirectory();
Path += "\Kernel32.dll";
LoadLibrary(Path);
I have considered, and rejected using Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection but this is problematic as it will leave FS redirection disabled in the library's DLLMain.
Given the above, what's the best way to go about what I am trying to do?
Thanks!
In terms of loading a DLL without dependencies, you are over thinking this. If the user has disabled file system redirection in a WOW64 process then LoadLibraryEx will attempt to load the DLLs from the 64 bit system32 folder. So you can simply do exactly the same and remove all that WOW64 code.
However, the documentation says (emphasis mine):
If this value is used, %windows%\system32 is searched for the DLL and its dependencies.
So, your approach cannot replicate LOAD_LIBRARY_SEARCH_SYSTEM32 because you can only supply the full path for the DLL you load, but not for its dependencies.
The only way to hope to replicate this is to force system32 to be at the head of the DLL search path. Specifying a full path won't help you.
Finally, are you sure that LOAD_LIBRARY_SEARCH_SYSTEM32 is not available on XP64?
As an alternative to the other answers use SetDlldirectory.
The advantage ist that the current Directory isn't checked for a DLL-load.
Still open is the search via PATH... but this is in the last Position, so your DLL located in the SYSTEM32 directoryies should be loaded first using SettDllDirectory.
Also it is supported since XP SP1
My code is using a library which is a static/implicitly linked DLL (let's call it DLLB) but on runtime it can't find it.
This is despite locating DLLB in the same directory as the code that calls it. (The calling code is itself a DLL, DLLA which is called from python, which is called from arcpy. I'm not quite sure why the python finds DLLA fine but DLLA doesn't find DLLB, despite them being in the same directory).
If I put the library DLL somewhere on the system path, everything works just fine.
But what's the best approach for deployment? Add an entry to the system path on the client machine, at install time? Modify the system path at runtime, from python, before loading the DLL? Something else?
Python must be specifying the full path to the DLL in the LoadLibrary call. This is recommended practice. If you specify only a module name, there is a risk of loading the wrong DLL, possibly introducing a binary planting vulnerability.
Note that although the default search path includes the directory the executable was loaded from, it does not include the directory other DLLs were loaded from. So the behaviour you're seeing is as expected.
If you can use dynamic loading, you can look up the path to DLLA and use it to construct the path to DLLB.
To get a module handle for DLLA, call GetModuleHandleEx. To get the full path to DLLA from the module handle, call GetModuleFileName. Check that the last element is DLLA.dll and replace it with DLLB.dll. You can then call LoadLibrary.
I want to make a dll with an exposed C function accessible to applications on the system.
Is there a better way to make it available than modifying %PATH%?
Because people don't like adding it to %PATH% here.
You have three options if you want to allow implicit linking to the dll :-
Create a native Win32 assembly that contains the dll and install it to WinSxS. This requires creating a simple .manifest file, the use of some crypto tools to sign the assembly (being the manifest file and the dll), and creating an MSI installer - or call IAssemblyCache directly to perform the actual install.
Install the dll to System32 - with this option you need to ensure the dll has a relativly unique name.
Ad the path to the dll to the someplace on the PATH (or modify path to point to the dll).
Other options if implicit linking to the C Function isn't critical:-
Create an COM interface that exposes the c-method. Register the path to the dll in the registry and users of the dll use CoCreateInstance to get the interface containing the function.
Store the path to the dll in the registry, and expect users of the dll to use that path with LoadLibrary, and GetProcAddress to load the dll.
Put it somewhere in your PATH. (C:\Windows\System32\ comes to mind). If it's only needed by one application, just stick it in the same directory.
If you call the DLL using an import library, then it looks in the current directory, and then in the PATH.
But, you don't need to call it that way. You can use LoadLibrary() and GetProcAddress() yourself and then do whatever you want. If you call LoadLibrary with just the dll name, it uses the same algorithm as with the import library (current dir + PATH) -- if you pass a full path, it will use it.
COM uses this technique to load a DLL based on a full path to the DLL which is in the registry -- you could do this too without COM.
You could search for it in some other way besides the PATH -- you could call with no path, see if it finds it, and then try the registry, and then look elsewhere (every drive's program files directory, etc).
Basically, if you call LoadLibrary and GetProcAddress yourself, you can do whatever you want.
I guess that it would be best to install it into system32 folder and forget about %PATH% modification...
I have a question about getting DLL's directory on Windows system.
The situation is like this :
I have a DLL and an EXE file. The exe file must load the DLL to run.
These 2 modules are in different directories.
Moreover, the directory of the DLL is changeable.
Now I have to get the directory of the DLL in "run time".
How could I do this?
Thanks in advance.
Do you need to find where the DLL is to load it or find the the path where it was loaded from?
The DLL path search algorithm is documented on MSDN and you can use the SearchPath function to search the system path.
If you need to find the path where a DLL was loaded, after it was loaded, use the GetModuleFileName function. That takes the module handle that is returned by LoadLibrary, GetModuleHandle, or passed in as hinstDLL to DllMain and returns the full path to the DLL.
I guess you need to implement some custom search algorithm. Only your exe knows which one DLL is needed and where it can be. So find the path and use it with LoadLibrary().
BTW, if possible, I would consider using COM. In this way you will use DLL stuff by some CLSID, which is completely independent from file path.
I am not able to get much information about dynamic loading of DLL files from C++ .
I know it does use some functions like LoadLibrary and FreeLibrary with GetProcAddress . But how it works actually internally in the OS perspective like where it actually looks for the DLL file and where it loads like Memory ? can someone help me on that with some diagrams ?
DLL search order is described on the MSDN, and there's an article on DLL loading, and two-part article describing PE format (part two here) (they're slightly old, but I don't think they're outdated). Look through MSDN Magazine and MSJ archives and you'll probably find more.
There's two ways to use a DLL. You can load it dynamically at run-time or statically link against it at link-time.
If you load dynamically it using LoadLibrary, the OS has some mechanism to determine where to look for DLLs. It then attempts to load them. Then you can try to get function pointers to the functions you name (by string or ordinary) and call these functions.
If you link statically, basically the linker adds a reference to the DLL and some jump table with an entry for each of the DLL's functions. When the OS loads your application, it finds references to those DLLs, attempts to load these, and patches the loaded DLL's function's addresses into the jump table. Only then is your application considered loaded and will start.
Note that in reality this is a bit more complicated. For example, DLLs can in turn reference other DLLs. So when the loader loads a DLL, before the DLL can be considered loaded, it will need to (possibly recursively) load other DLLs as well.
For Win32, loader details are on MSDN. See here.
From your C++ code, you're right (for Windows), you load with ::LoadLibrary and resolve function pointers with ::GetProcAddress. Typically you'll cast the result of GetProcAddress into the type that you know the entry point function to be, and then use it in your program.
For example, if you have a plug-in architecture like a browser, you'd decide what your plug-in directory is, get the filename list for that directory, and call ::LoadLibrary for each DLL (filtering filenames would be up to you). For each, you'd resolve the required entry points with GetProcAddress, store them in a structure for that library, and put them in some plug-in list. Later, you'd call through those function pointers to let the plug-in do its work.
If you specify a relative path (e.g. "foo.dll" rather than "c:\foo.dll"), the OS library search path kicks in. Details at MSDN.
Also, DLLs get loaded into your process's address space. Typically you don't care about where, but in the past, you could get faster load times by "rebasing" your DLLs. I don't think there are any guarantees about how the OS loader places libraries in memory, but you can always get the base address in your process's address space.
Your DLL's entry point (dllmain) can also respond to various messages -- thread attach, process attach -- to do initialization in a sensible way.