Как сделать условную компиляцию для CSIDL или KNOWFOLDERID в Delphi XE4?
Я использую Delphi XE4 на компьютере с Windows 7. Я хотел бы иметь одну кодовую базу, которая может распознать, использовать ли CSIDL или KNOWFOLDERID.
Есть ли способ использовать {$IFDEF XXXXXX) для условной компиляции различных файлов в разделе "Использования" и для вызова различных функций на основе Windows XP или ниже?
2 ответа
Скорее всего, вы не хотите использовать условную компиляцию для этого. Это заставляет вас отправлять разные исполняемые файлы для разных версий операционной системы. Это создает большую сложность установки.
Обычный подход к решению сценария заключается в использовании ветвления во время выполнения, а не в условной компиляции. Таким образом, вы написали бы код так:
if IsWindowsVistaOrGreater then
DoKnownFolderIDVersion
else
DoCSIDLVersion;
Одна вещь, которая имеет решающее значение, состоит в том, что вы должны держать эти операторы if на как можно более низком уровне. Вы должны скрыть эти детали от кода высокого уровня. С точки зрения кода высокого уровня, он должен запрашивать местоположение конкретной папки. Код высокого уровня не должен содержать ветвлений в зависимости от версии.
Сложность состоит в том, что вы не можете использовать привязку времени загрузки для ветви, которая использует функции API, которые могут отсутствовать на старых поддерживаемых платформах. Таким образом, вместо привязки по времени загрузки, используйте привязку по времени выполнения. Есть много разных способов добиться этого, но для системных API, с современными версиями Delphi, задержка загрузки является отличным вариантом.
Лично я не против использования API на основе CSIDL даже сейчас, потому что лично я не вижу, чтобы MS удаляла эту функциональность в ближайшее время. Но решение о том, использовать CSIDL или нет, очевидно, принадлежит вам. Я, конечно, могу понять желание не использовать эти API больше. Понятно, что Microsoft не хочет, чтобы вы это делали.
Если вы хотите проверить поддержку версии Windows, то вы должны использовать вспомогательные API новой версии. Теперь я знаю, что они были включены в модули Windows, которые поставляются с Delphi. Возможно, они в самой последней версии, но у вас может быть версия, в которой их нет. В этом случае вы можете использовать это:
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 своих библиотечных единиц, вам придется восстанавливать каждый раз, когда вы меняете цель.