2

I have a c++ application that is linked against some 3rd party dynamic libraries. Some of my main classes inherit from these libraries, and make function calls to those libraries, etc. My application works without the inclusion of those libraries in theory (ie, if I manually stripped out all code and references pertaining to those libraries, it would still work), it would just be more limited in functionality. If I could craft an analogy, imagine that I've created a Windows Notepad clone, and included a 3rd party library that allows users to embed pictures and video in the document.

When I distribute my application, there is a chance my clients may not have those libraries installed. Is there a way I can have my program detect if the required DLL library exists, and simply ignore all related code if it's not installed?

Currently if I run my application without the 3rd party libraries installed, it displays errors related to the missing DLLs and crashes. One obvious solution is to simply release two versions of my application...one without the external dependencies and one with, but I'd like to avoid managing two products independently like that.

Tyson
  • 1,226
  • 1
  • 10
  • 33
  • 1
    You might have to do some re-architecting, but [dynamic loading](https://en.wikipedia.org/wiki/Dynamic_loading) could be part of the solution. – Robert Prévost Sep 04 '17 at 19:22
  • 1
    You may be interested to read about the [Plugin Pattern](https://stackoverflow.com/questions/785480/good-patterns-for-a-c-c-plugin-based-system). – user0042 Sep 04 '17 at 19:36

6 Answers6

2

There is such option "delay load dll"

  1. For dll xxx.dll you configure linker to use "delayload"
  2. Till you call any function from dll it will not be loaded and your application will start successfully even if the dll is not present
  3. You use LoadLibrary to check if xxx.dll is available.
  4. If LoadLibrary failed - you disable module using xxx.dll
  5. If LoadLibrary is successful - You unload it (you do not need dynamic loading - it is only use to test the presence of the dll) and use library as if it is linked regularly - no need to modify code using any xxx.dll related functionality
Artemy Vysotsky
  • 2,694
  • 11
  • 20
  • Delay load is very easy, plus useful if the dll name is fixed. But some 3rd party libraries change their dll name, e.g., it includes (stupidly) a version number. In which case, see Wayne's answer below. Unfortunately GetProcAddress is tedious. – davidbak Sep 21 '17 at 17:50
2

See this answer here: Dynamically load a function from a DLL

  1. You basically use LoadLibrary to load the DLL, the result will be null or not if loaded.

  2. Then you use GetProcAddress to get the functions.

Wayne
  • 3,359
  • 3
  • 30
  • 50
0

If you want to distribute the binary of your application you can use dynamic loading (take a look here)

But if you have the option to build your application on clients system, you can use CMake and set compilation flags if it could not find the library you want. Then your code can behave according to this flag's value (i.e. this way you have the information about weather this library exists or not in your code)

Sinapse
  • 786
  • 1
  • 6
  • 23
0

Loading dynamic lib or injecting to the process or ... can be using after this you can :

    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
    inj_hModule = hModule;
    DisableThreadLibraryCalls(hModule); // Disable DllMain calls for DLL_THREAD_*

    HANDLE hThreadProc = CreateThread(nullptr, NULL, LPTHREAD_START_ROUTINE(ThreadProc), hModule, NULL, nullptr);
    CloseHandle(hThreadProc);
    Beep(2000, 500);
}

if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
    Beep(2000, 500);
    FreeLibraryAndExitThread(hModule, 0);
    // exit this thread
    ExitThread(0);
}
0

Well, you should revise your software architecture, and go about a Plugin Design Pattern as was introduced by Martin Fowler.
You don't want dynamic linkage for such case, though it's quite similar.

Regarding implementations in C++ that basically means you introduce an abstract interface first

 struct Foo {
     virtual void Bar() = 0;
     virtual ~Foo() {}
 };

and lookup for suitable implementations coming with shared libraries at runtime1.

The exported interface of the shared library implementation needs to match your abstract interface declaration.

You can use a Factory to do that lookup, loading the shared library and create an instance of the implementation.

Here's some more information which OS functions are involved in dynamically loading and binding the Plugin.


1)Note that shared libraries don't need to have the extension .dll or .so if you're loading these actively.

user0042
  • 7,917
  • 3
  • 24
  • 39
0

My advice would be to carefully split the code dependent on that DLL. Design a clean interface to that part of your project that can be easily dynamically loaded (LoadLibrary), and have only pure virtual interfaces (no DLL export) on any classes you interact with in the main part of your program. Ideally it has a pure function interface, as those are most stable.

Now, that DLL can depend on the 3rd party DLL like normal. Your main code calls your "wrapping" DLL by loading it manually, and handles load failure gracefully.

This is easier than using a DLL not designed for this, and you can experiment without installing/uninstalling the 3rd party DLL by omitting your wrapping DLL.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524