How to detect true Windows version? How to detect true Windows version? windows windows

How to detect true Windows version?


The best approach I know is to check if specific API is exported from some DLL. Each new Windows version adds new functions and by checking the existance of those functions one can tell which OS the application is running on. For example, Vista exports GetLocaleInfoEx from kernel32.dll while previous Windowses didn't.

To cut the long story short, here is one such list containing only exports from 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  

Writing the function to determine the real OS version is simple; just proceed from newest OS to oldest and use GetProcAddress to check exported APIs. Implementing this in any language should be trivial.

The following code in Delphi was extracted from the free DSiWin32 library):

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.dwPlatformIDend; { 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 }

--- updated 2009-10-09

It turns out that it gets very hard to do an "undocumented" OS detection on Vista SP1 and higher. A look at the API changes shows that all Windows 2008 functions are also implemented in Vista SP1 and that all Windows 7 functions are also implemented in Windows 2008 R2. Too bad :(

--- end of update

FWIW, this is a problem I encountered in practice. We (the company I work for) have a program that was not really Vista-ready when Vista was released (and some weeks after that ...). It was not working under the compatibility layer either. (Some DirectX problems. Don't ask.)

We didn't want too-smart-for-their-own-good users to run this app on Vista at all - compatibility mode or not - so I had to find a solution (a guy smarter than me pointed me into right direction; the stuff above is not my brainchild). Now I'm posting it for your pleasure and to help all poor souls that will have to solve this problem in the future. Google, please index this article!

If you have a better solution (or an upgrade and/or fix for mine), please post an answer here ...


WMI QUery:

"Select * from Win32_OperatingSystem"

EDIT: Actually better would be:

"Select Version from Win32_OperatingSystem"

You could implement this in Delphi like so:

function OperatingSystemDisplayName: string;  function GetWMIObject(const objectName: string): IDispatch;  var    chEaten: Integer;    BindCtx: IBindCtx;    Moniker: IMoniker;  begin    OleCheck(CreateBindCtx(0, bindCtx));    OleCheck(MkParseDisplayName(BindCtx, PChar(objectName), chEaten, Moniker));    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));  end;  function VarToString(const Value: OleVariant): string;  begin    if VarIsStr(Value) then begin      Result := Trim(Value);    end else begin      Result := '';    end;  end;  function FullVersionString(const Item: OleVariant): string;  var    Caption, ServicePack, Version, Architecture: string;  begin    Caption := VarToString(Item.Caption);    ServicePack := VarToString(Item.CSDVersion);    Version := VarToString(Item.Version);    Architecture := ArchitectureDisplayName(SystemArchitecture);    Result := Caption;    if ServicePack <> '' then begin      Result := Result + ' ' + ServicePack;    end;    Result := Result + ', version ' + Version + ', ' + Architecture;  end;var  objWMIService: OleVariant;  colItems: OleVariant;  Item: OleVariant;  oEnum: IEnumvariant;  iValue: LongWord;begin  Try    objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');    colItems := objWMIService.ExecQuery('SELECT Caption, CSDVersion, Version FROM Win32_OperatingSystem', 'WQL', 0);    oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;    if oEnum.Next(1, Item, iValue)=0 then begin      Result := FullVersionString(Item);      exit;    end;  Except    // yes, I know this is nasty, but come what may I want to use the fallback code below should the WMI code fail  End;  (* Fallback, relies on the deprecated function GetVersionEx, reports erroneous values     when manifest does not contain supportedOS matching the executing system *)  Result := TOSVersion.ToString;end;


How about obtaining the version of a system file?

The best file would be kernel32.dll, located in %WINDIR%\System32\kernel32.dll.

There are APIs to obtain the file version. eg: I'm using Windows XP -> "5.1.2600.5512 (xpsp.080413-2111)"