Reputation: 640
Using Visual Studio c++ V10, I am trying to figure out how to build a DLL and resolve a DLL naming conflict. Here are the details.
Company S ships a product called M.EXE
. Assume that M.EXE
is installed in \S\BIN\M.EXE
. Company S statically links to a DLL called U.DLL
, which is installed in \S\BIN\U.DLL
. U.DLL
contains open source code, and is built with Visual C++ compiler options /Zc:wchar_t-
, which doesn't recognize wchar as a native type.
Company C ships a DLL called O.DLL
, and publishes the API's for this DLL, and ships an import library for O.DLL
. Assume that O.DLL
is installed in \C\BIN\O.DLL
. O.DLL
statically links to a DLL called U.DLL
, which is installed in \C\BIN\U.DLL
. U.DLL
is built on the same open source code, but is built with Visual C++ compiler options /Zc:wchar_t
, which does recognize wchar_t
as a native type.
Ideally Company C and Company S would agree to build U.DLL
using the same Visual C++ options, but that is not possible.
M.EXE
from Company S is extensible, in that I can build my own DLL in unmanaged C++, call it NODE.DLL
that M.EXE
will invoke if I set everything up correctly. I would like to build NODE.DLL
so that it statically links to O.DLL
from Company C. But the problem is that once M.EXE
is running, it has loaded the U.DLL
library from \S\BIN
, and the symbols from \S\BIN\U.DLL
are slightly different than the ones in \C\BIN\U.DLL
, because of how U.DLL
was built by each company. So when M.EXE
attempts to load NODE.DLL
, it fails, because when NODE.DLL
loads O.DLL
, which needs U.DLL
, the symbols needed from \C\BIN\U.DLL
are not there, because Windows sees U.DLL
as already being loaded.
A diagram of the situation is as follows:
M.EXE static link to -> \S\BIN\U.DLL
M.EXE dynamic link to -> NODE.DLL
NODE.DLL static link to O.DLL
O.DLL static link to \C\BIN\U.DLL
Effectively, I need both \S\BIN\U.DLL
and \C\BIN\U.DLL
to co-exist in the same process space, and have M.EXE
use its version of U.DLL
and O.DLL
use its version of U.DLL
.
Note that I do not have the option to rebuild M.EXE
or O.DLL
to change how they each load U.DLL
. They come from third parties, so the static linking can't be changed. I also don't have the option of using LoadLibrary
on O.DLL
, because it is a C++ library, provided with an import library.
I believe that manifests can be used so that when I build NODE.DLL
that is statically linked to O.DLL, I set things up in the manifest of NODE.DLL
so that O.DLL
loads its own copy of U.DLL
that is installed in \C\BIN\U.DLL
. I just cannot figure out how to do this. Ideally, I'd like to not modify the manifest of O.DLL
, but if that is the only solution, I'll live with that.
Upvotes: 7
Views: 2556
Reputation: 179991
You're lucky that U.DLL is Open Source. You will need to build a version that supports both the /Zc:wchar_t-
and /Zc:wchar_t
functions. The first option merely defines wchar_t-
as unsigned short
. You'll get a ton of linker warnings for duplicate symbols, for each function that doesn't have a wchar_t
argument, but otherwise you just end up with a fatter DLL.
Mind you, if there are any global or static
variables using wchar_t
, then you'll have two copies of those as well. But you'd have the same effect if you shoehorned two copies of U.DLL
in one process.
Upvotes: 0
Reputation: 1628
You can resolve the source DLL programmatically at runtiome by using the /delayload linker option (Linker/Input/Delay Loaded DLLs in VS project properties) along with a custom hook. In one of your source files, you'll need to define and register a delayload hook function. In the hook function's dliNotePreLoadLibrary notification handler, simply call LoadLibrary with an explicit path to the desired DLL, then pass the DLL's HMODULE back to the delayload code. The delayload code will resolve the imported functions to the DLL that you give it regardless whether another DLL of the same name is already loaded into the process.
Off the top of my head, your hook will look something like this (where MyCustomLoadLibrary needs to be replaced with code that calls LoadLibrary with the complete path to the desired DLL in the conflicting case, or just the unqualified filename otherwise):
#include <delayimp.h>
FARPROC WINAPI MyDliNotifyHook( unsigned dliNotify, PDelayLoadInfo pdli )
{
if( dliNotify == dliNotePreLoadLibrary )
return (FARPROC)MyCustomLoadLibrary( pdli->szDll );
return NULL;
}
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook;
Upvotes: 1
Reputation: 48307
You can have multiple DLLs with the same filename in the same process by loading one or more of them with absolute paths. This does require the DLL to be dynamically loaded, but behavior is otherwise identical.
Instead of linking during the build process, you need to std::string moduleName = appPath + "\s\bin\u.dll"; LoadModule(moduleName.c_str())
. Because this is unambiguous as to which DLL needs loaded, it allows you to load multiple ones with the "same" name.
Once you have the module loaded, you can assign each of the necessary functions to function pointers, then either wrap those or use the legal but little-used syntax of calling functions pointers as normal functions (funcPtr(params)
).
If you are on a more recent version of Windows, you may be able to use DLL manifests to strengthen the versioning/naming around the module and cause the EXE to load a different DLL than it typically would. I'm not familiar with how exactly this would be done, although it is documented on MSDN (and probably here as well).
Upvotes: 4
Reputation: 49
Try using LoadLibrary and GetProcAddress. This will require restructuring your code to use function pointers everywhere though. See:
Upvotes: 0