Search code examples
c++windowswinapidllexport

Dynamically use a DLL from a console application


I'm trying to create a library Lib.dll to get dynamically called from a console application but cannot find the function funci() I want to call.

The Lib.dll is the outcome of a project (Console Application, but set to Configuration Type: .dll) created in Visual Studio 2019.

Lib.cpp is the only file in that project, and only contains the code:

__declspec(dllexport) int funci() 
{
    return 50;
}

I think I'm exporting the function correctly as I found the function by using DLL Export Viewer v1.66.

enter image description here

However, I struggle to locate the function through my Console Application (.exe):

#include <windows.h>
#include <iostream>

typedef int(__cdecl* o_funci)(void);

o_funci funci;

int main()
{
    HINSTANCE hGetProcIDDLL = LoadLibraryA("C:\\Lib.dll");

    if (!hGetProcIDDLL) {
        std::cout << "could not load the dynamic library" << std::endl;
        return EXIT_FAILURE;
    }

    // resolve function address here
    funci = (o_funci) GetProcAddress(hGetProcIDDLL, "funci");
    if (!funci) {
        std::cout << "could not locate the function" << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "funci() returned " << funci() << std::endl;

    FreeLibrary(hGetProcIDDLL);
}

Something is going wrong at GetProcAddress but don't know why. Where did I go wrong?

Output:

enter image description here

I've been looking at this old post: Dynamically load a function from a DLL


EDIT: SOLVED THANKS TO tenfour

I used DependencyWalker.

Without extern "C" I could see the undecorated funci had the name ?funci@@YGHXZ,

enter image description here

So funci = (o_funci)GetProcAddress(hGetProcIDDLL, "?funci@@YGHXZ"); worked.

With extern "C" the undecorated funci had the name _funci@0 - a little cleaner.

enter image description here

Another note; using ordinal 0x0001 worked in both cases. Like this: funci = (o_funci)GetProcAddress(hGetProcIDDLL, (PCSTR)0x0001);

enter image description here


Solution

  • The tool you're using is showing you a pretty-fied version of the export name. Its real name will include name mangling, which is a convoluted attempt to embed call info into the export name.

    You have a number of options to make this work with GetProcAddress:

    1. Use the REAL export name. Your tool probably has the option to see the un-prettyfied name (the mangled export name)
    2. Export the function using a module definition file (*.def), where you can even specify the name it will be exported as
    3. Import by ordinal instead of name
    4. Wrap the function in extern "C" { ... } which will use C-style naming, which avoids name mangling.

    The most common solution is probably #4, with #2 as a close second.