Monday, 27 January 2014

Calling Conventions in Delphi: safecall vs stdcall vs cdecl

Calling Conventions in Delphi: safecall vs stdcall vs cdecl

Calling conventions in Delphi determine the order in which parameters are passed to the routine. Calling conventions also affect the removal of parameters from the stack, the use of registers for passing parameters, and error and exception handling. 

Calling Conventions in Delphi

One of the most common operations in the processing of code is calling a subroutine that carries out a given task. In order to do that, the main code needs to hand over control to the subroutine, allow the subroutine to execute, and then return to where it left the main execution path. This process requires agreement between the caller and the callee about how to pass information to the subroutine, how to return results where applicable and who is responsible for the memory allocation and cleanup. Various conventions exist to deal with invoking subroutines, commonly known as calling conventions.

Calling conventions in Delphi define a number of different aspects of subroutine invokation:

1. Where parameters are located: in registers or on the stack
2. In which order parameters are passed: right-to-left or left-to-right
3. Who is responsible for cleaning up the parameters afterwards, the caller or the callee

Various calling conventions in Delphi are register, pascal, cdecl, stdcall, and safecall. The default calling convention is register.

The register and pascal conventions pass parameters from left to right; that is, the leftmost parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last. The cdecl, stdcall, and safecall conventions pass parameters from right to left.

For all conventions except cdecl, the procedure or function removes parameters from the stack upon returning. With the cdecl convention, the caller removes parameters from the stack when the call returns.

The register convention uses up to three CPU registers to pass parameters, while the other conventions pass all parameters on the stack.

The safecall convention implements COM error and exception handling.

The default register convention is the most efficient, since it usually avoids creation of a stack frame (Access methods for published properties must use register). The cdecl convention is useful when you call functions from DLLs written in C or C++, while stdcall and safecall are used for Windows API calls. The safecall convention must be used for declaring dual-interface methods. The pascal convention is maintained for backward compatibility. 

Difference between Safecall and Stdcall calling conventions in Delphi

In Delphi, the safecall calling convention encapsulates COM (Component Object Model) error handling, thus exceptions aren't leaked out to the caller, but are reported in the HRESULT return value, as required by COM/OLE. When calling a safecall function from Delphi code, Delphi also automatically checks the returned HRESULT and raises an exception if necessary.

Safecall implements exception 'firewalls'; especially on Win32, this implements interprocess COM error notification. It would otherwise be identical to stdcall (the other calling convention used with the win api)

The safecall calling convention is the same as the stdcall calling convention, except that exceptions are passed back to the caller in EAX as a HResult, while the function result is passed by reference on the stack as though it were a final "out" parameter. When calling a Delphi function from Delphi this calling convention will appear just like any other calling convention, because although exceptions are passed back in EAX, they are automatically converted back to proper exceptions by the caller. When using COM objects created in other languages, the HResults will be automatically raised as exceptions, and the result for Get functions is in the result rather than a parameter. When creating COM objects in Delphi with safecall, there is no need to worry about HResults, as exceptions can be raised as normal but will be seen as HResults in other languages.

function function_name(a: DWORD): DWORD; safecall;

Returns a result and raises exceptions like a normal Delphi function, but it passes values and exceptions as though it was:

function function_name(a: DWORD; out Result: DWORD): HResult; stdcall;

SafeCall function mapping determines which functions are declared as safecall when declarations specified in Delphi are converted to Restricted Interface Definition Language (RIDL) in the generated type library. Safecall functions automatically implement COM conventions for errors and exception handling, converting HRESULT error codes into exceptions. If you are entering function declarations in RIDL, you must explicitly specify the calling convention as safecall or stdcall.

Difference between stdcall and cdecl calling convention

cdecl and __stdcall just tells the compiler whether the called function or the calling function cleans up the stack. In __stdcall calling convention, the called function cleans up the stack when it is about to return. So if it is called in a bunch of different places, all of those calls do not need to extra code to clean up the stack after the function call.

In __cdecl calling convention, it is the caller function that is responsible for cleaning the stack, so every function call must also need to include extra code to clean up the stack after the function call.

Default Calling Convention for C programmes

The __cdecl is the default calling convention for C programs. In this calling convention, the stack is cleaned up by the caller. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code.

Default Calling Convention for Windows Programmes

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack. Functions that use this calling convention require a function prototype.

return-type __stdcall function-name[(argument-list)]

No comments:

Post a Comment