我的客户给我出了一个问题。
他们从他们的产品中删除了一些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
...
现在我可以调用没有任何头文件的类成员函数了!