求助:Delphi编写的动态链接库在VC下调用的问题(100分)

  • 主题发起人 主题发起人 wjy2334
  • 开始时间 开始时间
W

wjy2334

Unregistered / Unconfirmed
GUEST, unregistred user!
一个用Delphi写的动态链接库,其中一个函数的声明是这样的:
ReadRegister(PraAddr:integer,PraNum:byte;var cPraVal:array of word):boolean;stdcall
我试了以下三种方法:
方法一:
typedef BOOL (_stdcall *READREGISTER)(int,BYTE,WORD (*cPraVal)[]);
READREGISTER ReadRegister=(READREGISTER)GetProcAddress(hInst,"ReadRegister");
WORD cPraVal[2];
ReadRegister(0x90,2,cPraVal);
编译时出错:error C2664: 'int (int,unsigned char,unsigned short (*)[])' : cannot convert parameter 3 from 'unsigned short [2]' to 'unsigned short (*)[]'
方法二:
typedef BOOL (_stdcall *READREGISTER)(int,BYTE,WORD* cPraVal);
后编译连接不会出错,不过在程序运行时会出现错误提示框,内容为:
The value of ESP was not properly saved across a function call.This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
方法三:
分两部分定义,先定义:
typedef WORD (*WORD_ARRAY)[]
再定义:
typedef BOOL (_stdcall *READREGISTER)(int,BYTE,WORD_ARRAY);
出现和第一种方法一样的错误
我没招了,那位兄弟帮帮我啊?谢谢了
 
哈哈,100分我的了。
经过研究,终于知道原因了。你在C++下面这样定义函数类型
typedef BOOL (__stdcall *READREGISTER)(int, BYTE, WORD*, int);
最后一个int是第三个参数数组的长度
下面是C++调用DLL函数ReadRegister的代码
HMODULE h= LoadLibrary("C://Program Files//Borland//Delphi7//Projects//project2.dll");

READREGISTER ReadRegister=(READREGISTER)GetProcAddress(h,"ReadRegister");
WORD a[100];
memset(a, 0, sizeof(a));
a[0]= 1;
a[1]= 2;
a[2]= 3;
ReadRegister(1, 2, a, sizeof(a)/sizeof(WORD));
一会我写出原因。
 
今天在DFW上面看见有一个贴子是关于VC里面调用DELPHI编写的DLL,对于VC和DELPHI有一定自信的我,当然不过这样的拿分机会了。
贴子的大概内容是这样的,在DELPHI定义了这样一个函数并输出
myfunc(i:Integer;
b:Byte;
var Buffer:array of Word): Boolean;
stdcall;
之后在VC里面定义函数类型
typedef BOOL (__stdcall *pMyfunc)(int, BYTE, WORD*);
调用代码是这样
HMODULE h= LoadLibrary("C://Program Files//Borland//Delphi7//Projects//project2.dll");
pMyfunc MyFunc=(pMyfunc)GetProcAddress(h,"myfunc");
WORD a[100];
memset(a, 0, sizeof(a));
a[0]= 1;
a[1]= 2;
a[2]= 3;
MyFunc(1, 2, a);
但是函数成功返回后却提示:
The value of ESP was not properly saved across a function call.This is usually a result of calling a function declared with
one calling convention with a function pointer declared with a different calling convention.
经过研究,得出的解决的办法就是在VC里面这样定义函数类型
typedef BOOL (__stdcall *pMyfunc)(int, BYTE, WORD*, int);
多出一个参数int是数组的大小,所以调用时就要指出数组的大小
MyFunc(1, 2, a, sizeof(a)/sizeof(WROD));

下面是研究的过程。
根据出错提示和我的破解来看,一定是调用函数后栈不平衡了。至于具体原因就要再进一步研究。
我在Delphi调用了这个函数,并没有任何问题。所以我的直觉告诉我,一定和那个数组有关,之后我拿掉那个数组参数,在VC里调用一次,结
果一切正常! 看来真的是数组参数的问题。但是为什么Delph里调用却没有问题呢?想来想去也想不出原因,看来只好在汇编里找答案了。在
Delphi里调用myfunc的地方下了断点,
{调用函数的代码}
var
aw: array[0..99] of word;
//aw: array of word;
begin
//setlength(aw, 101);
myfunc(1, 2, aw);
//这里的反汇编对应静态数组的代码
004081FA 6A63 push $63
004081FC 6898A74000 push $0040a798
00408201 6A02 push $02
00408203 6A01 push $01
00408205 E82EFFFFFF call myfunc
//这里的反汇编对应动态数组的代码
004086E4 A198A74000 mov eax,[aw]
004086E9 E812BCFFFF call @DynArrayHigh
004086EE 50 push eax
004086EF A198A74000 mov eax,[aw]
004086F4 50 push eax
004086F5 6A02 push $02
004086F7 6A01 push $01
004086F9 E8E6FEFFFF call myfunc
可以很清楚的看到,我们的函数明明只定义了3个参数,却push了4个参数!而第4个函数根据静态数组的反汇编可以看出就是数组的长度!
所以在VC的函数定义要定义多一个参数,并把数组的长度传递给函数调用才会正常!
反思:原来自己对DELPHI的内部还不是很了解,还是菜菜一名,呵呵。
 
谢谢Writer,正如你所说,问题解决了!谢谢你的帮助,太佩服你了!!
100分给你了
 

Similar threads

D
回复
0
查看
1K
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
615
import
I
I
回复
0
查看
738
import
I
后退
顶部