C++ Load DLL From a Subdirectory?
Asked Answered
D

3

8

I'm new to the "hidden/dark places" of C++ and I was wondering how to load a .dll file from a different directory or a sub-directory inside the one where my current executable is running

Ex:

./MyAppDirectory
  /MyApp.exe
  /SomeDLL.dll
  /AnotherDLL.dll
  /SubDirectory
    /SomeDLL2.dll
    /AnotherDLL2.dll
    /YetAnotherDLL.dll
    /...

So "MyApp.exe" automatically loads "SomeDLL.dll" and "AnotherDLL.dll" from it's root folder "MyAppDirectory" however I also want to be able to load "SomeDLL2.dll", "AnotherDLL2.dll", "YetAnotherDLL.dll" etc. from the "SubDirectory" folder inside the "MyAppDirectory" folder.

I've been doing some searches and from what I've found the only solutions are:

  • 1) Modify the working directory of the executable.
  • 2) Put the DLL files inside the Windows root.
  • 3) Modify the PATH environment variable.

But all of them have some bad sides (not worth mentioning here) and it's not what I actually need. Also another solution is through "Application Specific Paths!" which involves working with Windows registry and seems the be slightly better then the ones mentioned before.

However I need to be able to do this inside "MyApp.exe" using C++ without the need to use external methods.

I'm using MinGW 4.7.2 and my IDE is Code::Blocks 12.11 also my OS is Windows XP SP3 Pro x86.

Any reference, tutorial, documentation, example etc. is accepted and thank you for your time :D

Devland answered 2/7, 2013 at 8:3 Comment(2)
All three of your itemised list are bad ideas. Don't do any of those.Megrim
possible duplicate of Altering DLL search path for static linked DLLSatterlee
I
3

If you are NOT explicitly loading the DLL ("manually", in your code using LoadLibrary(...)), then you HAVE to have the .dll in a place that Windows will look for DLL's, whihc pretty much means one of the three options you are talking about in your question.

When using LoadLibrary, you can specify a relative or absolute path to the DLL.

Note that it's completely different to load DLL's explicitly and implicitly - in the explicit case, you have to use the LoadLibrary, and then use GetProcAddress to find the address of the function, and you will have to use function pointers to call the functions - this is typically only used for plug-ins or similar functionality where the DLL provides a small number of functions (quite often just a factory function to create a objects to do something that has a generic interface class, and each DLL has the same type of function to create an object to do whatever it is supposed to do).

In the implicit load, you don't need to do anything in your code to use the DLL, and the functions from the DLL just appear to be there as if they were hard-linked into the application.

Indiana answered 2/7, 2013 at 9:39 Comment(2)
Thank you very much for the extended answer which answered my question :DDevland
Sorry for the mistake. I was distracted by someone while documenting further on your answer and forgot to confirm.Devland
E
1

You should use

LoadLibrary("subFolder\\dynamicLibrary.dll");

That's the explicit link to DLLs, it's a bit tougher than the implicit linking(that I think it's what you are using), but I believe that this is the correct way to achieve your purpose

explicit

implicit

Escallop answered 2/7, 2013 at 8:31 Comment(4)
Is this method specific to MSVC or I can use it in other compilers like MinGW (gcc) ?Devland
It's a WinAPI, so you can use in every compiler, you just need to include <windows.h> and link Kernel32.lib Obviously it works only in WindowsEscallop
No. You should use an absolute path.Megrim
Use an absolute path, and break if your program is installed in place where you didn't expect it? You'd fail the Microsoft "Designed for Windows XP" qualification, let alone the newer versions.Satterlee
S
0

I have done that by a bootstrap exe.

See the code below. Build it with c++17 standard.

It's a GUI app, it just:

  1. set working dir to the sub folder (bin folder in the following code),

  2. launch the target exe in sub folder according to a cmd file in that folder,

  3. and quit.

#include <windows.h>
#include <stdio.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>


namespace fs = std::filesystem;

std::wstring toWstring(const std::string& input)
{
    std::wstring retVal;
    auto targetSize = MultiByteToWideChar(CP_UTF8, 0, input.c_str(), static_cast<int>(input.size()), NULL, 0);
    retVal.resize(targetSize);
    auto res = MultiByteToWideChar(CP_UTF8, 0, input.c_str(), static_cast<int>(input.size()),
        const_cast<LPWSTR>(retVal.data()), targetSize);
    return retVal;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {

    //const wchar_t* startupCWD = fs::current_path().wstring().c_str();
    WCHAR startupCWD[MAX_PATH];
    GetCurrentDirectory(MAX_PATH, startupCWD);
 
    // get current exe location folder
    WCHAR szFileName[MAX_PATH];
    GetModuleFileName(NULL, szFileName, MAX_PATH);
    fs::path p = szFileName;
    fs::path curExeFolder = p.parent_path();

    // cmd file record the cmd line to launch exe, like "my.exe para1 para2"
    std::string cmdFilePath = curExeFolder.string() + "\\bin\\cmd";

    std::ifstream inFile(cmdFilePath);
    inFile.open(cmdFilePath);
    std::stringstream fcontent;
    fcontent << inFile.rdbuf(); //read the file
    inFile.close();

    std::wstring widestr = toWstring(fcontent.str());
    WCHAR  commandLine[260];
    wcscpy_s(commandLine, widestr.c_str());


    // set working dir to bin folder, 
    fs::current_path(curExeFolder.string() + "\\bin");



    // Create the process
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    // Initialize STARTUPINFO structure
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    // Initialize PROCESS_INFORMATION structure
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcessW(NULL,   // Application name
        commandLine, // Command line
        NULL,   // Process handle
        NULL,   // Thread handle
        FALSE,  // Inherit handles
        0,      // Creation flags
        NULL,   // Environment block
        NULL, // Working directory
        &si,    // STARTUPINFO
        &pi))  // PROCESS_INFORMATION
    {
        return 1;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}
Scotland answered 29/9 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.