这些Windows API签名在Delphi中有何区别?

5

在Delphi中查看Windows.pas文件时,我发现有几个签名,如LoadLibrary (A) or (W)用于加载特定模块。它们之间有什么区别,我能相信始终调用LoadLibrary来适用于所有类型的Windows平台吗?


简而言之,Delphi中的LoadLibrary和LoadLibraryW签名有什么区别? - Caitano Oliveira
我能理解为什么会有人踩,但我不明白问题的表述为何不清晰。已更新标题以反映所提问的问题。 - Jerry Dodge
2
@JerryDodge 这次修改让问题更好了。我已经投票重新开放这个问题。如果你也觉得你的编辑已经充分改进了问题,那么你也可以这样做。 - J...
2个回答

13
Windows API 提供 ANSI 字符串 (A) 或 Unicode 字符串 (W)。在内部,Windows API 两种字符串都可用。然而,Delphi 默认使用其中一种,这取决于 Delphi 版本。许多其他 Windows 语言也是如此。该语言将 ANSI 或 Unicode 字符串用作默认值。
在 Delphi 2009 之前的版本中,使用带有 A 后缀的 ANSI API 调用,因为当时 Delphi 主要使用 ANSI 字符串。从 Delphi 2009 开始,Unicode 已被强制执行。这也使默认的 API 调用变为 Unicode,使用 W 作为后缀。在 Delphi 中一直支持 Unicode,但自 2009 年以来,它已被强制执行为默认值,优先于 ANSI。在那些旧版本中,诸如 LoadLibrary 的函数映射到 ANSI 版本的 LoadLibraryA
你所提到的特定API调用 LoadLibrary 可作为 LoadLibraryA LoadLibraryW 使用。 Windows.h 还提供了一个通用的 LoadLibrary 函数,它在内部使用首选的Unicode版本。 A W 之间的区别为开发人员提供了向后兼容的选项,与Microsoft的许多产品一样。如果语言主要是ANSI字符串,则可以明确使用Unicode。或者,如果语言主要是Unicode,则可以明确使用ANSI。

长话短说,在某个时候,Windows本身从ANSI字符串切换到Unicode字符串作为默认设置。但仍提供向后兼容性。稍后的Delphi版本已更改为使用首选默认设置-在这种情况下,它们是Unicode。

总结一下:

  • LoadLibraryA-通过ANSI字符串加载库
  • LoadLibraryW-通过Unicode字符串加载库
  • LoadLibrary-使用首选默认值(Unicode字符串)加载库
  • 古老的Windows版本在引入Unicode之前仅使用ANSI字符串
  • Windows通过默认使用ANSI版本来提供向后兼容性-但最终将默认设置切换为Unicode(不确定是哪个版本)

您可以在这里了解更多有关微软介绍Unicode的信息,以及此处


32位和64位通常由完全不同的库副本组成,为每个平台编译 - 它们以完全相同的方式工作。但是这是一个完全不同的故事。 - Jerry Dodge
@Rob 说实话,我感觉我的整个回答都有点不稳定 :-/ 但是在 Delphi XE8 中查看 Winapi.Windows 时,我没有看到我实际期望的映射 - 它是直接的... 当查看 WinAPI 文档时,它解释说有一个通用版本可用:https://msdn.microsoft.com/en-us/library/windows/desktop/dd374089(v=vs.85).aspx - Jerry Dodge
它是通过windows.h中的宏“available”实现的,而不是操作系统中存在的任何内容。在C程序中放入 #define UNICODE 便可以将通用函数变为W函数,否则它们将为A函数。Delphi不支持这种条件编译,因此映射基于Delphi版本设置。如果在Windows.pas中找不到通用的 LoadLibrary ,请检查一些其他单位。 - Rob Kennedy
@Rob 我明白了,我习惯于只引用 Winapi.Windows 中 Pascal 告诉我的内容。所以这一切都与 Delphi 在后台导入 Windows API 的方式有关。 - Jerry Dodge
没错,@Arioch。我谨慎选择了我的措辞:它不支持那种条件编译。特别是,那种与手头讨论相关的条件编译。 - Rob Kennedy
显示剩余5条评论

7
为什么在Delphi XE2中有LoadLibrary和LoadLibraryW两个API,而它们在Windows中是相同的API?
为了兼容Win32 API、各种教程/示例以及Delphi的Ansi和Unicode版本。
Win32 API只定义了LoadLibraryA()(Ansi)和LoadLibraryW()(Unicode)作为实际函数(从kernel32.dll导出)。LoadLibrary()根本不是一个函数,它是一个预处理器宏(在winbase.h中定义),根据项目是否配置为编译Ansi或Unicode环境来映射到LoadLibraryA()或LoadLibraryW()。
#ifdef UNICODE
#define LoadLibrary  LoadLibraryW
#else
#define LoadLibrary  LoadLibraryA
#endif

当C/C++应用程序使用基于TCHAR的字符串调用通用的LoadLibrary()“函数”时,只需更改项目设置而不是更改源代码,即可为任一环境编译和链接该应用程序。例如:
HMODULE hLib = LoadLibrary(TEXT("filename"));
// calls either LoadLibraryA("filename") or LoadLibraryW(L"filename")
// depending on whether UNICODE is defined while compiling...

另一方面,Delphi不支持“.h”文件,因此无法利用Microsoft现有的所有函数声明。所有库函数和数据类型都必须在Pascal中重新声明(这就是为什么存在“Windows”单元和其他相关单元以供使用Win32 API)。对于LoadLibrary()函数,在Delphi中的所有版本都将LoadLibraryA()和LoadLibraryW()声明为从kernel32.dll导入的实际函数,并分别使用PAnsiChar和PWideChar参数。
function LoadLibraryA(const lpFileName: PAnsiChar): HMODULE; stdcall; external kernel32 name 'LoadLibraryA';
function LoadLibraryW(const lpFileName: PWideChar): HMODULE; stdcall; external kernel32 name 'LoadLibraryW';

Delphi不支持预处理宏,因此将LoadLibrary()声明为导入与Delphi的通用PChar类型匹配的任何DLL函数的函数。 因此,在Delphi 2007及之前,其中PCharPAnsiCharLoadLibrary()被声明为导入LoadLibraryA(),并且在Delphi 2009及以后,其中PCharPWideCharLoadLibrary()被声明为导入LoadLibraryW()

// Delphi 2007 and earlier...
function LoadLibrary(const lpFileName: PChar): HMODULE; stdcall; external kernel32 name 'LoadLibraryA';

// Delphi 2009 and later...
function LoadLibrary(const lpFileName: PChar): HMODULE; stdcall; external kernel32 name 'LoadLibraryW';

当一个Delphi应用程序使用PChar来调用通用的LoadLibrary()函数时,它可以在多个版本的Delphi中编译而无需更改源代码。
hLib := LoadLibrary(PChar(filename));
// calls either LoadLibraryA(PAnsiChar(filename) or LoadLibraryW(PWideChar(filename))
// depending on whether Delphi natively uses Ansi or Unicode strings...

这些因素适用于任何TCHAR基于API,不仅限于特定的LoadLibrary()。当给定的Win32 API支持AW版本时,MSDN会以其通用的TCHAR版本来记录它。请记住,Win32 API早于Unicode,而TCHAR是Microsoft在Windows NT首次引入Unicode API时迁移开发人员从Ansi API到Unicode API的解决方案,同时仍允许开发人员支持较早的Windows版本。为了向后兼容传统应用程序,现代Windows版本中仍支持现有的Ansi API,尽管已被放弃,推荐使用Unicode API。新引入的API倾向于只支持Unicode。


从技术上讲,TCHAR 是 C++ 运行时的一部分,而不是 Win32。 - David Heffernan
@DavidHeffernan:实际上,它根本不是 C++ 的一部分。你可能在想 C 运行时库中的 _TCHARTCHAR 是 Win32 的等效物。 - Remy Lebeau
显然,它不是C++或C的一部分,这些都是标准化的语言/库,不能定义仅在Windows上有意义的类型。我肯定从未说过TCHAR是C++的一部分。它是库的一部分,这就是我所说的。我应该说“MS C++运行时”。TCHAR由MSVC运行时库在tchar.h头文件中定义。但是,MS通过在winnt.h中再次定义它来混淆问题。唉。我认为TCHAR是MSVC库。我本应该什么也不说。对不起。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接