Testing this code:
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.
What will happen if we dropped the stdcall
in 32 bit or 64 bit ?
The answer is , the value $18f2dc
passed into x
. If its a string, it will point to position of $18f2dc
,and try to extract the string garbage from there.
This happens because Delphi just pass Pointer(s)
in the code.
It could changed from run to run and not be $18f2dc
, but its a 3 byte that are passed. (if you pass int its $18f2dc
in decimal 1635036).
Does this number has a unique meaning?
Why is stdcall
needed?
What will happen if we dropped the stdcall in 32 bit?
When no calling convention is specified, then the default of register
is used. Since this does not match the true calling convention, then garbage will be passed in the parameters.
In this particular case, the function that you call expects the parameters to be passed on the stack. The function will therefore read an integer from the stack. On the other hand, the calling code assumes register
calling convention and puts the argument in the EAX
register. Because the calling code did not push the argument onto the stack, the function gets what just happens to be on the stack when the function is called.
To be honest, there's not really much point in trying to reasons about 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(Interoperability - property of a product or system, whose interfaces are completely understood, to work with other products or systems) boundary, and that's really little different from using the wrong calling convention. With binary interop you just have to make sure that everything is matching: argument types, return value types, function names, calling convention, the values passed to the function, etc.
What will happen if we dropped the stdcall in 64 bit?
There is a single calling convention for the Windows x64 platform. The calling convention directives are ignored by the compiler.
Although the 64 bit compiler ignores these directives it is still good practise to include them. That way your code will work when you compile it for 32 bit.