10

My basic issue is this: my program (MyProgram.exe) has a dependency on a DLL from another program (OtherProgram), and I'm trying to avoid repackaging a new DLL every time OtherProgram updates. I'd like to have MyProgram.exe link in OtherProgram's DLL when it launches, but I'm not completely sure that Windows allows for this. So if there is some kind of workaround that would also be acceptable.

And just for some background, the platform is Windows 7 x64, and MyProgram.exe runs fine when I create a symlink in the MyProgram.exe project directory to the DLL in OtherProgram's install directory. When I try to run it without the symlink, I get the "program can't start because OtherProgramDLL.dll is missing from your computer" error.

Any advice or links to relevant info is greatly appreciated!

EDIT: Clarification: the DLL is not linked at compile-time, this issue crops up at runtime

CJ McAllister
  • 291
  • 3
  • 10
  • 20
  • 3
    One option is to use [delay loading](http://msdn.microsoft.com/en-us/library/151kt790.aspx) to be able control the path used for the DLL and not have to mess with the global `PATH` variable. For example see this article: http://www.codemaestro.com/articles/6 – David Heffernan May 15 '12 at 18:24
  • 1
    Your edit makes no sense. All DLLs are loaded at runtime. – David Heffernan May 15 '12 at 18:34
  • 1
    Are you using `LoadLibrary` to load the DLL? – John Dibling May 15 '12 at 18:35
  • 4
    This SO answer has more on the delay load option: http://stackoverflow.com/questions/280485/how-do-i-rename-a-dll-but-still-allow-the-exe-to-find-it#281011 – David Heffernan May 15 '12 at 18:43
  • The MSDN pages refer to two types of dynamic linking. The first and probably most-frequenltly used is when the DLL is loaded automatically when the program starts. This is called [Load-Time Linking](http://msdn.microsoft.com/en-us/library/windows/desktop/ms684184(v=vs.85).aspx). The second is when you explicitly call `LoadLibrary` in your code to load the DLL. This is called [Run-Time Linking](http://msdn.microsoft.com/en-us/library/windows/desktop/ms685090(v=vs.85).aspx) They are mutually exclusive. Use one or the other. – John Dibling May 15 '12 at 18:46
  • @John They used to call it implicit linking and what they now call run-time linking was formerly known as explicit linking. Clearly I am behind the times in the terminology. All the same, almost everyone refers to load-time linking as static linking which is even more bizarre in my view. – David Heffernan May 15 '12 at 18:50
  • This is somewhat dangerous as you are relying on OtherProgram's DLL interface to remain stable across product versions. Typically this is the case, but there is no guarantee (short of system libraries). If they change their DLL then your program stops working and your users call you. Proceed at your own peril. – Luke May 15 '12 at 20:22

6 Answers6

13

There are two types of dynamic linking in the Windows world:

  1. Load-Time linking is when a DLL is loaded automatically when your program starts up. Windows finds this DLL using a specific algorithm I'll discuss below.
  2. Run-Time linking is when you specifically load a DLL by calling LoadLibrary in your code. Similar rules apply as to how the library is found, but you can specify a fully-qualified or relatively-qualified path to control the search.

In the case of Load-Time linking, MS recommends that your program's DLLs are stored in and loaded from the same directory where your application is loaded from. If this is at all workable, this is probably your best option.

If that doesn't work, there are several other options, outlined here. One is to leverage the search order by putting the DLL in either the working directory or the directory where the application was loaded from.

You can change the working directory of an application by:

  1. Create a shortcut to your application.
  2. Bring up the shortcut's properties
  3. Edit the "Start in" property with the directory where the DLL is located.

When you launch your application using the shortcut, it will load the right DLL.

Other options for load-time linking include:

  • Adding a manifest to your application which specifies where your dependent assemblies are, or,
  • Setting the PATH.
Craig M. Brandenburg
  • 3,354
  • 5
  • 25
  • 37
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 4
    Using the current directory to find a DLL is legacy behaviour, and won't work if the system administrator has implemented KB2264107. – Harry Johnston May 15 '12 at 22:42
  • This KB only add option for admin, that he can remove cwd from dll search path, but cwd is still searched in by default. – Vizor Aug 16 '18 at 11:17
3

You could use LoadLibrary, but you would need a way to guarantee the DLL's location. This Wikipedia article provides good example on how to use the DLL after it has been loaded.

Eckstein
  • 183
  • 5
  • 1
    Wrong. If the exe is linked against the library, wherever you call LoadLibrary, it's too late. – Luchian Grigore May 15 '12 at 18:16
  • I didn't downvote, but you do not typically want to `LoadLibrary` a DLL. Certianly not just so you can specify the path where it lives. – John Dibling May 15 '12 at 18:16
  • @LuchianGrigore: Well, to be fair, it could be un-linked from the library. – John Dibling May 15 '12 at 18:17
  • 1
    @JohnDibling I disagree with your first comment. There are various scenarios where `LoadLibrary` is the best choice. And your second comment is quite correct, that's clearly what this answer envisions. – David Heffernan May 15 '12 at 18:17
  • Yes there are situations where LoadLibrary is actually the only option. But you shouldn't use it or *un-link* as you say when there are better options available. – Luchian Grigore May 15 '12 at 18:19
  • @LuchianGrigore What are the better options then. I strongly disagree that modifying `PATH` is a better option than this. – David Heffernan May 15 '12 at 18:20
  • @LuchianGrigore I don't believe his question stated his executable linked to the library at compile time, only that it has a dependency. If the DLL in "OtherProgram" changed when it updated he'd have to relink anyway. – Eckstein May 15 '12 at 18:20
  • @Eckstein: Only if the ABI changed. Simple bugfixes, with no changes in function signatures, would not need to be relinked for example. This is one of the big benefits of using DLLs in the first place. – John Dibling May 15 '12 at 18:21
  • @JohnDibling Correct, but in response to Luchian's comment, calling LoadLibrary is not too late. – Eckstein May 15 '12 at 18:23
  • @Eckstein I do believe Luchian is correct in that. I tried adding LoadLibrary as the first action within WinMain of MyProgram.exe, and it did not resolve the issue. However, I'm not all that familiar with COM and such, so there may be another location besides WinMain that would be more appropriate. – CJ McAllister May 15 '12 at 18:30
  • 1
    @cjm571 No I don't think you understand. You have to use `LoadLibrary` and `GetProcAddress` and stop using the .lib file that results in what is known as *implicit linking*. It certainly makes like more inconvenient if there are a lot of functions to link to, but you gain flexibility. – David Heffernan May 15 '12 at 18:33
1

You can add the directory where the dll is located to the PATH environment variable.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

I have struggled with the same problem and also found a dead end with the suggested methods like LoadLibrary, SetDllDirectory, Qt's addLibraryPath and others. Regardless of what I tried, the problem still remained that the application checked the libraries (and didn't find them) before actually running the code, so any code solution was bound to fail.

I almost got desperate, but then discovered an extremely easy approach which might also be helpful in cases like yours: Use a batch file! (or a similar loader before the actual application)

A Windows batch file for such a purpose could look like this:

@echo off
PATH=%PATH%;<PATH_TO_YOUR_LIB>
<PATH_TO_YOUR_APP_EXE>

/edit: Just saw @SirDarius comment in Luchian's answer which describes that way, so just take my batch code bit as a reference and all credits go to him.

Community
  • 1
  • 1
Franz B.
  • 442
  • 9
  • 22
  • SetDllDirectory won't work without delay-loaded dll because the compiler would ask the program to try load the DLL before your call to SetDllDirectory is made. See my answer below. – xiay Oct 01 '17 at 01:41
1

I have the same problem with one application I am working on.

I do not want to use runtime loading because there are tens of functions I would need to manually create function pointer for.

Mr Dibling's mention of manifest file opened a new door for me but I sadly found out that the oldest version of windows that supports the feature is Windows 7. It won't even work on Vista.

Long story short, a friend familiar with Windows Application development told me to look up Delay-Loaded DLL, which turns out to solve the problem perfectly with minimal effort. It delays the loading of DLL library to either the point you manually do, or the first time its function is called. So you just need to add your DLL path to the search path before that happens, where SetDllDirectory helps.

Here is the steps to make it work:

1) Specify the DLL to be delay-loaded to linker, either through your makefile, cmake or VS property page (Linker->Input of VS2015)

2) Call SetDllDirectory at the beginning of your program, before any call to the DLL is made.

Delay-loaded DLL is supported all the way back to VC6. SetDllDirectory is supported after XP SP1.

xiay
  • 855
  • 8
  • 19
0

Use Symbolic Links to the 3rd Party Executables

I found the approach advocated by Aaron Margosis useful. See:

Using NTFS Junctions to Fix Application Compatibility Issues on 64-bit Editions of Windows

Essentially, create symbolic links to each of the dependent 3rd Party executables. Place these symbolic link files in and amongst your own dependent executable files. Except for filename changes to the targets, the 'soft' symbolic links will resolve the load-time dependencies even as the target of the links are changed by future updates.

ergohack
  • 1,268
  • 15
  • 27