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. 😉
Entsprechend des Funktionsnamens würde ich erwarten, dass nur bei Windows XP ‚true‘ zurückgegeben wird. ‚OSIsWinXPOrHigher‘ wäre hier eindeutiger.
@Sven: Gebe ich Dir recht. Ich habe die Funktionsnamen für meinen Artikel angepasst und etwas unglücklich gewählt.
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.
Sprecht Ihr euch ab?
http://blogs.msdn.com/larryosterman/archive/2009/03/05/checking-file-versions-is-surprisingly-hard.aspx
😯 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
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.
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)
„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
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)