测试this代码:
procedure fii(i:integer);
var
Hbar: Thandle;
Foo: procedure (X: Integer); //i removed the stdcall here!
begin
Hbar := LoadLibrary('BAR.DLL');
if Hbar >= 32 then { success }
begin
Foo := GetProcAddress(HBar, 'FOO');
...
Foo(i); // if we debug trace this to the call of the dll we get not desired value
...
FreeLibrary(HBar);
end
else
MessageDlg('Error: could not find BAR.DLL', mtError, [mbOk], 0)
end.
如果我们将stdcall
放在32位或64位中会发生什么?
答案是,值$18f2dc
已传入x
。如果它是一个字符串,它将指向$18f2dc
的位置,并尝试从那里提取字符串垃圾。
这是因为Delphi只是在代码中传递了Pointer(s)
。
它可能会在运行之间发生变化,而不是$18f2dc
,但它会传递3个字节。 (如果你将其$18f2dc
传递给十进制1635036。
这个数字有独特的含义吗?
为什么需要stdcall
?
答案 0 :(得分:4)
如果我们将stdcall放在32位会怎么样?
如果未指定调用约定,则使用默认值register
。由于这与真正的调用约定不匹配,因此垃圾将在参数中传递。
在这种特殊情况下,您调用的函数需要在堆栈上传递参数。因此,该函数将从堆栈中读取整数。另一方面,调用代码假定register
调用约定并将参数放在EAX
寄存器中。因为调用代码没有将参数推送到堆栈中,所以函数会在调用函数时获得恰好在堆栈上的内容。
老实说,试图解释ABI(应用程序二进制接口 - 两个程序模块之间的接口)不匹配的原因并没有多大意义。如果您在interop的每一侧声明了不同数量的参数(互操作性 - 产品或系统的属性,其接口完全被理解,与其他产品一起使用),您真的会尝试推断会发生什么。系统)边界,这与使用错误的调用约定真的没什么不同。使用二进制互操作,您只需确保所有内容都匹配:参数类型,返回值类型,函数名称,调用约定,传递给函数的值等。
如果我们将stdcall丢弃在64位会发生什么?
Windows x64平台有一个调用约定。编译器会忽略调用约定指令。
尽管64位编译器忽略了这些指令,但包含它们仍然是一种好习惯。这样,当您将代码编译为32位时,您的代码就可以工作。