从 Delphi 调用特定的 Win32 API - 为什么异常会在没有“asm pop…”的情况下发生?
题
我正在使用 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作为最后一个参数。