如果你明确调用dll会发生什么,而不在程序中声明它的stdcall;

时间:2016-01-07 15:15:15

标签: delphi dll delphi-xe7

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

1 个答案:

答案 0 :(得分:4)

  

如果我们将stdcall放在32位会怎么样?

如果未指定调用约定,则使用默认值register。由于这与真正的调用约定不匹配,因此垃圾将在参数中传递。

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

老实说,试图解释ABI(应用程序二进制接口 - 两个程序模块之间的接口)不匹配的原因并没有多大意义。如果您在interop的每一侧声明了不同数量的参数(互操作性 - 产品或系统的属性,其接口完全被理解,与其他产品一起使用),您真的会尝试推断会发生什么。系统)边界,这与使用错误的调用约定真的没什么不同。使用二进制互操作,您只需确保所有内容都匹配:参数类型,返回值类型,函数名称,调用约定,传递给函数的值等。

  

如果我们将stdcall丢弃在64位会发生什么?

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

尽管64位编译器忽略了这些指令,但包含它们仍然是一种好习惯。这样,当您将代码编译为32位时,您的代码就可以工作。