如果您显式调用 dll,而没有在调用其 stdcall 的过程中声明,会发生什么情况;

what happens if you call dll explicit, without declaring in the procedure call its stdcall;

测试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.

如果我们在 32 位或 64 位中删除 stdcall 会发生什么?

答案是,值 f2dc 传递给 x。如果它是一个字符串,它将指向 f2dc 的位置,并尝试从那里提取字符串垃圾。 发生这种情况是因为 Delphi 只是在代码中传递了 Pointer(s)。 它可以从 运行 运行 而不是 f2dc,但它是一个传递的 3 字节。 (如果你以十进制 1635036 的形式传递它的 f2dc)。

这个数字有什么独特的含义吗? 为什么需要 stdcall

What will happen if we dropped the stdcall in 32 bit?

当没有指定调用约定时,则使用默认的register。由于这不符合真正的调用约定,那么参数中将传递垃圾。

在这种特殊情况下,您调用的函数需要在堆栈上传递参数。因此,该函数将从堆栈中读取一个整数。另一方面,调用代码采用 register 调用约定并将参数放入 EAX 寄存器中。因为调用代码没有将参数压入堆栈,所以函数在调用函数时获取恰好在堆栈上的内容。

老实说,尝试解释 ABI(Application Binary Interface - the interface between two program modules) mismatches like this. You would really try to reason about what would happen if you declared a different number of arguments on each side of the interop(互操作性 - 属性 一个产品或系统的接口完全理解的原因,与其他产品或系统一起工作并没有多大意义系统)边界,这与使用错误的调用约定确实没有什么不同。使用二进制互操作,您只需确保所有内容都匹配:参数类型、return 值类型、函数名称、调用约定、传递给函数的值等。

What will happen if we dropped the stdcall in 64 bit?

Windows x64 平台只有一个调用约定。调用约定指令被编译器忽略。

虽然 64 位编译器会忽略这些指令,但包含它们仍然是一个好习惯。这样当你为 32 位编译时你的代码将工作。