几年前我在C ++中使用旧的Win32 API编程经验,最近我参与了Delphi的开发。我立即认识到了Windows API中的许多功能(例如,CreateThread
,CreateWindowEx
等等。)
我发现Embarcadero的文档不完整(至少可以说),通常可以参考Microsoft网站获取文档。在哪里,我可以补充说,所有的功能都是用C语言定义的,这使得非C语言的人很难(但对我来说更容易)。
我想知道的是 - 鉴于Delphi函数签名与Microsoft提供的C函数签名相同 - 调用Delphi Windows API函数立即调用Windows API函数,或者它是否调用相同的Delphi函数,然后调用Windows API函数并返回结果,前者意味着与相应的C代码相比没有可区别的性能差异,而后者意味着某些性能罚?
答案 0 :(得分:20)
阅读来源。在CreateWindowEx
单元中定义了对Windows.pas
的调用,作为CreateWindowExW
中User32.DLL
函数的直接调用(来自XE5的来源 - 在所有版本的Delphi中都可以找到类似的定义对于支持的操作系统版本):
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';
所以你的具体问题的答案是否定的。没有性能损失。在Delphi中调用WinAPI函数不会导致性能损失。
答案 1 :(得分:9)
对Delphi Windows API函数的调用是否会立即调用Windows API函数?
不是没有。
为了论证,我们考虑调用CloseHandle
。这是在Windows
单元中声明的,并使用external
实现。当你调用它时,实际上你会在CloseHandle
单元中调用一个名为Windows
的函数。所以在伪汇编程序中它看起来像这样:
.... prepare parameters
CALL Windows.CloseHandle
然后,Windows.CloseHandle
实现如下:
JMP kernel32.CloseHandle
因此,与直接调用相比,调用thunk函数,然后跳转到Win32 DLL。这被称为蹦床。
可以采用不同的方式实施。编译器可以发出代码直接调用Win32 DLL。一些编译器会这样做。例如,MSVC发出的此调用的等效asm将是:
CALL DWORD PTR [__imp__CloseHandle@4]
此处,__imp__CloseHandle@4
是内存中包含Windows DLL中CloseHandle
地址的位置的地址。加载程序在加载时将CloseHandle
的实际地址写入__imp__CloseHandle@4
。
哪个效率更高?没有剖析,不可能肯定地说。但我相信,在极少数情况下,任何差异都会很大。
当然,也可以生成直接调用而没有间接调用的代码。这将涉及加载器补丁每次调用该函数。这可能是一个坏主意,但是因为它会导致大量的加载时间修复,这将是启动时的性能问题。也就是说,它与需要在加载时重新定位的DLL几乎相同。无论如何,我知道没有采用这一政策的工具链。
也许你关心的是这些函数是否是真正的Win32函数。或者它们周围是否有一层改变了意义。这些是真正的Win32功能。没有Delphi文档,因为它们是Win32函数。 MSDN上的Win32文档是文档的权威来源。
正如许多人所说,Win32函数被调用而没有中间层。因此,在这些意义上直接调用它们将您的参数未经修改地传递给API函数。但是呼叫机制是间接的,因为它使用蹦床。语义上没有区别。