【问题标题】:How to do Conditional Compilation for CSIDL or KNOWFOLDERID in Delphi XE4?如何在 Delphi XE4 中对 CSIDL 或 KNOWFOLDERID 进行条件编译?
【发布时间】:2014-08-27 04:07:03
【问题描述】:

我在 Windows 7 机器上运行 Delphi XE4。我想要一个可以识别是使用 CSIDL 还是 KNOWFOLDERID 的代码库。

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

【问题讨论】:

    标签: delphi delphi-xe4 windowsversion


    【解决方案1】:

    您很可能不想为此使用条件编译。这样做会迫使您为不同版本的操作系统提供不同的可执行文件。这会增加安装的复杂性。

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

    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;
    

    【讨论】:

    【解决方案2】:
    {$IFDEF VISTA_UP}
    // use modern APIs
    {$ELSE}
    // fallback
    {$ENDIF}
    

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

    • 在“项目选项”的“目录/条件”下
    • 使用-Dxxx命令行编译开关
    • 或在单独的 $INCLUDE-d 文件中使用 $DEFINE VISTA_UP 以及所有其他编译时配置文件

    请记住,您不能保留库单元的 DCU,每次切换目标时都必须重建。

    【讨论】:

      猜你喜欢
      • 2014-04-07
      • 1970-01-01
      • 2013-09-12
      • 1970-01-01
      • 2014-03-09
      • 1970-01-01
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      相关资源
      最近更新 更多