Selbst reingelegt beim Test von „XP oder später“

Manche Codezeilen schreibt man ja einfach im Schlaf so in etwa wie diesen hier

static const OSVERSIONINFO &GetOSVersionInfo()
{
 static OSVERSIONINFO osVersionInfo;
 if (osVersionInfo.dwOSVersionInfoSize==0)
 {
  osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  ::GetVersionEx(&osVersionInfo);
 }
 // return pointer to struct
 return osVersionInfo;
}

bool OSIsWinXP()
{
 // Check if OS is XP or later
 const OSVERSIONINFO &osvi= GetOSVersionInfo();
 return (osvi.dwPlatformId & VER_PLATFORM_WIN32_NT)!=0 &&
     osvi.dwMajorVersion>=5 &&
     osvi.dwMinorVersion>=1;
}

Der Sinn und Zweck ist eindeutig. Ich benötige diese Funktion um zu Testen ob Windows XP oder ein späteres OS wie Vista oder Windows 7 installiert ist. Dumm nur das dieser Code dämlich falsch ist.
Die Betriebssysteme haben die folgenden internen Versionsnummern
5.0 – Windows 2000
5.1 – Windows XP
5.2 – Windows Server 2003
6.0 – Windows Vista
6.1 – Windows 7 (Anmerkung: idotisch, dass hier nicht 7.0 verwendet wird)

Als ich den Code schrieb war Windows XP gerade draußen und selbst Windows Server 2003 gerade am Horizont. Dämlicherweise schrieb ich in dem Test osvi.dwMajorVersion>=5 && osvi.dwMinorVersion>=1.
ohne natürlich daran zu denken, dass ein späteres OS wieder mit einer 0 als minor Version kommen könnte.
Dadurch ergibt sich natürlich das der Test für alle Betriebssysteme nach Windows XP funktioniert nur nicht für Windows Vista  weil eben die Minor Version hier 0 ist. Ich war drauf und dran mal wieder einen Bug einzureichen bis mir schlagartig klar war, dass nicht Vista einen Fehler hat sondern mein eigener Code.

Der korrekte Test muss natürlich so lauten:

bool OSIsWinXP()
{
 // Check if OS is XP or later
 const OSVERSIONINFO &osvi= GetOSVersionInfo();
 return (osvi.dwPlatformId & VER_PLATFORM_WIN32_NT)!=0 &&
   (osvi.dwMajorVersion>5 ||    // May be vista or later
       (osvi.dwMajorVersion==5 &&    // that's XP
        osvi.dwMinorVersion>=1));
}

Code wie im Schlaf zu schreiben bringt es manchmal eben nicht. 😉

9 Gedanken zu „Selbst reingelegt beim Test von „XP oder später““

  1. Entsprechend des Funktionsnamens würde ich erwarten, dass nur bei Windows XP ‚true‘ zurückgegeben wird. ‚OSIsWinXPOrHigher‘ wäre hier eindeutiger.

  2. Ich habe das bei mir so gelöst, dass ich die MajorVersion mit 10 multipliziere und dann die MinorVersion addiere. „XpOrHigher“ wäre dann >=51 Das funktioniert ab Windows 2000 und auf Systemen mit der Major Version 4 läuft unsere Software sowieso nicht (mehr). Hoffentlich bleibt Microsoft da auch in Zukunft im Schema.

    @Martin
    Ich finde die interne Versionsnummer für Windows 7 in einer Art schon konsistent. Immer, wenn sich auf dem Desktop die Major Version geändert hat (Win 2000, Vista) hat es auch an der Win32 API größere Erweiterungen gegeben, und es war auch ein größerer Aufwand nötig, um das Programm an die Möglichkeiten der Plattform anzupassen. Bis jetzt sieht es bei mir so aus, als ob ein Vista kompatibles Programm (Trustinfo Manifest, nichts mehr in das Programm Verzeichnis schreiben, größere Icons, keine Adminrechte nötig) ohne weitere Änderungen auch unter Windows 7 rund läuft.

    1. 😯 Ich kenne Larry nicht persönlich, aber grenzt ja schon an Mystik.
      Und nein ich habe nicht abgeschrieben 😉
      So wie ich die Daten des RSS-Feeds interpretiere hat Larry seinen Artikel kurz nach mir heute in der Nacht veröffentlicht und soweit ich weiß kann er kein Deutsch :mrgreen:

  3. Euch ist aber schon bekannt, das die internen Versionnummern von
    Windows XP-64 und Windows Server 2003 Identisch sind. Also
    5.2 tragen. Das ist ein echtes Problem, konnte hier aber noch nichts finden.

    1. Ich verstehe Dein Problem nicht, denn das ist dokumentiert in der MSDN
      OSVERSIONINFOEX http://msdn.microsoft.com/en-us/library/ms724833(VS.85).aspx
      – Windows Server 2003 Version: 5.2
      GetSystemMetrics(SM_SERVERR2) == 0
      – Windows Server 2003 R2 Version: 5.2
      GetSystemMetrics(SM_SERVERR2) != 0
      – Windows XP Professional x64 Edition Version 5.2
      (OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION) && (SYSTEM_INFO.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)

  4. „Windows 7 (Anmerkung: idotisch, dass hier nicht 7.0 verwendet wird)“
    => FALSCH

    Es wird immer nach der Buildnummer und Version des Kernels gegangen. Da Windows 7 nur ein aufgepepptes Windows Vista ist und sich nichts wesentliches im Kernel tat, wurde die Versionsnummer nur im Minor-oder Maintenance-Bereich geändert.

    Du wirst’s nicht glauben, aber dies ist ebenfalls mit Windows 2000 und Windows XP 32 Bit so (5.0 zu 5.01). Windows XP 64 Bit besitzt allerdings schon 5.02, da dieses einen Windows 2003 Server Kernel besitzt und grössere Änderungen umgesetzt wurden insb. bei der Sicherheit.

    Also Windows XP 64 Bit ist das wesentlich sicherere Windows XP.

    Cheers

  5. Ich vermeide immer osvi.dwMinorVersion und benutze faulerweise nur
    osvi.dwMajorVersion

    Der Vorschlag von Thorsten,
    (osvi.dwMajorVersion * 10 + osvi.dwMinorVersion)
    zu rechnen ist schon ganz gut.

    Noch etwas besser ist:
    (osvi.dwMajorVersion * 100 + osvi.dwMinorVersion)

    Aber beide haben den Datentyp DWORD (auch bekannt als unsigned long).
    Theoretisch waere also ein vorzeichenloser 64-bit Datentyp richtig:
    (((__int64)osvi.dwMajorVersion << 32) + osvi.dwMinorVersion)

    Eine aehnliche Loesung ist machbar, wenn man hofft, dass die Zahlen
    16 bit nie ueberschreiten:
    ((osvi.dwMajorVersion << 16) + osvi.dwMinorVersion)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.