DLL dependency question / SetDLLDirectory

2019-01-26 23:35发布

问题:

I have the following situation and can't come up with any good solution.

I have a C++ application (app.exe) installed in C:\ProgFiles\MyApp. It needs a bunch of DLLs, which I install in C:\ProgFiles\MyApp\bin. I'd like to put them in a subfolder because there are so many of them.

Now when I start app.exe, something needs to let Windows know where the required DLLs are. In the past I was using the PATH environment variable for this, but I can't do this anymore because I will create another application with a separate installer, which uses many of the DLLs that have the same name.

I was thinking of calling SetDLLDirectory at the beginning of the app - but I forgot that because required DLLs are missing, it fails before getting there.

Any suggestions?

回答1:

See this article from Microsoft which discusses the DLL search path and related issues.

In particular, notice that if you do not put them in your app’s directory the current directory takes precedence, which is a security hole.

One solution would be to use LoadLibrary (with a fully-qualified path), then GetProcAddress. That would be kind of painful.

No normal user is going to go digging around in C:\Program Files\YourApp and that is where you should put them unless you have a good reason not to.



回答2:

Using the delay load option in conjunction with SetDLLDirectory might work. A delay loaded DLL is dynamically loaded by the system on its first reference. If you are using Visual Studio, you can specify which DLLs are to be delay loaded in the project properties under the Linker Input options. There is a Delay Loaded DLLs field for specifying them. Otherwise, you can specify /DELAYLOAD:mydll.dll in the linker command.



回答3:

I think you are best putting the .DLL files in the same directory as the .EXE - there might be lots of them, but this works and no one is gonna look in that directory anyway, so I wouldn't worry too much about it.

If you rely on PATH then you are always going to be at the mercy of the user screwing it up and causing you extra support overhead, for no good reason at all.



回答4:

one solution to the problem would be use SetDllDirectory function; but, it needs to be first thing you execute on your program (which is hard to do), my solution is to use third party program to set dll directory and then invoke your EXE file as a new process:

this is third party which will be a EXE file:

#include <windows.h>

SetDllDirectory(_T(".dll location"));   

STARTUPINFOW siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);

if (CreateProcessW(L".exe location",NULL, NULL, NULL, FALSE,
    0, NULL, NULL,
    &siStartupInfo, &piProcessInfo))
{
    /* This line waits for the process to finish. */
    /* You can omit it to keep going whilst the other process runs */
    //dwExitCode = WaitForSingleObject(piProcessInfo.hProcess, (SecondsToWait * 1000));
}
else
{
    /* CreateProcess failed */
    //iReturnVal = GetLastError();
}
return 0;