You are not asking for something very basic. Windows just does not support what you want.
You have several options for solving this problem:
- Create two DLLs. Your DLL version of the plugin, statically linked to any other DLL files that you need. And a simple "facade" dll, loaded by the hosting application. The torch dll receives a call to SetDllDirectory and then to LoadLibrary to load the DLL implementation with the desired search path, and then for each exported plug-in function, it implements a stub function that uses GetProcAddress to simply pass the call directly to your DLL implementation.
If the plugin interface is complex, but the dll interface you are using is missing, then:
Give up and just use LoadLibrary (with an explicit path) and GetProcAddress to access the functions in your satellite dll (s). Pain.
The last option is the least documented and the most poorly understood by Windows programmers. We mainly use the version of Windows for technology built to support .NET: assembly builds. Do not be alarmed. A "collaborative build" is just a plain old dll, but with an accompanying manifest file that provides more information about this.
The reason we want to do this is because the search order for dlls that are connected via SxS technology is different from the usual dll search order: - Namely, after searching c: \ windows \ WinSxS, the windows will look the same as the DLL that refers to the DLL, not to the EXE folder.
Start by taking an inventory of all the satellite DLLs you need to connect to and create an assembly from them. This means: create a .manifest file with a bunch of files = nodes. You must give the assembly a name. Let's call it "MyAssembly".
Create the file "MyAssembly.manifest" in your dll folder with contents similar to the following: (listing each of the libraries you need to include)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="MyAssembly" processorArchitecture="*" type="win32" version="1.0.0.1"/> <file name="firstrequireddll.dll"/> <file name="2ndrequireddll.dll"/> </assembly>
Now, this is your assembly manifest. We are half done.
The next half is to force your DLL to use the assembly, and for this you need to add the manifest resource to your Dll file. This manifest should ultimately contain the following content: -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="MyAssembly" version="1.0.0.1" processorArchitecture="*"/> </dependentAssembly> </dependency> </assembly>
Obviously, the application manifest (which is a confusing name when embedding in dll) is also allowed to use the <file> node, so itβs possible to skip creating an assembly and just go with
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <file name="firstrequireddll.dll"/> <file name="2ndrequireddll.dll"/> </assembly>
like a manifest dll. I have not played with this iteration yet, so I'm not sure how this will change the usual dll search path (if at all).
Without knowing your development environment, it's hard to know how to tell you how to add a manifest to the dll. If you edit the .rc file and enter the manifest manually, be aware that Dlls uses resource identifier 2 rather than 1, which it usually uses in exe examples.
If you are using DevStudio 2005 or later, there is a convenient #pragma directive that will make everything magically correct and be in the right places.
If the project settings are set by default, VS2005 and higher will be automatically generated and embed the manifest, if necessary. this #pragma will add additional build dependencies to the generated manifest: -
#if _MSC_VER >= 1400 // VS2005 added this directive #pragma comment(linker, \ "\"/manifestdependency:type='Win32' "\ "name='Company.Product.Subsystem' "\ "version='6.0.0.0' "\ "processorArchitecture='*' "\ "language='*'\"") #endif