我在 Windows 7 机器上运行 Delphi XE4。我想要一个可以识别是使用 CSIDL 还是 KNOWFOLDERID 的代码库。
有没有办法使用 {$IFDEF XXXXXX) 有条件地编译uses部分中的不同文件并调用基于Windows XP或更低版本的不同函数?
我在 Windows 7 机器上运行 Delphi XE4。我想要一个可以识别是使用 CSIDL 还是 KNOWFOLDERID 的代码库。
有没有办法使用 {$IFDEF XXXXXX) 有条件地编译uses部分中的不同文件并调用基于Windows XP或更低版本的不同函数?
您很可能不想为此使用条件编译。这样做会迫使您为不同版本的操作系统提供不同的可执行文件。这造成了沉重的安装复杂性。
处理这种情况的常用方法是使用运行时分支而不是条件编译。所以你会写这样的代码:
if IsWindowsVistaOrGreater then
DoKnownFolderIDVersion
else
DoCSIDLVersion;
至关重要的一件事是,您必须将这些 if 语句保持在尽可能低的水平。您必须对高级代码隐藏这些细节。从高级代码的角度来看,它必须询问特定文件夹的位置。高级代码不得包含任何基于版本的分支。
复杂之处在于,您不能对使用旧支持平台上可能不存在的 API 函数的分支使用加载时间链接。因此,不要使用加载时链接,而是使用运行时链接。有很多不同的方法可以实现这一点,但是对于系统 API,使用现代版本的 Delphi,延迟加载是一个很好的选择。
就个人而言,即使是现在,我也不反对使用基于 CSIDL 的 API,因为我个人认为 MS 不会很快删除该功能。但是,是否使用 CSIDL 显然是你的决定。我当然可以理解不再使用这些 API 的愿望。很明显,Microsoft 不希望您这样做。
如果您想检查 Windows 版本支持,那么您应该使用新版本的帮助程序 API。我现在知道它们已包含在 Delphi 附带的 Windows 单元中。也许它们是最新的,但您可能有一个没有它们的版本。在这种情况下,您可以使用这些:
function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion, wServicePackMajor: Word): Boolean;
function IsWindowsXPOrGreater: Boolean;
function IsWindowsXPSP1OrGreater: Boolean;
function IsWindowsXPSP2OrGreater: Boolean;
function IsWindowsXPSP3OrGreater: Boolean;
function IsWindowsVistaOrGreater: Boolean;
function IsWindowsVistaSP1OrGreater: Boolean;
function IsWindowsVistaSP2OrGreater: Boolean;
function IsWindows7OrGreater: Boolean;
function IsWindows7SP1OrGreater: Boolean;
function IsWindows8OrGreater: Boolean;
function IsWindows8Point1OrGreater: Boolean;
....
const
VER_EQUAL = 1;
VER_GREATER = 2;
VER_GREATER_EQUAL = 3;
VER_LESS = 4;
VER_LESS_EQUAL = 5;
VER_AND = 6;
VER_OR = 7;
_WIN32_WINNT_WINXP = $0501;
_WIN32_WINNT_VISTA = $0600;
_WIN32_WINNT_WIN7 = $0601;
_WIN32_WINNT_WIN8 = $0602;
_WIN32_WINNT_WINBLUE = $0603;
function VerSetConditionMask(dwlConditionMask: ULONGLONG; dwTypeBitMask: DWORD; dwConditionMask: Byte): ULONGLONG; stdcall; external kernel32;
function VerifyVersionInfo(var lpVersionInfo: TOSVersionInfoEx; dwTypeMask: DWORD; dwlConditionMask: DWORDLONG): BOOL; stdcall; external kernel32 name 'VerifyVersionInfoW';
function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion, wServicePackMajor: Word): Boolean;
var
osvi: TOSVersionInfoEx;
dwlConditionMask: DWORDLONG;
begin
osvi := Default(TOSVersionInfoEx);
osvi.dwOSVersionInfoSize := SizeOf(osvi);
osvi.dwMajorVersion := wMajorVersion;
osvi.dwMinorVersion := wMinorVersion;
osvi.wServicePackMajor := wServicePackMajor;
dwlConditionMask := VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or VER_SERVICEPACKMAJOR, dwlConditionMask);
end;
function IsWindowsXPOrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WINXP), LoByte(_WIN32_WINNT_WINXP), 0);
end;
function IsWindowsXPSP1OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WINXP), LoByte(_WIN32_WINNT_WINXP), 1);
end;
function IsWindowsXPSP2OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WINXP), LoByte(_WIN32_WINNT_WINXP), 2);
end;
function IsWindowsXPSP3OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WINXP), LoByte(_WIN32_WINNT_WINXP), 3);
end;
function IsWindowsVistaOrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_VISTA), LoByte(_WIN32_WINNT_VISTA), 0);
end;
function IsWindowsVistaSP1OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_VISTA), LoByte(_WIN32_WINNT_VISTA), 1);
end;
function IsWindowsVistaSP2OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_VISTA), LoByte(_WIN32_WINNT_VISTA), 2);
end;
function IsWindows7OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WIN7), LoByte(_WIN32_WINNT_WIN7), 0);
end;
function IsWindows7SP1OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WIN7), LoByte(_WIN32_WINNT_WIN7), 1);
end;
function IsWindows8OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WIN8), LoByte(_WIN32_WINNT_WIN8), 0);
end;
function IsWindows8Point1OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HiByte(_WIN32_WINNT_WINBLUE), LoByte(_WIN32_WINNT_WINBLUE), 0);
end;
function IsWindowsServer: Boolean;
var
osvi: TOSVersionInfoEx;
dwlConditionMask: DWORDLONG;
begin
osvi := Default(TOSVersionInfoEx);
osvi.dwOSVersionInfoSize := SizeOf(osvi);
osvi.wProductType := VER_NT_WORKSTATION;
dwlConditionMask := VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
Result := not VerifyVersionInfo(osvi, VER_PRODUCT_TYPE, dwlConditionMask);
end;
{$IFDEF VISTA_UP}
// use modern APIs
{$ELSE}
// fallback
{$ENDIF}
当您VISTA_UP
的目标是 Vista+ 时,在某处定义条件符号,例如:
-Dxxx
命令行编译器开关$DEFINE VISTA_UP
在单独的$INCLUDE
-d 文件中与所有其他编译时配置内容一起使用请记住,您不能保留库单元的 DCU,每次切换目标时都必须重建。