Search code examples
delphidlldelphi-xe7

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


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?


Solution

  • 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.