如何在Delphi XE4中对CSIDL或KNOWFOLDERID进行条件编译?

时间:2014-07-06 15:53:46

标签: delphi delphi-xe4 windowsversion

我在Windows 7计算机上运行Delphi XE4。我希望有一个代码库可以识别是否使用CSIDL或KNOWFOLDERID。

有没有办法使用{$ IFDEF XXXXXX)有条件地编译使用部分中的不同文件,并调用基于Windows XP或更低版本的不同功能?

2 个答案:

答案 0 :(得分:4)

你很可能不想为此使用条件编译。这样做会强制您为不同版本的操作系统提供不同的可执行文件。这造成了大量的安装复杂性。

处理场景的常用方法是使用运行时分支而不是条件编译。所以你会写这样的代码:

if IsWindowsVistaOrGreater then
  DoKnownFolderIDVersion
else
  DoCSIDLVersion;

至关重要的一点是,您必须将这些if语句保持在尽可能低的水平。您必须从高级代码中隐藏这些详细信息。从高级代码的角度来看,它必须询问特定文件夹的位置。高级代码不得包含基于版本的任何分支。

复杂的是,您不能对使用旧功能支持平台上可能不存在的API函数的分支使用加载时链接。因此,使用运行时链接而不是加载时间链接。有很多不同的方法可以实现这一点,但对于系统API,使用现代版本的Delphi,延迟加载是一个很好的选择。


就个人而言,我现在不反对使用基于CSIDL的API,因为我个人认为MS不会很快删除功能。但是关于是否使用CSIDL的决定显然是你的。我当然可以理解不再使用这些API的愿望。很明显,微软不希望你这样做。


如果要检查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;

答案 1 :(得分:0)

{$IFDEF VISTA_UP}
// use modern APIs
{$ELSE}
// fallback
{$ENDIF}

当您的目标是Vista +时,在某处定义了VISTA_UP条件符号,例如:

  • "目录/条件"在"项目选项"
  • 使用-Dxxx命令行编译器开关
  • $DEFINE VISTA_UP在单独的$INCLUDE - d文件中,包含所有其他编译时配置内容

请记住,您无法保留图书馆单元的DCU,每次切换目标时都必须重建。