通过Delphi访问Windows API会有性能损失吗?

时间:2014-02-28 06:25:30

标签: c++ delphi winapi

几年前我在C ++中使用旧的Win32 API编程经验,最近我参与了Delphi的开发。我立即认识到了Windows API中的许多功能(例如,CreateThreadCreateWindowEx等等。)

我发现Embarcadero的文档不完整(至少可以说),通常可以参考Microsoft网站获取文档。在哪里,我可以补充说,所有的功能都是用C语言定义的,这使得非C语言的人很难(但对我来说更容易)。

我想知道的是 - 鉴于Delphi函数签名与Microsoft提供的C函数签名相同 - 调用Delphi Windows API函数立即调用Windows API函数,或者它是否调用相同的Delphi函数,然后调用Windows API函数并返回结果,前者意味着与相应的C代码相比没有可区别的性能差异,而后者意味着某些性能罚?

2 个答案:

答案 0 :(得分:20)

阅读来源。在CreateWindowEx单元中定义了对Windows.pas的调用,作为CreateWindowExWUser32.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函数。但是呼叫机制是间接的,因为它使用蹦床。语义上没有区别。