2

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

0

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

7 Comments

WTF? I missed the extern "C" but looked at the snapshot of OP and thought: Hmm. __cdecl might fix it but I don't have experience with it. I never had guessed that the DLL export viewer shows a pretty-fied version of the export name (I've some experience with DependencyWalker but I cannot remember how it is done there.) How underhanded...
@Scheff "I've some experience with DependencyWalker but I cannot remember how it is done there." Dependecy Walker has a toggle named "Undecorate C++ functions".
@AlgirdasPreidžius Correct, confirmed. ;-) I'm not sure whether this can be configured (or is remembered somehow) but in my case the "true" (decorated) names are shown by default. That's what I would consider as "less underhanded". (Dep.Walker still rocks.) :-)
extern "C" doesn't avoid name mangling. It merely chooses a different set of name decorations, that are easier to read and type. There's also a 5th option: Compile a 64-bit binary (with extern "C"). The name decoration in this case will disappear.
@jub: Importing by ordinal requires that you never change the order of exports. A pretty tough requirement to satisfy, and hardly justifiable if all you need is more convenient important names.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.