c++visual-c++loadlibrary

How to initialize a C++ class inside a DLL which was loaded via LoadLibrary()?


I got a problem from my clients.

They removed some VC++ projects from their product, only have the dlls .

Now they want to process some data with some functions inside these dlls.

Let's say this is one class inside a dll.

//MyClass.h
class __declspec(dllexport) MyClass{
public:
    int a;
    int b;
public:
    MyClass();
    int Sum(int, int);
}
//MyClass.cpp
MyClass::MyClass(){
    a=0;
    b=0;
}

int MyClass::Sum(int c, int d){
    return c+d;
}

And, here is the exe.

//Test.exe
typedef void(__stdcall *TCon)();    // for constructor
typedef int(__stdcall *TSum)(int, int);    // for function Sum()

int main(){
    HMODULE myDll = LoadLibrary(TEXT("MyClass.dll"));
    FARPROC con = GetProcAddress(myDll, "??0MyClass@@QAE@XZ");  // I got this from DUMPBIN.exe
    FARPROC sum = GetProcAddress(myDll, "?Sum@MyClass@@QAEHHH@Z");  // I got this from DUMPBIN.exe, too

    TCon f_con = (TCon)con;
    TSum f_sum = (TSum)sum;

    f_con();    //Here I got access violation exception
    printf("Sum is:%d¥n", f_sum(1,2));

    return 0;
}

If MyClass only has the Sum() function, no constructor, no member like a and b, the Sum() function can be called without problem, I tested this with VS2017.

But when the class has constructor and members, the memory access violation happens.

I guess this is maybe MyClass should be initialized first, so I tried to call the constructor, that's why I added f_con, but f_con got the same access violation problem.

What the clients asked, is we only have the dll files to import class.

As I know, there are few ways to import class from other dlls by include their headers. Because at least we need the declaration of class which we want to import.

Is there something I can do to get Sum() work?


Solution

  • I found what I need here.

    As I tested, use the inline assembler syntax will solve my problem:

    __asm {MOV ECX, p};  //p points to a malloc area for instance.
    

    Now I can associate the INSTANCE of that class for the constructor.

    Because in EXE side I have to do everything myself, so I need to use that assembler syntax everytime I want to call a function of that class. Like this:

    ...
        __asm {MOV ECX, p};  //move instance's address into the ECX register
        f_con();  //call constructor
        __asm {MOV ECX, p};  //move instance's address into the ECX register again
        int r = f_Sum(1,2);  //call member function
    ...
    

    Now I can call a class member function without any headers!