我正在使用Delphi为Excel制作XLL加载项,这涉及对xlcall32.dll的Excel4v函数进行大量调用 . 但是,正如我希望在其他API中也可能出现这个问题一样 .
在C中,特别是在Microsoft Excel 2007 XLL SDK附带的xlcall.h文件中,Excel4v定义为:
int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);
在Delphi我正在使用:
function Excel4v(xlfn: Integer; operRes: LPXLOPER; count: Integer;
opers: array of LPXLOPER): Integer; stdcall; external 'xlcall32.dll';
LPXLOPER是指向结构(在C中)或记录(在Delphi中)的指针 .
我一直在做我的功课,在Delphi中声明C函数(this excellent article是一个很好的帮助),我想我正在宣布Excel4v . 但是,从Delphi代码调用该函数会导致异常("access violation..."是我一直看到的),除非后面跟着以下行:
asm pop sink; end;
其中“sink”在某处定义为整数 .
我对组装没有任何线索......所以我没想办法尝试用"asm pop sink; end;"修复异常 . 但"asm pop sink; end;"确实解决了异常问题 . 我第一次看到它在this useful article on making XLLs using Delphi中使用过 . 这是最相关的报价:
“从Delphi中,带有加载项的大绊脚石是堆栈上返回地址之后的额外参数 . 每次调用Excel都可以免费使用 . 我从来没有发现它拥有什么,但只要你抛出它离开,你的加载项工作正常 . 添加行asm pop变量,结束;在每次调用之后,变量可以是任何至少4个字节长的全局,局部或对象变量 - 整数就好了 . 重复 - 这必须在每次Excel4v通话后都包括在内 . 否则你正在制造定时炸弹 . “
基本上 I want to understand what's actually happening, and why . 什么可能导致Win32函数返回"extra parameter after the return address on the stack",这实际上是什么意思?
可能有另一种解决方法,例如使用不同的编译器选项或声明函数的不同方式?
并且有什么风险可以称为“asm pop sink; end;”每次调用Excel4v后......?它看起来工作正常,但是,由于我不明白发生了什么,感觉有点危险......
3 回答
我不相信它是pascal vs stdcall - 它们是非常相似的调用约定,不应该在函数退出时导致不匹配的堆栈 .
从引用的article开始,
您将获得传递给函数的额外“最高数组索引”参数 . 这是一个int,当函数退出时必须清理它,这样你就不会遇到损坏的堆栈并崩溃 . 本文指出如何将数组传递给C函数 .
就像是:
并将PLPXLOPER作为最后一个参数传递 .
大多数Windows函数使用__stdcall作为calling conventions .
你的调用约定是错误的,特别是“stdcall” . C声明被指定为“pascal”
Stdcall以从右到左的顺序传递参数,期望例程清理,并且不使用寄存器 . Pascal,OTOH按从左到右的顺序传递参数 . 因此,在任何一种情况下,事情都不会像另一半代码所期望的那样发生 .
将您的Delphi声明更改为“pascal”而不是“stdcall” .