При разработке приложений под Windows, важно учитывать, что пользователи могут запускать их в режиме совместимости, что может привести к неожиданным ошибкам, особенно если используется сторонний код, зависящий от версии операционной системы. В данной статье мы рассмотрим, как можно обнаружить, что ваше приложение запущено в режиме совместимости, и как это может быть связано с использованием библиотек защиты данных.
Проблема
Разработчики часто сталкиваются с проблемой, когда их приложения, использующие сторонние библиотеки для защиты данных, не работают корректно в режиме совместимости. Это особенно актуально, когда библиотека требует инициализации с параметрами, зависящими от версии операционной системы. В случае, если приложение запущено в режиме совместимости с Windows XP на Windows 7, метод шифрования данных из библиотеки может не работать.
Решение
Для решения этой проблемы необходимо обнаружить, что приложение запущено в режиме совместимости. Один из способов - сравнить информацию о версии операционной системы, полученную через функцию GetVersionEx, с версией, предоставляемой WMI-классом Win32_OperatingSystem.
Пример кода на Object Pascal (Delphi)
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
SysUtils,
ActiveX,
ComObj,
Variants;
function WMI_OSVersion: string;
var
FSWbemLocator: OLEVariant;
FWMIService: OLEVariant;
FWbemObjectSet: OLEVariant;
rgvar: OLEVariant;
LEnum: IEnumVARIANT;
pceltFetched: LongWord;
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObjectSet := FWMIService.ExecQuery('SELECT Version FROM Win32_OperatingSystem', 'WQL', $00000020);
LEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if LEnum.Next(1, rgvar, pceltFetched) = S_OK then
Result := String(rgvar.Version);
end;
function WinApi_OsVersion: string;
var
lpVersionInformation: TOSVersionInfo;
begin
ZeroMemory(@lpVersionInformation, SizeOf(lpVersionInformation));
lpVersionInformation.dwOSVersionInfoSize := SizeOf(lpVersionInformation);
GetVersionEx(lpVersionInformation);
Result := Format('%d.%d.%d', [lpVersionInformation.dwMajorVersion, lpVersionInformation.dwMinorVersion, lpVersionInformation.dwBuildNumber]);
end;
function RunningCompatibilityMode: Boolean;
begin
Result := WMI_OSVersion <> WinApi_OsVersion;
end;
begin
try
CoInitialize(nil);
try
Writeln('Running in Compatibility Mode - ' + BoolToStr(RunningCompatibilityMode, True));
finally
CoUninitialize;
end;
except
on E: EOleException do
Writeln(Format('EOleException %s %x', [E.Message, E.ErrorCode]));
on E: Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
Альтернативные подходы
Существуют и другие методы для определения настоящей версии операционной системы, такие как использование RtlGetVersion, NetServerGetInfo, NetWkstGetInfo. Однако стоит помнить, что в Windows 8.1 и более новых версиях, проявление (manifestation) также влияет на GetVersionEx, и просто проверка номеров версий не указывает на использование режима совместимости, но может свидетельствовать о наличии какой-либо виртуализации.
Заключение
Обнаружение режима совместимости в Delphi является важной задачей для обеспечения стабильной работы приложений, особенно тех, которые используют сторонние библиотеки защиты данных. Приведенный выше код может быть полезен для разработчиков, сталкивающихся с подобными проблемами, и поможет им избежать ошибок, связанных с некорректной работой сторонних библиотек в режиме совместимости.
Приложение на Delphi может обнаружить запуск в режиме совместимости для корректной работы с библиотеками защиты данных, используя различные методы определения настоящей версии операционной системы.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS