如果您显式调用 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 位编译时你的代码将工作。
测试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 位编译时你的代码将工作。