I have a DLL made in Delphi 7/Windows XP that I want to statically load in a host application on Windows (made in Delphi, too). I am using this line of code:
procedure Prepare_HTML_Email(var MailMessage : TIdMessage;
const FileAddress, aDetail, aAlarmType : String); stdcall; external DLL_ADD开发者_运维问答RESS;
where DLL_ADDRESS
must be the location the DLL is. But at this point I have a problem. The host application is a service, so it is running in C:\WINDOWS\System32
, but I want to put the DLL in another directory, not in C:\WINDOWS\System32
. The "external" keyword doesn't let to follow it with a function, it only admits a constant expression. So, How can I get the path of the DLL?
First, you're not "statically loading" anything. The D in DLL stands for dynamic; all DLLs are linked dynamically, no matter what. Static linking is how DCU and OBJ files get included in your program. You can't link statically to a DLL.
You're talking about load-time dynamic linking, where the OS loads the DLL for you implicitly due to the functions listed in your program's import table, as opposed to run-time dynamic linking, where you call LoadLibrary
using whatever you want. When you use the external
directive to define your function, you create an entry in the import table, and as far as I know, relative paths there are meaningless. The OS looks for DLLs at load time (and run time) using a certain documented search order. In general, it's the application's own directory, the current directory, the system directory, the Windows directory, and then everything else on the PATH environment variable.
In your case, the current directory and the system directory are the same place, and you don't have any control over them anyway. Don't put your DLLs in the Windows directory; that already has enough stuff that doesn't belong there.
Your best bet is to put your DLLs in the same directory as you've put your service EXE. If you don't want then, then you could put just enough to bootstrap your program in one DLL in that directory and then load everything else later with LoadLibrary
using whatever private DLL directory you want.
You could put your DLLs someplace else and then add that directory to the PATH environment variable. That variable is a shared resource, though, so think twice before you change it.
- Take a look at delayed dynamic link libraries, available since Delphi 2010. AFAIK you can't load the dll from a very specific path, but you can modify the environment path variable on the very first line of your host program to include the path where the dll is located before you use it's exported functions.
- Changing your code to load the dll explicitly is not difficult and you can specify the full path to the LoadLibrary API Call. You'll found a example of implicit and explicit dll loading in the same article.
If you place the path to the DLL in your system path, then it doesn't matter where you put it. Just be aware that you will have to reboot if you make the change for a service before it may take effect.
To edit the path variable, go to the advanced tab for system properties (right click properties from "My Computer") and press the "Environment Variables..." button. Change the system variable "Path" to include the directory where you want to store your DLL.
When resolving a DLL, the system first checks the current directory where the process is started, followed by the path variable from left to right, and will use the DLL found in the first directory it runs across... which is why it works when you place it in C:\Windows\System32.
See how Windows load DLLs here:
http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx
SetDllDirectory() may help you, but it's not available before XP SP1.
Also worth reading (linked from the main MSDN documentation page) is:
Dynamic-Link Library Redirection
Which allows to override even a hard coded DLL path in LoadLibrary. If it works for services, this could solve the problem in question.
精彩评论