I've had experience programming with ye old Win32 API in C++ several years ago, and recently I've been involved in development with Delphi. I immediately recognised a lot of the functions from the Windows API (e.g., CreateThread
, CreateWindowEx
, etc, etc).
I have found Embarcadero's documentation incomplete (to say the least), and typically refer to the Microsoft website for documentation. Where, might I add, all the functions are defined in C, which makes it difficult for the non-C folk out there (but easier for me).
What I want to know is - given that the Delphi function signatures are identical to the C function signatures provided by Microsoft - does a call to the Delphi Windows API function immediately call the Windows API function, or does it call an identical Delphi function which then calls the Windows API function and returns the result, the former meaning no distinguishable difference in performance compared to the corresponding C code, while the later meaning something of a performance penalty?
Read the source. A call to CreateWindowEx
is defined in the Windows.pas
unit as a direct call to the CreateWindowExW
function in User32.DLL
(from XE5's source - similar definitions are found in all versions of Delphi for the supported OS versions):
function CreateWindowEx(dwExStyle: DWORD; lpClassName: LPCWSTR;
lpWindowName: LPCWSTR; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer;
hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND;
stdcall; external user32 name 'CreateWindowExW';
So the answer to your specific question is no. There is no performance penalty. A call to a WinAPI function in Delphi does not incur a performance hit.
Does a call to the Delphi Windows API function immediately call the Windows API function?
Not it does not.
For sake of argument let us consider a call to CloseHandle
. This is declared in the Windows
unit and implemented using external
. When you call it, you do in fact call a function named CloseHandle
in the Windows
unit. So in pseudo assembler it looks like this:
.... prepare parameters
CALL Windows.CloseHandle
Then, Windows.CloseHandle
is implemented like this:
JMP kernel32.CloseHandle
So, compared to a direct call, there is a call to a thunk function, and then a jump into the Win32 DLL. This is known as a trampoline.
It could be implemented differently. The compiler could emit code to call directly into the Win32 DLL. And some compilers will do this. For instance, the equivalent asm for this call as emitted by MSVC would be:
CALL DWORD PTR [__imp__CloseHandle@4]
Here, __imp__CloseHandle@4
is the address of a location in memory which contains the address of CloseHandle
in the Windows DLL. The loader writes the actual address of CloseHandle
into __imp__CloseHandle@4
at load time.
Which is more efficient? Impossible to say for sure without profiling. But I'm confident that any difference will be significant in a vanishingly small number of cases.
Of course it is possible also for code to be generated that would call directly with no indirection. That would involve the loader patch every call to the function. That is probably a bad idea however because it would lead to a large number of load time fixups which would be a performance issue at startup. That said, it would be pretty much the same as a DLL that needs to be relocated at load time. In any case, I know of no tool chain that adopts this policy.
Perhaps what you are concerned about is whether these functions are the real Win32 functions. Or whether there is a layer around them that changes the meaning. These are the real Win32 functions. There is no Delphi documentation because these are Win32 functions. The Win32 documentation on MSDN is the authoritative source of documentation.
As many people have said, the Win32 functions are called with no intervening layer. So they are directly called in these sense that your parameters are passed un-modified to the API functions. But the calling mechanism is indirect in the sense that it uses a trampoline. Semantically there is no difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With