使用一个VC写的DLL中的函数,返回值表明函数执行成功,但程序提示错误!

Storm2008 2009-06-01 12:15:09
VC头文件中函数原型为
int __declspec(dllexport) Load_BC_Datablk_MCH(int, usint blknum, usint wdcnt, usint *data);

调用过程为
	
WORD BCIN00[32];

BCIN00[0] =0x4004;
BCIN00[1] =0x0180;
BCIN00[2] =0;
BCIN00[3] =0;
BCIN00[4] =0;;
BCIN00[5] =0;;
BCIN00[6] =0;;

Load_BC_Datablk_MCH(m_nhandle, 1,18,BCIN00);


我转成了Delphi的
Function Load_BC_Datablk_MCH(hBus : THandle; BlkNum, wdcnt : WORD; var Data :  WORD) : Integer; stdcall; external 'MCHMS.DLL' name 'Load_BC_Datablk_MCH';


Function Load_BC_Datablk_MCH(hBus : THandle; BlkNum, wdcnt : WORD; Data : Array of WORD) : Integer; stdcall; external 'MCHMS.DLL' name 'Load_BC_Datablk_MCH';

调用过程
BCIN : Array[0..31] of WORD;

BCIN[0] := $4004;
BCIN[1] := $0180;
BCIN[2] := 0;
BCIN[3] := 0;
BCIN[4] := 0;
BCIN[5] := 0;
BCIN[6] := 0;
Load_BC_Datablk_MCH(hBus, 1, 18, BCIN);
或者
Load_BC_Datablk_MCH(hBus, 1, 18, BCIN[0]);


函数返回值都是0,表示函数成功返回了。但程序执行是总是提示Access violation,如果是单独运行编译后的程序的话,什么提示也没有,程序就直接退出了。


我想了想,问题可能是出在函数转化的地方,类型可能用得不对。请大家帮我看看,谢谢
...全文
92 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
Rex_love_Burger 2009-06-08
  • 打赏
  • 举报
回复
后来也发觉了,本想告诉你,但我已连发了3帖,发不动了,呵呵!:)
Storm2008 2009-06-07
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 extcsdn 的回复:]
说白了,你最后一个参数的含义没搞清楚!
[/Quote]

请看下原贴,我用了两种方式调用都不行


原因是没搞清楚stdcal和cdecl的区别
stdcall由被调用方清理stack,cdecl由调用方清理,调用方和被调用方没对应上的结果就是函数返回的地址跑飞了
Rex_love_Burger 2009-06-05
  • 打赏
  • 举报
回复
说白了,你最后一个参数的含义没搞清楚!
Rex_love_Burger 2009-06-05
  • 打赏
  • 举报
回复
你的BCIN[0]是第一个元素的内容,而不是这个数组的地址,远函数的这个参数实际需要的是这个数组的起始地址!!!!!
Rex_love_Burger 2009-06-05
  • 打赏
  • 举报
回复
最后一个参数类型可以用Pointer,使用时可以如下:
var
data:array[0..xxx] of Word;
begin
Load_BC_Datablk_MCH(XXX, blknum, wdcnt, @data[0]);
end;
手指风 2009-06-02
  • 打赏
  • 举报
回复
__declspec?
gyk120 2009-06-02
  • 打赏
  • 举报
回复
stdcall会在退出时清空堆栈,但是调用函数在堆栈中压入了参数占用了位置,这些位置将由调用函数负责清空。如果参数个数未知,函数在编译期就不知到底要在堆栈里清除多少个字节,这样_stdcall就不能用了,有些函数只能使用Pascal调用约定,函数不会清空堆栈,cdecl就是谁调用谁清理,恢复堆栈,可以理解成前者把破摊子丢给别人,后者自己闯的祸自己解决
starluck 2009-06-02
  • 打赏
  • 举报
回复
函数返回值都是0,表示函数成功返回了。但程序执行是总是提示Access violation,如果是单独运行编译后的程序的话,什么提示也没有,程序就直接退出了。




這個應該是調用方式的問題,可能是由於讓被調用方清理了堆栈造成的。
starluck 2009-06-02
  • 打赏
  • 举报
回复

C++中如果
WORD BCIN00[32]; 這也是DLL處的寫法


那在 Delphi 中最好 array[0..32-1] of Word ; //


sparklerl 2009-06-01
  • 打赏
  • 举报
回复
Function Load_BC_Datablk_MCH(hBus : THandle; BlkNum, wdcnt : WORD; 
Data : PWordArray) : Integer; stdcall;
external 'MCHMS.DLL' name 'Load_BC_Datablk_MCH';



Array of WORD换成 PWordArray试试


PWordArray TWordArray (declared in SysUtils). Used to typecast dynamically allocated memory for arrays of 2-byte values.

Delphi syntax:

type
PWordArray = ^TWordArray;
TWordArray = array[0..16383] of Word;

C++ syntax:

typedef Word TWordArray[16384];

Description

TWordArray declares a general array of type Word that can be used in typecasting.

Seamour 2009-06-01
  • 打赏
  • 举报
回复
array of Word这种参数类型别乱写,比一般的多压一个High(arrayVar),stdcall保证call一次挂一次
stdcall由被调用方清理stack,cdecl由调用方清理,调用方和被调用方没对应上的结果就是函数返回的地址跑飞了
Storm2008 2009-06-01
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 kampan 的回复:]
C++中的usint应该对应Delphi中的Longword,楼主最好将参数的类型保持一致。
[/Quote]

usint 是自己定义的对应 unsigned short 与 delphi 中 word类型是一致的。



[Quote=引用 2 楼 sxy_9761 的回复:]
把stdcall去掉后再试试
[/Quote]

把stdcall换成cdecl后工作正常了
应该是stdcall方式传过去的参数bcin被释放了,当再次访问该变量时出错。
具体不是太清楚,那位朋友讲讲


_cdecl:C\C++的缺省调用协议,由调用者清理堆栈,这就是C\C++中可以使用可变参数的函数的原因,所有参数自右至作入栈,生成的代码中函数名有一个_做前缀

_stdcall:Win32 API的调用协议,由被调用的函数清理堆栈,所有参数自右至左入栈,生成的代码中函数名有一个_做前缀和一个@和参数的总字节数(十进制)作后缀。它不支持可变参数,但它产生的代码比_cdecl短,因为没有每次调用后的清理堆栈的代码。



gyk120 2009-06-01
  • 打赏
  • 举报
回复
调试一下吧……参数不一致的话寄存器传值会报错的,个人比较同意3L的观点
kampan 2009-06-01
  • 打赏
  • 举报
回复
C++中的usint应该对应Delphi中的Longword,楼主最好将参数的类型保持一致。
sxy_9761 2009-06-01
  • 打赏
  • 举报
回复
把stdcall去掉后再试试

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧