spiderman's 点滴(1)

来源:互联网 发布:java object() 编辑:程序博客网 时间:2024/05/18 13:24

从dll中加载函数, 惨痛的教训啊, 还差点去问别人, 是不是你的DLL弄错了

 

 

-----------------------------------------------------------------------------

使用Win32::API时需要注意的基本上就3点:
1、DLL中函数的calling convention必须为__stdcall型。这个应该是Win32::API的底层库中引入的一个假设,和Perl没关系;如果你用XS自己写DLL的调用过程,自然可以根据DLL中特定的calling convention自行调整调用方法,这一限制也就不复存在了。
2、导入DLL中的函数时要保证函数标识符的正确性。之所以要提这一点是因为在不使用definition file的情况下,不同的编译器在产生DLL时对导出函数名的处理方法不一样。以VC6为例,当调用规范为__cdecl时,函数func将被改名为_func;调用规范为__stdcall时,函数func被改名为_func@n,其中n是函数参数的总字节数。因此在导入函数之前最好用dumpbin之类的工具看一下DLL导出函数的真正标识符,必须用这种name mangling之后的标识符才能正常导入函数。为了避免这种麻烦,在写DLL的时候尽量用definition file指定每个函数生成的标识符吧。
3、用给出函数原型的方法导入函数时表示指针的*号一定要和类型紧挨着,另外这时对于指针类型的参数不需要自己pack数据了。例如:
假设test.dll中有一个函数long func(long *a),则
use Win32::API;
$handle=Win32::API->new('test','long func(long* a)'); # 这里指针符号*和指向的类型必须紧挨着,
# 这是由Win32::API解析原型的方法决定的。
$a=10; # 注意:不需要pack了!Win32::API会自动根据函数原型pack数据
$handle->Call($a);
不使用原型时,由于指针指向的对象类型未知,Win32::API无法知道如何处理这种数据,就必须手工将数据pack到标量中去。
$handle=Win32::API->new('test','func','P','N');
$a=pack('L',10);
$handle->Call($a);                                                                             【网摘】

--------------------------------------------------------------------

 

对以上3点中的第2点, 我刻骨铭心啊, 以后不敢弱弱的直接拿函数名去getprocaddress了, 其余两点等撞墙后顿悟。

 

补充:

       dumpbin -export xxxx.dll > xxxx.def