DLL file loaded twice with DLL redirection through manifest

c++, dll, manifest, python, visual-studio

Solution

After exhaustive battle with WinSxS and DLL redirection, here's my advice for you:

Some background

Various things can cause a DLL file to be loaded under Windows:

- Explicit linking (`LoadLibrary`) -- the loader uses the current activation context of the running EXE file. This is intuitive.

- Implicit linking ("load time linkage", the "auto" ones) -- the loader uses the default activation context of the depending DLL file. If `A.exe` depends on `B.dll` depends on `C.dll` (all implicit linkage), the loader will use `B.dll`'s activation context when loading `C.dll`. IIRC, it means if B's `DllMain` loads `C.dll`, it can be using `B.dll`'s activation context -- most of the time it means the system-wide default activation context. So you get your Python DLL from `%SystemRoot%`.

- COM (`CoCreateInstance`) -- this is the nasty one. Extremely subtle. It turns out the loader can look up the full path of a DLL file from the registry using COM (under `HKCR\CLSID`). `LoadLibrary` will not do any searching if the user gives it a full path, so the activation context can't affect the DLL file resolution. Those can be redirected with the `comClass` element and friends, see [reference][msdn_assembly_ref].

- Even though you have the correct manifest, sometimes someone can still change the activation context at run time using the Activation Context API. If this is the case, there is usually not much you can do about it (see the ultimate solution below); this is just here for completeness. If you want to find out who is messing with the activation context, WinDbg `bp kernel32!ActivateActCtx`.

Now on to finding the culprit

- The easiest way to find out what causes a DLL file to load is to use Process Monitor. You can watch for "Path containing `python25.dll`" or "Detail containing `python25.dll`" (for COM lookups). Double clicking an entry will actually show you a stack trace (you need to set the symbol search paths first, and also set Microsoft's PDB server). This should be enough for most of your needs.

- Sometimes the stack trace obtained from above could be spawned from a new thread. For this purpose you need WinDbg. That can be another topic, but suffice to say you can `sxe ld python25` and look at what other threads are doing (`!findstack MyExeModuleName` or `~*k`) that causes a DLL file to load.

Real world solution

Instead of fiddling with this WinSxS thing, try hooking `LoadLibraryW` using Mhook or EasyHook. You can just totally replace that call with your custom logic. You can finish this before lunch and find the meaning of life again.

[msdn_assembly_ref]: Assembly Manifests

Problem

I'm including `python.h` in my Visual C++ DLL file project which causes an implicit linking with `python25.dll`. However, I want to load a specific `python25.dll` (several can be present on the computer), so I created a very simple manifest file named test.manifest: ``` <?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <file name="python25.dll" /> </assembly> ``` And I'm merging it with the automatically embedded manifest file generated by Visual Studio thanks to: ``` Configuration Properties -> Manifest Tool -> Input and Output -> Additional Manifest Files -->$(ProjectDir)\src\test.manifest ``` `python25.dll` is now loaded twice: the one requested by the manifest, and the one that Windows should find through its search order. Screendump of Process Explorer http://dl.dropbox.com/u/3545118/python25_dll.png Why is that happening and how can I just load the DLL file pointed by the manifest?

Original source