首页 文章

从Delphi调用特定的Win32 API - 为什么异常会在没有“asm pop ...”的情况下飞行?

提问于
浏览
6

我正在使用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 回答

  • 0

    我不相信它是pascal vs stdcall - 它们是非常相似的调用约定,不应该在函数退出时导致不匹配的堆栈 .

    从引用的article开始,

    这确实是一个非常好的语法,但它与上面的数组定义不同 . 数组参数是开放数组参数 . 它们可能看起来像任何数组,并且它们接受任何数组,但它们会获得一个额外的(隐藏)参数,该参数保存数组中的最高索引(高值) . 因为这只是在Delphi中,而不是在C或C中,所以你会遇到一个真正的问题 . (另请参阅我关于开放数组的文章),因为参数的实际数量不匹配 .

    您将获得传递给函数的额外“最高数组索引”参数 . 这是一个int,当函数退出时必须清理它,这样你就不会遇到损坏的堆栈并崩溃 . 本文指出如何将数组传递给C函数 .

    就像是:

    type
     PLPXLOPER  = ^LPXLOPER;
    

    并将PLPXLOPER作为最后一个参数传递 .

  • 0

    大多数Windows函数使用__stdcall作为calling conventions .

  • 8

    你的调用约定是错误的,特别是“stdcall” . C声明被指定为“pascal”

    Stdcall以从右到左的顺序传递参数,期望例程清理,并且不使用寄存器 . Pascal,OTOH按从左到右的顺序传递参数 . 因此,在任何一种情况下,事情都不会像另一半代码所期望的那样发生 .

    将您的Delphi声明更改为“pascal”而不是“stdcall” .

相关问题