8

I made a DLL with a function named "render()" and I want to load it dynamically to my application, but GetProcAddress cannot find it. Here's the DLL .h:

#ifdef D3D_API_EXPORTS
#define D3D_API_API __declspec(dllexport)
#else
#define D3D_API_API __declspec(dllimport)
#endif

D3D_API_API void render();

And here's DLL .cpp:

#include "stdafx.h"
#include "D3D_API.h"
#include <iostream>

D3D_API_API void render()
{
    std::cout << "method called." << std::endl;
}

Here's the application that tries to use that function:

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

int _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE myDLL = LoadLibrary( L"D3D_API.dll" );

    if (myDLL == NULL) {
        std::cerr << "Loading of D3D_API.dll failed!" << std::endl;
    }

    typedef void (WINAPI *render_t)();

    render_t render = (render_t)GetProcAddress( myDLL, "render" );

    if (render == NULL) {
        std::cerr << "render() not found in .dll!" << std::endl;
    }
    return 0;
}

My goal is to make a 3D engine that supports both D3D and OpenGL through their own .DLLs using a unified API. I looked at the .dll in notepad and there was a string "render".

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87

2 Answers2

13

The function you export is treated as a C++ function (because of *.cpp file extension) and so C++ name mangling is used to decorate the exported function name. If you use the Dependency Walker tool from Microsoft to inspect your created DLL you will see the functions full name.

You can either use that decorated name in your import code or force the compiler to export your function in C style, that is, in its undecorated form that your current import code expects.

You can tell the compiler to do so by adding extern "C" to your functions signature. Something like this:

extern "C" D3D_API_API void render();

Now your import code should work as expexted.

Frank Bollack
  • 24,478
  • 5
  • 49
  • 58
  • I tried using the decorated name in the import code, that is `GetProcAddress(myDLL, "??0MyObject@my_name_space@@QAE@XZ");` and the return value is `NULL`. Are you sure this should work? – Benny Feb 19 '14 at 13:07
  • 1
    To add to this, using 'extern "C"' will remove any C++ name mangling, but still leaves C name mangling. In order to export the plain names you should look at using a .DEF file. See https://blogs.msdn.microsoft.com/oldnewthing/20120525-00/?p=7533 – njplumridge Oct 03 '17 at 17:18
0

As the comment to the answer says:

using 'extern "C"' will remove any C++ name mangling, but still leaves C name mangling. In order to export the plain names you should look at using a .DEF file. See blogs.msdn.microsoft.com/oldnewthing/20120525-00/?p=7533

You need to add a new file with .DEF extension to your project, with similar to this contents:

LIBRARY      "MyRenderLib"

EXPORTS
render

Then in your DLL header you don't use __declspec(dllexport), but only extern "C"

extern "C" void render();
Dmitriy
  • 5,357
  • 8
  • 45
  • 57