从 Delphi 调用特定的 Win32 API - 为什么异常会在没有 "asm pop..."的情况下出现?

标签 c delphi winapi assembly xll

我正在使用 Delphi 为 Excel 制作一个 XLL 加载项,其中涉及对 Excel4v 进行大量调用xlcall32.dll 的功能。但是,我猜这里很少有 Delphi 专家使用过那个特定的 API,我希望在其他 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 代码调用该函数会导致异常(“访问冲突...”是我一直看到的)除非它们后跟以下行:

asm pop sink; end;

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

我对汇编一无所知……所以我没有办法尝试用“asm pop sink;end;”修复异常。但是“asm pop sink; end;”确实修复了异常。我第一次看到它用于 this useful article on making XLLs using Delphi .这是最相关的引述:

"From Delphi the big stumbling block with add-ins is the extra parameter after the return address on the stack. This comes free with every call to Excel. I’ve never found out what it holds, but so long as you throw it away, your add-in will work fine. Add the line asm pop variable, end; after every call where variable can be any global, local or object variable that is at least 4 bytes long- integer is fine. To repeat- THIS MUST BE INCLUDED after every Excel4v call. Otherwise you are constructing a time-bomb."

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

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

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

最佳答案

我不认为这是 pascal 与 stdcall - 它们是非常相似的调用约定,不应导致函数退出时堆栈不匹配。

来自引用的 article ,

This would indeed be a very nice syntax, but it is not the same as the above array definition. Array-of parameters are open array parameters. They may look like any array, and they do accept any array, but they get an extra (hidden) parameter, which holds the highest index in the array (the High value). Since this is only so in Delphi, and not in C or C++, you'd have a real problem. (See also my article on open arrays), since the real number of parameters wouldn't match.

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

类似于:

type
 PLPXLOPER  = ^LPXLOPER;

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

关于从 Delphi 调用特定的 Win32 API - 为什么异常会在没有 "asm pop..."的情况下出现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1093206/

相关文章:

C Eclipse 语义错误?

c++ - WinAPI - 从 DLL 加载资源

c++ - TerminateThread() with CloseHandle() on thread which uses only stack plain variables (without alloc) 泄漏内存?

c - 使用 char 和 int 访问内存映射寄存器的区别

c - Linux | C 中的 Shell 实现 |重定向文件包括提示

c - 引导跨平台编译器

delphi - TIdTCPClient 到 SSL

delphi - 如何将 record 类型的记录添加到 TList<> 中?

delphi - Robert Giesecke 的非托管导出和 Visual Studio 2015 构建错误

c++ - 通过 recv-hook 中的 SOCKET-identifier 获取远程地址