Delphi中的这些WindowsAPI签名有什么区别?

What's the difference between these Windows API signatures in Delphi?

在 Delphi 中查看 Windows.pas,我看到有几个签名 LoadLibrary (A) or (W) 用于加载特定模块。它们之间有什么区别?我是否可以相信总是为所有类型的 Windows 平台调用 LoadLibrary?

Windows API 提供 ANSI 字符串 (A) 或 Unicode 字符串 (W)。在内部,Windows API 两者都可用。但是,Delphi 默认为其中之一,具体取决于 Delphi 的版本。许多其他 Windows 语言也这样做。该语言默认使用 ANSI 或 Unicode 字符串。

在 2009 年之前的 Delphi 版本中,使用了 ANSI API 调用,后缀为 A。那是 Delphi 主要使用 ANSI 字符串的时候。自 Delphi 2009 年及更高版本起,已强制执行 Unicode。这也对 Unicode 进行了默认 API 调用,后缀为 W。 Delphi 一直支持 Unicode,但自 2009 年起,它已作为默认设置强制执行,优于 ANSI。在那些旧版本中,LoadLibrary 等函数映射到 ANSI 版本 LoadLibraryA.

您所指的特定 API 调用 LoadLibrary 可作为 LoadLibraryALoadLibraryW 使用。 Windows.h 还提供了一个通用的 LoadLibrary 函数,它在内部使用首选的 Unicode 版本。 AW 的区别为开发人员提供了向后兼容的选项,就像 Microsoft 的许多产品一样。如果语言主要是 ANSI 字符串,您可以明确使用 Unicode。或者,如果语言主要是 Unicode,您可以明确使用 ANSI。

长话短说,在某一时刻,Windows 本身默认从 ANSI 字符串切换到 Unicode 字符串。但是仍然提供向后兼容性。后来的 Delphi 版本已更改为使用首选默认值 - 在本例中它们是 Unicode。

总结一下:

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

您可以了解有关 Microsoft's introduction of Unicode here as well as here 的更多信息。

why there is in Delphi XE2 LoadLibrary and LoadLibraryW when they are the same api in Windows?

为了与 Win32 API 和各种 tutorials/examples 兼容,以及为了与 Delphi.

的 Ansi 和 Unicode 版本兼容

Win32 API 仅将 LoadLibraryA() (Ansi) 和 LoadLibraryW() (Unicode) 定义为实际函数(从 kernel32.dll 导出)。 LoadLibrary() 根本不是函数,它是映射到 LoadLibraryA() 或 [=17= 的 预处理器宏 (在 winbase.h 中定义) ],基于项目是否配置为针对 Ansi 或 Unicode 环境进行编译:

#ifdef UNICODE
#define LoadLibrary  LoadLibraryW
#else
#define LoadLibrary  LoadLibraryA
#endif

当 C/C++ 应用程序使用基于 TCHAR 的字符串调用通用 LoadLibrary() "function" 时,可以通过只需更改项目设置而不是更改源代码,例如:

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 导入的真实函数,使用 [=30] =]和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-based API,而不仅仅是 LoadLibrary()。当给定的 Win32 API 支持 AW 版本时,MSDN 根据其通用 TCHAR 版本对其进行记录。请记住,Win32 API 早于 Unicode,而 TCHAR 是 Microsoft 将开发人员从 Ansi APIs 迁移到 Unicode APIs 的解决方案,当时它们是在 Windows 中首次引入的] NT,同时仍然允许开发人员支持更早的 Windows 版本。为了与遗留应用程序向后兼容,那些现有的 Ansi APIs 在现代 Windows 版本中仍然受支持,尽管不赞成使用 Unicode APIs。引入的新 API 倾向于仅支持 Unicode。