LoadLibrary returns the module was first loaded

If there are multiple foo.dll loaded (from different paths), LoadLibrary(“foo.dll”) will return the first foo.dll was loaded.

This is documented in MSDN:

https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp

“If lpFileName does not include a path and there is more than one loaded module with the same base name and extension, the function returns a handle to the module that was loaded first.”

I was helping a developer to diagnose a misterious LoadLibrary failure in Windows Vista. The application works fine in Windows XP and early builds of Windows Vista. Starting from a certain build, the application will fail to load a particular dll.

After some debugging, turns out this is because the application carries a dll named shdocvw.dll in its own directory. The dll is an .Net framework assembly generated by AxImp.exe(a .Net framework SDK tool)  operated on shdocvw.dll in system32. For some reason, AxImp decides to keep the output file the same name as the original file, and the application carries the generated copy in its own directory.

On the Windows Vista build that the application fails to load the dll, its own copy of shdocvw.dll is loaded first, and later the “real” one in system32 is loaded. The failure dll happens to depend on shdocvw.dll. When resolving its dependencies, the first loaded shdocvw.dll (the one in app directory in our case) is used. Since it is a .Net framework assembly, loader can’t find its import address table and fails the load.

When running on Windows XP, the failure dll is not required. On early builds of Windows Vista, the system32 copy of shdocvw.dll is loaded first. Presumeably there is an optimization in the OS removed the loading of shdocvw.dll in system32. Unfortunately the seemly innocent optimization breaks the application.

Fortunately the application is developed in house so we are able to correct it, by having AxImp generate a different name for the output assembly.

Takeaway from this story:

It is highly fragile depending on the dll load order. Avoid it if possible.

Collorary:

Don't collide the name of your dlls with the ones in system32.