views:

584

answers:

2

Two Delphi programs need to load foo.dll, which contains some code that injects a client-auth certificate into a SOAP request. foo.dll resides in c:\fooapp\foo.dll and is normally loaded by c:\fooapp\foo.exe. That works fine. The other program needs the same functionality, but it resides in c:\program files\unwantedstepchild\sadapp.exe. Both aps load the DLL with this code:

FOOLib := LoadLibrary('foo.dll'); 
...
If FOOLib <> 0 then 
begin
  FOOProc := GetProcAddress(FOOLib , 'xInjectCert');
  FOOProc(myHttpRequest, Data, CertName);
end;

It works great for foo.exe, as the dll is right there. sadapp.exe fails to load the library, so FOOLib is 0, and the rest never gets called. The sadapp.exe program therefore silently fails to inject the cert, and when we test against production, it the cert is missing, do the connection fails. Obviously, we should have fully-qualified the path to the DLL. Without going into a lot of details, there were aspects of the testing that masked this problem until recently, and now it's basically too late to fix in code, as that would require a full regression test, and there isn't time for that.

Since we've painted ourselves into a corner, I need to know if there are any options that I've overlooked. While we can't change the code (for this release), we CAN tweak the installer. I've found that placing c:\fooapp into the path works. As does adding a second copy of foo.dll directly into c:\program files\unwantedstepchild. c:\fooapp\foo.exe will always be running while sadapp.exe is running, so I was hoping that Windows would find it that way, but apparently not. Is there a way to tell Windows that I really want that same DLL? Maybe a manifest or something? This is the sort of "magic bullet" that I'm looking for. I know I can:

  1. Modify the windows path, probably in the installer. That's ugly.
  2. Add a second copy of the DLL, directly into the unwantedstepchild folder. Also ugly
  3. Delay the project while we code and test a proper fix. Unacceptable.
  4. Other?

Thanks for any guidance, especially with "Other". I understand that this issue is not necessarily specific to Delphi. Thanks!

+6  A: 

The MSDN documentation for LoadLibrary tells you exactly where Windows will search for the DLLs. You either have to hard-code the path to the DLL, put it in the same folder as your app, or put it in one of those default search locations from the LoadLibrary docs.

Ken White
Thanks - that's a good article, and I apparently suffer from Delphi Myopia, as I forget to check MSDN. Interestingly, MSDN claims: "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 would expect that this would have saved me here, but apparently there's more to it than that. Even though foo.exe has loaded foo.dll, SadApp.exe is not able to take advantage of that.
Chris Thornton
+1 Loadlibrary is my current weapon of choice, and hence what my suggestion would have been.
MarkRobinson
The problem has solved itself, due to my re-reading of the MSDN docs. The key is that the 'current directory' is searched in addition to "The directory from which the application loaded.". Ok, so why/when would those be different? That's the key here. Normally, the user launches SadApp from a menu within foo.exe. But there's also an icon that can be used to launch it independenly. That's where it was failing. When launched "normally" through the menu of the main app, the "current directory" is c:\fooapp, and the DLL is found and loaded. Bingo! Now it's just a procedural/training issue.
Chris Thornton
@Chris: Windows shortcuts have a Current Directory field. See if you can modify your installer to make it set the Current Directory for SadApp whenit creates the shortcut to it.
Mason Wheeler
There are several reasons why the current directory could be different from the application directory, Chris. One is if the "start in" property is set in the shortcut file used to start the program. Another is if the program is started from the console command line using a full path from another directory. Another is if you've used the default settings of the TOpenDialog and the user has used the dialog to select a file. Yet another, and perhaps the most obvious, is if you've called ChDir. This is **not** a training issue. Your program should work no matter how the user starts it.
Rob Kennedy
@Rob, It's a training issue in that we need to train the users to only launch the program from the menu of the main program, and not use the shortcut. i.e. we can't fix the code right now, so in the meantime, we'll train the users to do it the "regular" way, which always works. +1 for good answer though.
Chris Thornton
@Mason, Undestood. Unfortunately, it turns out that this release is going to be pushed down via an auto-update program (homebrew) that doesn't have the same capability that a full installer would, so modifying the shortcuts is out of the picture. So my options #1, #2, which I intially proposed, turned out to be non-starters. +1 for good answer though.
Chris Thornton
A: 

Or you can simply edit the environment variable "path" and place the path to the dll in there. In this case adding ;c:\fooapp to the path should be sufficient. Since the environment changes of a parent effects a child, you can also create a loader application which adjusts the its environment variable then spawns to your application.

skamradt