Лучший подход, который я знаю, это проверить, экспортируется ли определенный API из какой-либо DLL. Каждая новая версия Windows добавляет новые функции, и, проверяя их наличие, можно определить, на какой ОС запущено приложение. Например, Vista экспортирует GetLocaleInfoEx из kernel32.dll, в то время как предыдущие Windowses этого не делали.
Короче говоря, вот один такой список, содержащий только экспорт из kernel32.dll.
> *function: implemented in*
> GetLocaleInfoEx: Vista
> GetLargePageMinimum: Vista, Server 2003
GetDLLDirectory: Vista, Server 2003, XP SP1
GetNativeSystemInfo: Vista, Server 2003, XP SP1, XP
ReplaceFile: Vista, Server 2003, XP SP1, XP, 2000
OpenThread: Vista, Server 2003, XP SP1, XP, 2000, ME
GetThreadPriorityBoost: Vista, Server 2003, XP SP1, XP, 2000, NT 4
IsDebuggerPresent: Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98
GetDiskFreeSpaceEx: Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98, 95 OSR2
ConnectNamedPipe: Vista, Server 2003, XP SP1, XP, 2000, NT 4, NT 3
Beep: Vista, Server 2003, XP SP1, XP, 2000, ME, 98, 95 OSR2, 95
Написание функции для определения реальной версии ОС просто; просто перейдите от самой новой ОС к самой старой и используйте GetProcAddress для проверки экспортированных API. Реализация этого на любом языке должна быть тривиальной.
Следующий код в Delphi был извлечен из бесплатной библиотеки DSiWin32 ):
TDSiWindowsVersion = (wvUnknown, wvWin31, wvWin95, wvWin95OSR2, wvWin98,
wvWin98SE, wvWinME, wvWin9x, wvWinNT3, wvWinNT4, wvWin2000, wvWinXP,
wvWinNT, wvWinServer2003, wvWinVista);
function DSiGetWindowsVersion: TDSiWindowsVersion;
var
versionInfo: TOSVersionInfo;
begin
versionInfo.dwOSVersionInfoSize := SizeOf(versionInfo);
GetVersionEx(versionInfo);
Result := wvUnknown;
case versionInfo.dwPlatformID of
VER_PLATFORM_WIN32s: Result := wvWin31;
VER_PLATFORM_WIN32_WINDOWS:
case versionInfo.dwMinorVersion of
0:
if Trim(versionInfo.szCSDVersion[1]) = 'B' then
Result := wvWin95OSR2
else
Result := wvWin95;
10:
if Trim(versionInfo.szCSDVersion[1]) = 'A' then
Result := wvWin98SE
else
Result := wvWin98;
90:
if (versionInfo.dwBuildNumber = 73010104) then
Result := wvWinME;
else
Result := wvWin9x;
end; //case versionInfo.dwMinorVersion
VER_PLATFORM_WIN32_NT:
case versionInfo.dwMajorVersion of
3: Result := wvWinNT3;
4: Result := wvWinNT4;
5:
case versionInfo.dwMinorVersion of
0: Result := wvWin2000;
1: Result := wvWinXP;
2: Result := wvWinServer2003;
else Result := wvWinNT
end; //case versionInfo.dwMinorVersion
6: Result := wvWinVista;
end; //case versionInfo.dwMajorVersion
end; //versionInfo.dwPlatformID
end; { DSiGetWindowsVersion }
function DSiGetTrueWindowsVersion: TDSiWindowsVersion;
function ExportsAPI(module: HMODULE; const apiName: string): boolean;
begin
Result := GetProcAddress(module, PChar(apiName)) <> nil;
end; { ExportsAPI }
var
hKernel32: HMODULE;
begin { DSiGetTrueWindowsVersion }
hKernel32 := GetModuleHandle('kernel32');
Win32Check(hKernel32 <> 0);
if ExportsAPI(hKernel32, 'GetLocaleInfoEx') then
Result := wvWinVista
else if ExportsAPI(hKernel32, 'GetLargePageMinimum') then
Result := wvWinServer2003
else if ExportsAPI(hKernel32, 'GetNativeSystemInfo') then
Result := wvWinXP
else if ExportsAPI(hKernel32, 'ReplaceFile') then
Result := wvWin2000
else if ExportsAPI(hKernel32, 'OpenThread') then
Result := wvWinME
else if ExportsAPI(hKernel32, 'GetThreadPriorityBoost') then
Result := wvWinNT4
else if ExportsAPI(hKernel32, 'IsDebuggerPresent') then //is also in NT4!
Result := wvWin98
else if ExportsAPI(hKernel32, 'GetDiskFreeSpaceEx') then //is also in NT4!
Result := wvWin95OSR2
else if ExportsAPI(hKernel32, 'ConnectNamedPipe') then
Result := wvWinNT3
else if ExportsAPI(hKernel32, 'Beep') then
Result := wvWin95
else // we have no idea
Result := DSiGetWindowsVersion;
end; { DSiGetTrueWindowsVersion }
--- обновлено 2009-10-09
Оказывается, что очень трудно сделать «недокументированное» обнаружение ОС на Vista SP1 и выше. Если посмотреть на изменения API , то видно, что все функции Windows 2008 также реализованы в Vista SP1 и что все функции Windows 7 также реализованы в Windows 2008 R2. Жаль: (
--- конец обновления
FWIW, с этой проблемой я столкнулся на практике. У нас (в компании, в которой я работаю) есть программа, которая на самом деле не была готова к Vista, когда была выпущена Vista (и через несколько недель после этого ...). Он также не работал под слоем совместимости. (Некоторые проблемы с DirectX. Не спрашивайте.)
Мы не хотели, чтобы слишком умные для своих собственных пользователей пользователи запускали это приложение в Vista - в режиме совместимости или нет - поэтому мне пришлось искать решение (парень, умнее меня, указал мне правильное направление, материал выше не мое детище). Сейчас я публикую это для вашего удовольствия и для помощи всем бедным душам, которые должны будут решить эту проблему в будущем. Google, пожалуйста, проиндексируйте эту статью!
Если у вас есть лучшее решение (или обновление и / или исправление для моего), пожалуйста, оставьте ответ здесь ...