提问人:hzh 提问时间:1/19/2023 最后编辑:hzh 更新时间:1/21/2023 访问量:343
如何在通过 LoadLibrary() 加载的 DLL 中初始化 C++ 类?
How to initialize a C++ class inside a DLL which was loaded via LoadLibrary()?
问:
我从客户那里得到了一个问题。
他们从他们的产品中删除了一些 VC++ 项目,只有 dll。
现在,他们希望使用这些dll中的一些函数处理一些数据。
假设这是 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;
}
而且,这是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;
}
如果 MyClass 只有 Sum() 函数,没有构造函数,没有像 a 和 b 这样的成员,那么可以毫无问题地调用 Sum() 函数,我用 VS2017 对此进行了测试。
但是,当类具有构造函数和成员时,就会发生内存访问冲突。
我想这也许是应该首先初始化 MyClass,所以我尝试调用构造函数,这就是我添加f_con的原因,但f_con遇到了同样的访问冲突问题。
客户问的是,我们只有导入类的dll文件。
据我所知,有几种方法可以通过包含它们的标头从其他dll导入类。因为至少我们需要我们想要导入的类的声明。
我能做些什么来让 Sum() 工作吗?
答:
我感觉你错过了什么。所有那些在入口点上乱搞的东西都不应该是必要的。除非你想把它作为一种练习来做。
当您的客户端代码也是 C++ 时,您应该能够包含类的头文件并像往常一样使用它。
但是(若要获取运行时链接),必须能够在类声明的 dllexport 和 dllimport 之间切换。编译 DLL 时必须使用 DLLexport,使用 DLL 时必须使用 DLLIMPORT。
因此,请使用 COMPILING_DLL(命令行预处理器定义)编译您的 dll 然后用它添加一个头文件,并在你的类头文件中使用它。
#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
并将类声明更改为:
class DLLEXPORT MyClass{...};
评论
我在这里找到了我需要的东西。
正如我测试的那样,使用内联汇编器语法将解决我的问题:
__asm {MOV ECX, p}; //p points to a malloc area for instance.
现在,我可以将该类的 INSTANCE 关联到构造函数。
因为在EXE端,我必须自己做所有事情,所以每次我想调用该类的函数时,我都需要使用该汇编器语法。喜欢这个:
...
__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
...
现在我可以调用没有任何标头的类成员函数了!
评论
__declspec(dllimport)