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

StackOverflow https://stackoverflow.com/questions/1093206

我正在使用 Delphi 为 Excel 制作 XLL 插件,这涉及到对 Excel4v xlcall32.dll 的函数。然而,我猜这里很少有 Delphi 专家使用过该特定 API,所以我希望在其他 API 中也能观察到该问题。

在 C 中,特别是在附带的 xlcall.h 文件中 Microsoft Excel 2007 XLL SDK, ,Excel4v 定义为:

int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);

在德尔福我使用:

function Excel4v(xlfn: Integer; operRes: LPXLOPER; count: Integer;
    opers: array of LPXLOPER): Integer; stdcall; external 'xlcall32.dll';

LPXLOPER 是指向结构(在 C 中)或记录(在 Delphi 中)的指针。

我一直在做关于在 Delphi 中声明 C 函数的作业(这篇优秀的文章 是一个很大的帮助),并且我认为我正确地声明了 Excel4v。但是,从 Delphi 代码调用该函数会导致异常(我一直看到“访问冲突...”) 除非 它们后面跟着以下行:

asm pop sink; end;

其中“sink”在某处定义为整数。

我对组装一窍不通...因此,我不可能尝试用“asm pop sink; 修复异常”。结尾;”。但是“asm pop 水槽;end;”确实修复了异常。我第一次看到它用于 这篇关于使用 Delphi 制作 XLL 的有用文章. 。这是最相关的引用:

“从德尔菲(Delphi),带有附加组件的大绊脚石是堆栈返回地址之后的额外参数。这是免费的,这是免费的。我从来没有发现它拥有的内容,但是只要您将其扔掉,您的加载项就可以正常工作。添加行ASM POP变量,结束;在每个呼叫之后,变量可以是至少4个字节长整数的任何全局,本地或对象变量都可以。重复 - 每个Excel4v调用后必须包含此内容。否则,您将建造一个炸弹。”

基本上 我想了解到底发生了什么以及为什么. 。什么可能导致 Win32 函数返回“堆栈上返回地址后的额外参数”,这实际上意味着什么?

是否有另一种方法可以解决这个问题,例如使用不同的编译器选项或声明函数的不同方式?

调用“asm pop sink;”有什么风险吗?end;” 每次调用 Excel4v 后...?看起来工作正常,但是,由于我不明白发生了什么,感觉有点危险......

有帮助吗?

解决方案

我不相信这是帕斯卡尔对STDCALL - 他们是非常相似的调用约定,不应该导致对函数退出不匹配的堆栈

从引用文章

  

这确实是一个很不错的   语法,但它是不一样的   上述数组定义。阵列的   参数被公开阵列参数。   他们可能看起来像任何阵列,它们   做接受任何阵,但他们得到的   额外的(隐藏)的参数,其持有   阵列中的最高索引(   高价值)。由于这只是所以在   德尔福,而不是在C或C ++,你会   有一个真正的问题。 (另见我   文章开放数组),因为   参数实数不会   匹配。

你越来越被传递给函数的额外的“最高数组索引”参数。这是一个int,并已被清理,当函数退出,这样你就不会损坏的堆栈和崩溃收场。该文指出如何将数组传递给C函数。

是这样的:

type
 PLPXLOPER  = ^LPXLOPER;

和通过PLPXLOPER作为最后一个参数。

其他提示

大多数Windows函数使用 __stdcall 以其调用约定的。

您调用约定是错误的,特别是“STDCALL”。 C的声明被指定为“帕斯卡”

STDCALL传入从右到左的顺序参数,期望例程进行清理,并且不使用寄存器。帕斯卡,OTOH在从左到右顺序传递参数。因此,事情不会发生的代码的另一半期望在两种情况下的方式。

更改您的德尔福声明也是“帕斯卡”,而不是“STDCALL。”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top