tags:

views:

304

answers:

1

This problem of mine has me pulling my hair out. It's related to the issue I had earlier with needing to write a Mutex that will get destroyed when going out of scope. It turns out that I was stupid and didn't need the Mutex -- the things I needed to lock out wouldn't observe the lock because they were actually being called from the same thread. I hadn't realized that one set of calls was coming from a Timer. Oops.

Anyhow, I'm doing some investigation to try to help narrow down the cause of our problems with that 3rd party DLL. They seem to believe that if we have multiple copies of their C DLLs (we'll call them a.dll and b.dll for now) in different folders, local only to the C# assemblies that use them, then life will be good and I can finally go home and actually see my family.

The proposed folder structure looks something like this:

+--App folder
   +--DeviceA.dll
   +--a.dll (linked to by DeviceA)
   +--b.dll (linked to by a.dll)
   +--Device B Folder
      +--DeviceB.dll
      +--a.dll
      +--b.dll

My problem is that even though DeviceB.dll is in a separate folder, when it is loaded, it doesn't load and look for its dependencies in the Device B Folder -- it looks in the App folder instead. I really need to be able to guarantee that it's linking to a totally different DLL than the one that's in the App folder.

I've looked into the build properties, read some things on manifests, and haven't figured it out yet. Is this even possible? If I know that DeviceB.dll is in a different folder, do I have to set CurrentDirectory or something similar to force it to link to the DLLs in its own folder, instead of from the executing assembly's folder?

EDIT-- actually, the a.dll in "Device B Folder" should be c.dll. So a.dll links to b.dll, and c.dll links to b.dll. I can't change this behavior because the 3rd party DLL is already compiled to link to b.dll.

+3  A: 

Once you load a DLL (at the SDK level, with LoadLibrary), it's in your process space. If you try to load it again, you'll just increment the reference count. In other words, you won't be able to load two different versions of the same DLL because they have the same module name.

Steven Sudit
I figured as much that this wouldn't work. Bummer... is there any way to modify the binary to at least hack the system until the 3rd party developer can fix it (assuming that he even will?)?
Dave
actually, maybe I should clarify something -- I'm a little weak in the area of DLL loading and how it works under the hood. I don't recall a DLL having any "module name" other than the filename. In my example above, I have two different copies of a.dll and b.dll, but I failed to mention that in reality, I have renamed Device B's dependencies to c.dll, but b.dll is still b.dll. I can't change that because I can't change the linking of the 3rd party DLL. So... yeah I guess I am out of luck since you're saying that even if b.dll is in another folder, it will still be referenced the same.
Dave
Yes, probably, although it's a major pain. In a DLL's .DEF file, there's a command at the top that goes "LIBRARY libname". It's this libname that is used as the unique module name, so if you patch the second set of DLL's to use a different libname, that'll do it. You'll also need to generate new .LIB files with ImpLib and compile to those. However, there's no guarantee that either DLL will peacefully coexist with itself.
Steven Sudit
@Steven - yes, I do believe this is somewhat of a useless exercise for me. Useless in that I think the flaw is some static data in the 3rd party DLL, but useful in that I'm learning some things I've never even dabbled with before, i.e. nitty-gritty specifics of DLL loading.
Dave
I think the best thing you can do is make a strong case for this being their fault, so you can get them to fix their own product.
Steven Sudit
@Steven - I'm not one to complain unless I'm absolutely positive that it's not on my end. I'm no genius developer after all. :) So here's what I did to fake out the system -- I took my hex editor, then changed one character in a.dll so that it would load f.dll instead of b.dll. Totally tricked the system from a module loading standpoint! Now I have to see if everything still crashes like before...
Dave
Good luck. (Let us know how it goes.)
Steven Sudit
OMG. The hex editing totally worked. Now it's not a long term solution by any means, and I haven't tested the system enough to rule out any crashes, but it's actually running the code from both DLLs right now. Wow.
Dave
Glad the hack worked, though it's really not a solution.
Steven Sudit
so apart from the naming issue, how about the issue related to loading a DLL's dependencies from the folder that said DLL is in? I don't want to have all of these extra copies in the main app's folder. At the very least, I still want them to reside only in the folder of the DLL that needs them.
Dave
If I understand correctly, you've resolved this. You've patched the a.dll and b.dll in the Device B folder to a1.dll and b2.dll, then patched a1.dll to load b1.dll and DeviceB.dll to load a1.dll, right? If so, then you can keep them in separate directories or combine them; whichever you prefer.
Steven Sudit
you have it correct enough -- a.dll loads b.dll, and c.dll loads d.dll, where c.dll is a hex-edited copy of a.dll and d.dll is really b.dll. My problem right now is that even when I load DeviceB.dll from the DeviceB folder, it is looking for c.dll and d.dll in the executing assembly's folder, rather than the DeviceB.DLL module's folder. How can I force DeviceB.dll, when loaded, to look for its dependencies in its folder first? I always thought that was automatic -- look in the local folder, whether it's an EXE or DLL, then look in the windows PATH... but that's not the case for DLLs here.
Dave
Take a look at the registry stuff at the bottom of http://msdn.microsoft.com/en-us/library/ms886736.aspx
Steven Sudit
Thanks, Steven. I just got back from vacation, so I didn't get to read your comment until just now. If I need to specify the exact path to the DLL that I want to load, but let Visual Studio run the show, what project settings do I need to change so that the DLL is in the plugin's output folder, rather than that of the executing assembly?
Dave
I'm not sure that this is something VS can do, but I was thinking of a possible workaround. If you need absolute control over which DLL is loaded, the way to do it is to call LoadLibrary with th exact path. As I understand it, once a specific DLL is loaded, other attempts at LoadLibrary are not going to reload it again, just increment a reference count that prevents unloading. If you see what I'm getting at, this could let you preload the desired DLL's in the desired order.
Steven Sudit
I'm reading some references in MSDN, SO, and some books on the CLR right now, and it sounds like I can modify app.config, or whatever config file my plugins use, to specify exactly where the CLR should look for dependencies. Hopefully, I'll have this figured out in a couple of days.
Dave
You sure can, but I think this applies only to assemblies, not to generic DLL's.
Steven Sudit