user295190
user295190

Reputation:

C++: Explicit DLL Loading: First-chance Exception on non "extern C" functions

I am having trouble importing my C++ functions. If I declare them as C functions I can successfully import them. When explicit loading, if any of the functions are missing the extern as C decoration I get a the following exception:

First-chance exception at 0x00000000 in cpp.exe: 0xC0000005: Access violation.

DLL.h:

extern "C" __declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

DLL.cpp:

#include "DLL.h"
int addC(int a, int b) {
    return a + b;
}
int addCpp(int a, int b) {
    return a + b;
}

main.cpp:

#include "..DLL/DLL.h"
#include <stdio.h>
#include <windows.h>

int main() {
    int a = 2;
    int b = 1;
    typedef int (*PFNaddC)(int,int);
    typedef int (*PFNaddCpp)(int,int);

    HMODULE hDLL = LoadLibrary(TEXT("../Debug/DLL.dll"));

    if (hDLL != NULL)
    {
        PFNaddC pfnAddC = (PFNaddC)GetProcAddress(hDLL, "addC");
        PFNaddCpp pfnAddCpp = (PFNaddCpp)GetProcAddress(hDLL, "addCpp");
        printf("a=%d, b=%d\n", a,b);
        printf("pfnAddC: %d\n", pfnAddC(a,b));
        printf("pfnAddCpp: %d\n", pfnAddCpp(a,b)); //EXCEPTION ON THIS LINE

    }
    getchar();
    return 0;
}

How can I import c++ functions for dynamic loading? I have found that the following code works with implicit loading by referencing the *.lib, but I would like to learn about dynamic loading.

Thank you to all in advance.

Update: bindump /exports

1 00011109 ?addCpp@@YAHHH@Z = @ILT+260(?addCpp@@YAHHH@Z)
2 00011136 addC = @ILT+305(_addC)

Solution:

  1. Create a conversion struct as found here
  2. Take a look at the file exports and copy explicitly the c++ mangle naming convention.

    PFNaddCpp pfnAddCpp = (PFNaddCpp)GetProcAddress(hDLL, "?addCpp@@YAHHH@Z");

Upvotes: 0

Views: 1909

Answers (2)

Ken Bloom
Ken Bloom

Reputation: 58800

It's possible to just wrap a whole header file in extern "C" as follows. Then you don't need to worry about forgetting an extern "C" on one of your declarations.

#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

#ifdef __cplusplus
} /* extern "C" */
#endif

You can still use all of the C++ features that you're used to in the function bodies -- these functions are still C++ functions -- they just have restrictions on the prototypes to make them compatible with C code.

Upvotes: 0

James McNellis
James McNellis

Reputation: 355297

Inevitably, the access violation on the null pointer is because GetProcAddress() returns null on error.

The problem is that C++ names are mangled by the compiler to accommodate a variety of C++ features (namespaces, classes, and overloading, among other things). So, your function addCpp() is not really named addCpp() in the resulting library. When you declare the function with extern "C", you give up overloading and the option of putting the function in a namespace, but in return you get a function whose name is not mangled, and which you can call from C code (which doesn't know anything about name mangling.)

One option to get around this is to export the functions using a .def file to rename the exported functions. There's an article, Explicitly Linking to Classes in DLLs, that describes what is necessary to do this.

Upvotes: 1

Related Questions