3

I'm writing a Windows application plug-in (as a DLL) in native C++. Let's call it myplugin.dll. My plug-in references another DLL which we'll call other.dll.

My plug-in is installed in the myplugin subdirectory of the application's plugins directory:

application.exe
plugins\
    myplugin\
        myplugin.dll

myplugin.dll links implicitly to other.dll. I cannot delay-load other.dll because it exposes classes with virtual methods, and virtual method tables being considered as data, they cannot be imported from delay-loaded DLLs.

I would naturally like to place other.dll in the plugins\myplugin directory, next to myplugin.dll, but by default Windows will not look in plugins\myplugin when searching for other.dll (source).

What are my options here, other than placing other.dll in the root directory of the application?

(While the question Altering DLL search path for static linked DLL is related, it describes a scenario that doesn't quite make sense: an application implicitly linking against a plug-in DLL. I believe that a clear, typical scenario may help uncover additional solutions to this common issue, such as explicitly loading other.dll when myplugin.dll gets loaded by the application, if that would be possible.)

Edit: another similar question: Plugin DLLs that depend on other DLLs

Edit: I found a solution to the problem, see the accepted answer below. As far as I know, this is the cleanest solution. I hope it helps someone else.

Community
  • 1
  • 1
François Beaune
  • 4,270
  • 7
  • 41
  • 65
  • How about in a directory found on your PATH? The link you posted says exactly this. – PaulMcKenzie Apr 23 '16 at 18:49
  • 2
    Possible duplicate of [Altering DLL search path for static linked DLL](http://stackoverflow.com/questions/3832290/altering-dll-search-path-for-static-linked-dll) – gdlmx Apr 23 '16 at 19:00
  • 1
    @PaulMcKenzie Thanks for chiming in. Altering the PATH is quite intrusive, may have side effects, and basically requires an installer program (i.e. pure "xcopy-deployment" is no longer possible). – François Beaune Apr 23 '16 at 19:06
  • And introduces a potential privilege escalation as the system will load the first "other.dll" it finds on the path. – Chris Becke Apr 23 '16 at 19:25
  • 1
    The solutions in Altering DLL search path... do apply here, and the scenario served to simply constrain some of the potential solutions - a statically linked plugin dll would be loaded before the host app could call `SetDllDirectory` - which is a sub optimal solution as it requires the application to prepare the runtime environment for the dll. – Chris Becke Apr 23 '16 at 19:31
  • You've probably already thought of this, but just in case: consider recompiling `other.dll` to be a static library (which you can then include directly in `myplugin.dll`) rather than a DLL. – Harry Johnston Apr 23 '16 at 23:21
  • @HarryJohnston Yes I thought about that, unfortunately the plugin is really a collection of plugins working together (that's how things are done with this app--Autodesk 3ds Max) so it is desirable to have only one "instance" of `other.dll` loaded. Additionally `other.dll` is actually a rather large library (30 MB) so it would be a gigantic waste of space to duplicate it. – François Beaune Apr 24 '16 at 07:59
  • If you don't get a better answer, are you able to control the order in which the plugins are loaded? You could include a dummy plugin whose only job is to preload the DLL; once it is loaded the other plugins should be able find it. (Or if not you could add the directory to the process DLL search path.) – Harry Johnston Apr 24 '16 at 23:27
  • @HarryJohnston Unfortunately I don't have any control over the order in which plug-ins are loaded, however you gave me a (possibly impractical) idea: write a plug-in "shim" that would first load `other.dll` before loading `myplugin.dll` and deferring all calls to the shim to calls to the real plugin. Not sure how much wiring is necessary, and whether or not it's worth the effort... – François Beaune Apr 25 '16 at 07:03
  • That should work, come to think of it. Assuming there is some sort of initialization function that the application calls first when it loads a plugin, it shouldn't even be too hard to do. – Harry Johnston Apr 25 '16 at 07:12

1 Answers1

3

The idea I outlined in the last comment to my question turned out to be a good one.

I changed myplugin.dll to be a simple shim DLL. The entry point of that shim performs the following operations:

  1. It first loads other.dll (using LoadLibrary) from the directory containing the shim, plugins\myplugin\ in my case.
  2. It then loads myplugin-impl.dll, the "real" plug-in, from the same directory.

myplugin.dll then simply forward all calls to myplugin-impl.dll which does the actual job.

Note that myplugin-impl.dll still links implicitly to other.dll. However, when myplugin-impl.dll is loaded, other.dll has already been loaded by the shim in the address space of the application's process so no further loading occurs.

With this solution, we get the benefits of implicit DLL loading (in particular loading C++ classes with virtual methods) while still having full control on where the implicitly-loaded DLL is loaded from and how it is loaded.

François Beaune
  • 4,270
  • 7
  • 41
  • 65