vb调用dll问题

sunghj 2018-06-29 11:29:25
有一段vc调用dll的代码想改成vb的
vc代码如下:
unsigned char *carddata = new unsigned char[255];
memcpy(carddata, m_Floor ,255);
HINSTANCE hInstance = LoadLibrary("ICDLL.dll");
unsigned char *s = new unsigned char[255];
unsigned char st;
s[0] = '\0';
int (*f)(unsigned char *,unsigned char *) = (int (*)(unsigned char *,unsigned char *))GetProcAddress(hInstance, "MyFunc");
st = f(carddata,s);

我写的vb调用代码:
Public Declare Function MyFunc Lib "ICDLL.dll" (ByRef CardData As Byte, ByRef s As Byte) As Byte
Dim CardData As String
Dim s(0 To 255) As Byte
CardData = "1234567890ABCDEF"
Dim CD(0 To 255) As Byte
For i = 0 To Len(CardData) - 1
CD(i) = Asc(Mid(CardData, i + 1, 1))
Next i
nRet = MyFunc(CD(0), s(0))

vb执行后提示 调用约定错误!看不出是哪的问题。
...全文
363 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
如果你的代码:
nRet = MyFunc(CD(0), s(0))
后面还有其它的代码(同过程/函数中)的话,有可能因“堆栈不平衡”,造成无法预料的结果!

但如果另外写一个函数来“包装一下”:
private function MyCall(aBuffA() as byte, aBuffB() as byte) as long
MyCall = MyFunc(aBuffA(0), aBuffB(0))
end function

然后“调用”从 nRet = MyFunc(CD(0), s(0)) 改为: nRet = MyCall(CD(0), s(0))
这样,编译后运行exe,基本不会有问题。
因为编译后运行,MyCall = MyFunc(aBuffA(0), aBuffB(0)) 可以正确接收到函数返回值;
虽然“在此句执行后堆栈不平衡”,但 End Function 返回后,在“主调语句”那儿,堆栈已经“被平衡”了。
这样“本过程/函数中还有后续执行代码”,也不会有因堆栈问题引发的“不可预料的后果”。

这种方法的好处是“实现简单”,但缺点是: “如果后续执行依赖函数返回值,则不能调试运行”。
 当然,如果只是返回TURE、FALSE 的结果状态的,就无所谓了,报“调用约定错误”后,
  点“调试”,然后不管它、按你的调试需要,分别以“执行成功”或“执行失败”进行后续的执行就行了。

如果依赖函数返回值、并想“调试运行”,那么只有用我上面提到的“方法一”的接口来处理。
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
如果API函数“无参数”的话,那么StdCall 和 CDecl 调用,可以说是等价的。
有函数参数的话,那么VB6中按StdCall去调用 CDecl约定的API,
 返回后堆栈不平衡,VB6的IDE就会报“调用约定错误!”了。
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
引用 2 楼 sunghj 的回复:
[quote=引用 1 楼 Chen8013 的回复:]
VB调用dll函数,按“正常方式”只能调用StdCall的API函数。
显示“调用约定错误”,那么95%以上的可能性是那个dll函数是CDecl调用约定的。

如果要调用 CDecl编写的API:
其一是用“ChunkCode方式”来处理堆栈平衡实现CDecl调用;
其二,可以尝试一下:自己另写一个函数把这个调用语句单独包装一下,编译后运行。
  调试运行,可以点“调试”,然后看“执行结果”,当然“函数返回值”得不到;
  如果两个参数都是“输入缓冲区”的指针,那么只有运行编译后的exe。

谢谢你的答案,这个dll还有其他函数是可以正常调用的。要怎么看这个函数是哪种方式调用的?另外,vb也可以调用GetProcAddress,然后类似vc那样调用,是不是一样的结果呢?[/quote]
VB 不支持“函数指针”,GetProcAddress( ) 返回的函数地址你也没法直接用。
我说的“方法一”就是实现“类似vc那样调用”……
sunghj 2018-06-30
  • 打赏
  • 举报
回复
看来确实不是StdCall的,我把程序编译运行,就不在提示调用约定错误
sunghj 2018-06-30
  • 打赏
  • 举报
回复
引用 1 楼 Chen8013 的回复:
VB调用dll函数,按“正常方式”只能调用StdCall的API函数。
显示“调用约定错误”,那么95%以上的可能性是那个dll函数是CDecl调用约定的。

如果要调用 CDecl编写的API:
其一是用“ChunkCode方式”来处理堆栈平衡实现CDecl调用;
其二,可以尝试一下:自己另写一个函数把这个调用语句单独包装一下,编译后运行。
  调试运行,可以点“调试”,然后看“执行结果”,当然“函数返回值”得不到;
  如果两个参数都是“输入缓冲区”的指针,那么只有运行编译后的exe。

谢谢你的答案,这个dll还有其他函数是可以正常调用的。要怎么看这个函数是哪种方式调用的?另外,vb也可以调用GetProcAddress,然后类似vc那样调用,是不是一样的结果呢?
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
VB调用dll函数,按“正常方式”只能调用StdCall的API函数。
显示“调用约定错误”,那么95%以上的可能性是那个dll函数是CDecl调用约定的。

如果要调用 CDecl编写的API:
其一是用“ChunkCode方式”来处理堆栈平衡实现CDecl调用;
其二,可以尝试一下:自己另写一个函数把这个调用语句单独包装一下,编译后运行。
  调试运行,可以点“调试”,然后看“执行结果”,当然“函数返回值”得不到;
  如果两个参数都是“输入缓冲区”的指针,那么只有运行编译后的exe。
sunghj 2018-06-30
  • 打赏
  • 举报
回复
引用 9 楼 Chen8013 的回复:
调试运行时,会报“调用约定错误”,那是因为IDE下是解释执行,并且在调用API后,IDE去检测堆栈是否平衡。
发现“不平衡”就报“调用约定错误”。

并且我也给你说过,“无参数”的API,无论声明为CDecl调用,还是StdCall调用,
 都把它当成StdCall调用, 实质是一样的。

非常感谢,困扰我很久的问题,终于找到了原因。
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
调试运行时,会报“调用约定错误”,那是因为IDE下是解释执行,并且在调用API后,IDE去检测堆栈是否平衡。
发现“不平衡”就报“调用约定错误”。

并且我也给你说过,“无参数”的API,无论声明为CDecl调用,还是StdCall调用,
 都把它当成StdCall调用, 实质是一样的。
舉杯邀明月 2018-06-30
  • 打赏
  • 举报
回复
当然是。
编译后的代码中,又不会有“检测堆栈是否平衡”的代码,当然不可能存在报“调用约定错误”的事情。

如果堆栈不平衡,却偏要按“平衡”的状态去操作堆栈,结果肯定会破坏堆栈数据,后果无法预料。
sunghj 2018-06-30
  • 打赏
  • 举报
回复
引用 6 楼 Chen8013 的回复:
如果你的代码:
nRet = MyFunc(CD(0), s(0))
后面还有其它的代码(同过程/函数中)的话,有可能因“堆栈不平衡”,造成无法预料的结果!

但如果另外写一个函数来“包装一下”:
private function MyCall(aBuffA() as byte, aBuffB() as byte) as long
MyCall = MyFunc(aBuffA(0), aBuffB(0))
end function

然后“调用”从 nRet = MyFunc(CD(0), s(0)) 改为: nRet = MyCall(CD(0), s(0))
这样,编译后运行exe,基本不会有问题。
因为编译后运行,MyCall = MyFunc(aBuffA(0), aBuffB(0)) 可以正确接收到函数返回值;
虽然“在此句执行后堆栈不平衡”,但 End Function 返回后,在“主调语句”那儿,堆栈已经“被平衡”了。
这样“本过程/函数中还有后续执行代码”,也不会有因堆栈问题引发的“不可预料的后果”。

这种方法的好处是“实现简单”,但缺点是: “如果后续执行依赖函数返回值,则不能调试运行”。
 当然,如果只是返回TURE、FALSE 的结果状态的,就无所谓了,报“调用约定错误”后,
  点“调试”,然后不管它、按你的调试需要,分别以“执行成功”或“执行失败”进行后续的执行就行了。

如果依赖函数返回值、并想“调试运行”,那么只有用我上面提到的“方法一”的接口来处理。


看我理解的对不对哈,vb调用cdecl API,即使编译成exe只有没有报调用约定错误,但是已经堆栈不平衡了,所以会造成无可预料的后果,是这个意思吧。联想,到之前调用过一个dll,也是编译后执行正常,但是在后续代码回报内存溢出,而且不固定是那一段代码,应该就是你说的这个问题吧。

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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