@Abt, RegistryView ⇒
Danke für diesen Hinweis.
Jetzt sieht es so aus und funktioniert mit AnyCPU ...
using Microsoft.Win32;
using System;
using System.Runtime.InteropServices;
namespace WinVerHK
{
internal class Program
{
struct OSVERSIONINFOEXW
{
public int dwOSVersionInfoSize { get; set; }
public int dwMajorVersion { get; set; }
public int dwMinorVersion { get; set; }
public int dwBuildNumber { get; set; }
}
[DllImport("ntdll.dll", SetLastError = true)]
static extern int RtlGetVersion(ref OSVERSIONINFOEXW versionInfo);
static void Main(string[] args)
{
string sWinVer = WinVer();
Console.ReadLine();
}
//===============================================
// Windows-Version ermitteln
//===============================================
private static string WinVer()
{
OSVERSIONINFOEXW osv = new OSVERSIONINFOEXW();
var rcRtl = RtlGetVersion(ref osv);
if (osv.dwMajorVersion == 10 && osv.dwMinorVersion == 0 &&
osv.dwBuildNumber >= 22000)
{ osv.dwMajorVersion = 11; }
string RtlVers = osv.dwMajorVersion.ToString() + "." +
osv.dwMinorVersion.ToString();
string sVer = "??"; // "XP", "Vista", "7", "8", "8.1", "10", "11"
switch (RtlVers)
{
case "5.1" : sVer = "XP"; break;
case "6.0" : sVer = "Vista"; break;
case "6.1" : sVer = "7"; break;
case "6.2" : sVer = "8"; break;
case "6.3" : sVer = "8.1"; break;
case "10.0": sVer = "10"; break;
case "11.0": sVer = "11"; break;
}
string sCurrentBuild = osv.dwBuildNumber.ToString();
bool Is64os = System.Environment.Is64BitOperatingSystem;
string sArchitektur = Is64os ? "x64" : "x86";
RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey skey2 = key.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
sCurrentBuild = HoleRegValue(skey2, "CurrentBuild");
string sUBR = HoleRegValue(skey2, "UBR");
string sDisplayVersion = HoleRegValue(skey2, "DisplayVersion");
string sEditionID = HoleRegValue(skey2, "EditionID");
string sRegisteredOwner = HoleRegValue(skey2, "RegisteredOwner");
string sInstallDate = HoleRegValue(skey2, "InstallDate");
Console.WriteLine("Windows " + sVer + " Version " + sDisplayVersion +
" (Build " + sCurrentBuild + "." + sUBR + ")\n");
string SysName = "Microsoft Windows " + sVer + " " + sEditionID + " " + sArchitektur;
Console.WriteLine("Betriebssystemname " + SysName);
Console.WriteLine("Installiert am " + sInstallDate);
Console.WriteLine("Registrierter Benutzer " + sRegisteredOwner);
return sVer; // 10 oder 11 oder 8.1 oder 7 oder XP
} // private static string WinVer()
//=============================================================
// Angaben zu einem Key aus der Registry holen
//=============================================================
private static string HoleRegValue(Microsoft.Win32.RegistryKey skey, string suKey)
{
// Problem: Groß- und Kleinschreibung ist nicht immer gleich, bei C# aber relevant
System.String[] ParaKeys = skey.GetValueNames();
for (int i = 0; i < ParaKeys.Length; i++)
{
if (suKey.ToLower() == ParaKeys[i].ToLower())
{
string rc = skey.GetValue(ParaKeys[i]).ToString(); // Original-Key benutzen
if (suKey == "InstallDate") // UNIX-Zeistempel ab dem 01.01.1970 00:00:00
{
DateTime AnfDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var sec = skey.GetValue(ParaKeys[i]); // UINT32 = Sekunden seit dem 01.01.1970 00:00:00 Uhr
DateTime EndDate = AnfDate.AddSeconds((int)sec);
rc = EndDate.ToString();
}
return rc;
}
} // for
return "";
} // private static string HoleRegValue
} // internal class Program
} // namespace WinVerHK
Jetzt habe ich eine Lösung gefunden, das Programm zeigt alles korrekt an in Windows 32 und 64.
Was habe ich gemacht ?
Projekt → Eigenschaften → Build → Zielplattform: Any CPU
Projekt → Eigenschaften → Anwendung → Zielframework: .NET Framework 4 (vorher war 4.8)
Damit funktioniert alles. Die Merkwürdigkeiten sind offenbar erst nach 4.0 aufgetreten.
Hier das jetzige Programm
using System;
using System.Runtime.InteropServices;
namespace WinVerHK
{
internal class Program
{
struct OSVERSIONINFOEXW
{
public int dwOSVersionInfoSize { get; set; }
public int dwMajorVersion { get; set; }
public int dwMinorVersion { get; set; }
public int dwBuildNumber { get; set; }
}
[DllImport("ntdll.dll", SetLastError = true)]
static extern int RtlGetVersion(ref OSVERSIONINFOEXW versionInfo);
static void Main(string[] args)
{
string sWinVer = WinVer();
Console.ReadLine();
}
//===============================================
// Windows-Version ermitteln
//===============================================
private static string WinVer()
{
OSVERSIONINFOEXW osv = new OSVERSIONINFOEXW();
var rcRtl = RtlGetVersion(ref osv);
if (osv.dwMajorVersion == 10 && osv.dwMinorVersion == 0 &&
osv.dwBuildNumber >= 22000)
{ osv.dwMajorVersion = 11; }
string RtlVers = osv.dwMajorVersion.ToString() + "." +
osv.dwMinorVersion.ToString();
string sVer = "??"; // "XP", "Vista", "7", "8", "8.1", "10", "11"
switch (RtlVers)
{
case "5.1" : sVer = "XP"; break;
case "6.0" : sVer = "Vista"; break;
case "6.1" : sVer = "7"; break;
case "6.2" : sVer = "8"; break;
case "6.3" : sVer = "8.1"; break;
case "10.0": sVer = "10"; break;
case "11.0": sVer = "11"; break;
}
string sCurrentBuild = osv.dwBuildNumber.ToString();
bool Is64os = System.Environment.Is64BitOperatingSystem;
string sArchitektur = Is64os ? "x64" : "x86";
string subKey2 = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
Microsoft.Win32.RegistryKey skey2 = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(subKey2);
sCurrentBuild = HoleRegValue(skey2, "CurrentBuild");
string sUBR = HoleRegValue(skey2, "UBR");
string sDisplayVersion = HoleRegValue(skey2, "DisplayVersion");
string sEditionID = HoleRegValue(skey2, "EditionID");
string sRegisteredOwner = HoleRegValue(skey2, "RegisteredOwner");
string sInstallDate = HoleRegValue(skey2, "InstallDate");
Console.WriteLine("Windows " + sVer + " Version " + sDisplayVersion +
" (Build " + sCurrentBuild + "." + sUBR + ")\n");
string SysName = "Microsoft Windows " + sVer + " " + sEditionID + " " + sArchitektur;
Console.WriteLine("Betriebssystemname " + SysName);
Console.WriteLine("Installiert am " + sInstallDate);
Console.WriteLine("Registrierter Benutzer " + sRegisteredOwner);
return sVer; // 10 oder 11 oder 8.1 oder 7 oder XP
} // private static string WinVer()
//=============================================================
// Angaben zu einem Key aus der Registry holen
//=============================================================
private static string HoleRegValue(Microsoft.Win32.RegistryKey skey, string suKey)
{
// Problem: Groß- und Kleinschreibung ist nicht immer gleich, bei C# aber relevant
System.String[] ParaKeys = skey.GetValueNames();
for (int i = 0; i < ParaKeys.Length; i++)
{
if (suKey.ToLower() == ParaKeys[i].ToLower())
{
string rc = skey.GetValue(ParaKeys[i]).ToString(); // Original-Key benutzen
if (suKey == "InstallDate") // UNIX-Zeistempel ab dem 01.01.1970 00:00:00
{
DateTime AnfDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var sec = skey.GetValue(ParaKeys[i]); // UINT32 = Sekunden seit 01.01.1970 00:00:00 Uhr
DateTime EndDate = AnfDate.AddSeconds((int)sec);
rc = EndDate.ToString();
}
return rc;
}
} // for
return "";
} // private static string HoleRegValue
} // internal class Program
} // namespace WinVerHK
Mit der RtlGetVersion kann ich die Windows-Version erkennen unabhängig vom Modus X64 oder AnyCPU.
AnyCPU bwirkt m.E., dass das Programm im x86 Modus ausgeführt wird und dass in diesem Fall die für diesen Modus vorhandenen Registry Werte zur Verfügung gestellt werden. Das ist bekannt und OK. Allerdings ist nicht OK, dass die Registry Werte
"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion"
mit denen von
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
nicht übereinstimmen.
Im X64 Modus bekomme ich korrekte Werte, das Programm kann aber nicht in einem Win32 laufen, dort gibt es die beiden unterschiedlichen Werte nicht.
Im AnyCPU Modus funktioniert das Programm in einem Win32, erhält aber im Win-64 falsche Angaben, weil die Angaben bei WOW6432Node unkorrekt sind oder ganz fehlen, wie das Install-Datum.
Für andere Angaben in der Registry habe ich noch nicht auf Abweichungen untersucht.
Mein Ziel deshalb, ich möchte, dass das Programm auch im AnyCPU-Modus die korrekten Werte erhält.
Ich habe nun allerdings noch ein Problem, auch eine weniger elegante Lösung.
Ich möchte das Programm nicht im X64 Modus ausführen, weil es da z.B. auf meinem Tablet mit Win10-32 nicht funktioniert.
Wenn ich bei VS2022 in den Eigenschaften "Any CPU" statt X64 einstelle, erhalte ich ganz andere Angaben beim Auslesen der Registry.
Da stimmen einigen Angaben nicht oder sind gar nicht vorhanden, z.B. Installations-Zeitpunkt. Es wird von folgendem Key gelesen
"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion"
anstelle von
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
Mein Lösungsansatz ist folgender: Ich rufe regedit mit folgendem Kommando auf
"%WINDIR%\RegEdit" /a "x:\RegData.TEMP" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
und lese danach die Datei x:\RegData.TEMP ein und hole mir die benötigten Daten heraus. In dieser Datei steht alles so, wie beim X64-Programm.
Meine Frage: Gibt es eine Möglicheit in einem X64-System mit einem AnyCPU-Programm die X64-Angaben mit GetValue auszulesen ?
Jetzt bekomme ich die unkorrekten WOW6432Node Werte.
Th69,
auf meinem Tablet steht dort auch nicht "Windows 10", sondern etwas anderes - ich habe das allerdings nicht selbst eingetragen.
Ich benutze nun Deinen Vorschlag und bekomme damit heraus, um welches Windows es sich handelt
using System;
using System.Runtime.InteropServices;
namespace WinVerHK
{
internal class Program
{
struct OSVERSIONINFOEXW
{
public int dwOSVersionInfoSize { get; set; }
public int dwMajorVersion { get; set; }
public int dwMinorVersion { get; set; }
public int dwBuildNumber { get; set; }
}
[DllImport("ntdll.dll", SetLastError = true)]
static extern int RtlGetVersion(ref OSVERSIONINFOEXW versionInfo);
static void Main(string[] args)
{
string sWinVer = WinVer();
Console.ReadLine();
}
//===============================================
// Windows-Version ermitteln
//===============================================
private static string WinVer()
{
OSVERSIONINFOEXW osv = new OSVERSIONINFOEXW();
var rcRtl = RtlGetVersion(ref osv);
if (osv.dwMajorVersion == 10 && osv.dwMinorVersion == 0 &&
osv.dwBuildNumber >= 22000)
{ osv.dwMajorVersion = 11; }
string RtlVers = osv.dwMajorVersion.ToString() + "." +
osv.dwMinorVersion.ToString();
string sVer = "??"; // "XP", "7", "8.1", "10", "11"
switch (RtlVers)
{
case "5.1" : sVer = "XP"; break;
case "6.0" : sVer = "Vista"; break;
case "6.1" : sVer = "7"; break;
case "6.2" : sVer = "8"; break;
case "6.3" : sVer = "8.1"; break;
case "10.0": sVer = "10"; break;
case "11.0": sVer = "11"; break;
}
@Abt,
ich habe es wie folgt geändert
if (suKey == "InstallDate") // UNIX-Zeistempel ab dem 01.01.1970 00:00:00
{
DateTime AnfDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var sec = skey.GetValue(ParaKeys[i]); // UINT32 = Sekunden seit dem 01.01.1970 00:00:00 Uhr
DateTime EndDate = AnfDate.AddSeconds((int)sec);
rc = EndDate.ToString();
}
Es wird weiterhin 17:24:18 als Uhrzeit der Installation angezeigt.
Windows 10 Version 22H2 (Build 19045.3031)
Betriebssystemname Microsoft Windows 10 Professional X64
Installiert am 22.10.2022 17:24:18
Muss man bei Windows einstellen, dass man mit der UTC Zeit arbeiten möchte ?
Windowspage - Datum und Uhrzeit - BIOS/CMOS-Zeit als UTC-Zeit festlegen
Bei mir ist diesbezüglich nichts in der Registry eingestellt, meine Uhrzeit läuft als mitteleuropäische Sommerzeit (UTC+2)
Deshalb sind die angezeigten Zeiten immer die zutreffenden Ortszeiten meines ortsfesten PCs.
Nach UTC bzw. nach ISO8601 zu speichern sind jedoch technische Standards - daher auch keine Philosophie.
Der eine macht es so, der andere macht es nicht so. Das ist kein fixer Standard. Windows mit UTC Zeiten haben nur die PCs, bei denen man es so einstellt, ein Standard-Windows benutzt die Ortszeit. Anders ist es ggf. bei einigen Linux-Systemen.
Th69, wieso hat Deine Registry nicht diesen Eintrag ? Bei mir ist der bei allen drei WIndows 10 und 11 PC vorhanden, allerdings nicht bei der Vorgängerversionen XP, 7 und 8.1.
@Abt,
Windows speichert jedoch alle Werte getreu dem ISO-Standard nach UTC.
Meinst Du damit alle Zeiten, also auch den Zeitstempel beim Ändern von Dateien ?
Ich habe gerade einen Ordner angelegt mit dem Namen X162739,
dabei bedeuten die Zahl die Uhrzeit des Anlegens = 16:27:39
Im Directory sieht der Zeitstempel folgendermaßen aus:
000EC0: 58 31 36 32 37 33 39 20 20 20 20 10 00 0D 76 83 :X162739 ...v.:
000ED0: CB 56 CB 56 00 00 77 83 CB 56 C8 02 00 00 00 00 :.V.V..w..V......:
----- -----
Time Date
TIME: 77 83 = 0x8377 = 1000 0011 0111 0111
------#######++++++
Stunde Minute DoppelSek = 16:27:46
10000 011011 10111
16 27 23 => *2 = 46
Die Sekunden weichen etwas ab, aber nicht die Stunde.
Das DIR Kommando zeigt es so an, ich kann keine UTC-Zeit erkennen, alle Zeiten sind dresdner Ortszeiten, auch die BIOS/UEFI-Uhr läuft nach unserer Ortszeit:
Microsoft Windows [Version 10.0.19045.3031]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
G:\Test>dir a:
Datenträger in Laufwerk A: ist AAA
Volumeseriennummer: EC88-CC58
Verzeichnis von A:\
08.06.2023 16:02 <DIR> Bilder
11.06.2023 16:27 <DIR> X162739
0 Datei(en), 0 Bytes
2 Verzeichnis(se), 2.048 Bytes frei
G:\Test>
Ich könnte bei Zeit ja noch den Hinweis "Lokalzeit" ausgeben.
Welche Zeit sollte denn angezeigt werden, um den CODE-FEHLER zu beseitigen ?
Da ja nicht angespeichert ist, wo (an welchem Ort der Erde) die Installation stattfand, kann man die Zeit auch nicht korrekt zuordnen. Wurde dieses Windows bei einem fertig-PC/Notebook/Tablet in Mexiko, China oder Indien installiert und war es damals an diesem ort gerade 14°° Uhr Ortszeit, was soll man nun in Deutschlan anzeigen ? Man weiß ja nicht WO bei dem betreffenden Zeitstempel installiert wurde.
Die ZEIT und die ZEITZONE ist m.E. mehr ein philosophisches als ein technisch-mathematisches Problem.
@Abt,
Die absolute Zeit ist doch völlig uninteressant, ob die Installation nun eine Stunde früher oder später war - interessant ist das Datum.
Die Uhrzeit ist trotzdem hilfreich, wenn ich z.B. nachschauen will, ob ich nun zuerst Windows 11 oder 10 auf einem PC installiert habe. Bei mir gibt es beinahe auf jedem PC Win10 und 11 parallel und zusätzlich XP, 7 und 8.1 und Ubuntu als VMs. DOS und Win3.1 habe ich auch noch in der DosBox laufen.
@Th69,
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
SrvComment = Windows 10
Aus dieser Angabe ermittle ich, ob es sich um Windows 10 oder 11 handelt, Bei beiden meiner Pro-Versionen gibt es diesen Parameter. Bei Windows 7 und 8.1 gibt es ihn nicht, deshalb frage ich bei diesen Versionen den Parameter nicht ab, Win7 und 8.1 sind bereits an Hand der OSDescription eindeutig zu erkennen. WIn10 und 11 leider nicht.
Wenn bei Dir SrvComment nicht vorhanden ist - dann hast Du sicherlich ein anderes WIndows, das habe ich nicht und konnte es deshalb auch nicht testen.
@Palladin007,
in meinem Programm, wo ich das einsetze, kann man die System-Information abrufen.
Die angezeigten Werte sind weitestgehend identisch mit der System-Info von Windows 10.
Dort hat man (aus gutem Grund ?) die Uhrzeit der Installation weggelassen.
Ich habe jetzt eine Lösung gefunden, da muss man etwas mehr tun, als nur eine Varibale abfragen.
Das Ergenis dieses Test-Konsolenprogrammes sieht so aus:
Windows 10 Version 22H2 (Build 19045.3031)
Betriebssystemname Microsoft Windows 10 Professional X64
Installiert am 22.10.2022 17:24:18
Registrierter Benutzer xyz@t-online.de
In den Projekt Eigenschaften von VS2022 muss bei Build als Zielplattform X64 eingestellt sein.
using System;
using System.Runtime.InteropServices;
namespace WinVerHK
{
internal class Program
{
static void Main(string[] args)
{
string sWinVer = WinVer();
Console.ReadLine();
}
//===============================================
// Windows-Version ermitteln
//===============================================
private static string WinVer()
{
string sCurrentBuild = "";
string sUBR = "";
string sDisplayVersion = "";
string sEditionID = "";
string sProductName = "";
string sRegisteredOwner = "";
string sReleaseId = "";
string sInstallDate = "";
string sInstallTime = "";
string sCurrentMajorVersionNumber = "";
string sCurrentMinorVersionNumber = "";
string sCurrentVersion = "";
string sSrvComment = "";
string sVer = "XP"; // "XP", "7", "8.1", "10", "11"
string OSa = RuntimeInformation.OSArchitecture.ToString(); // X64
string sArchitektur = OSa;
string osVersion = Environment.OSVersion.ToString();
// 10: "Microsoft Windows NT 6.2.9200.0"
// 11: "Microsoft Windows NT 6.2.9200.0"
// 7 : "Microsoft Windows NT 6.1.7601 Service Pack 1"
string sOsVersion = osVersion;
string Version = Environment.Version.ToString();
// 10: "4.0.30319.42000"
// 11: "4.0.30319.42000"
// 7: "4.0.30319.42000"
string sVersion = Version;
string OSd = RuntimeInformation.OSDescription;
// 10 : Microsoft Windows 10.0.19045
// 11 : Microsoft Windows 10.0.22621 = Build
// 8.1: Microsoft Windows 6.3.9600
// 7 : Microsoft Windows 6.1.7601 S
string sDescription = OSd;
sVer = "???";
if (OSd.StartsWith("Microsoft Windows 6.3.")) { sVer = "8.1"; goto UpNxt; }
if (OSd.StartsWith("Microsoft Windows 6.1.")) { sVer = "7"; goto UpNxt; }
string subKey1 = @"SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters";
Microsoft.Win32.RegistryKey skey1 = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(subKey1);
sSrvComment = HoleRegValue(skey1, "SrvComment");
if (sSrvComment.EndsWith("10")) sVer = "10";
if (sSrvComment.EndsWith("11")) sVer = "11";
UpNxt:
string subKey2 = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
Microsoft.Win32.RegistryKey skey2 = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(subKey2);
sCurrentBuild = HoleRegValue(skey2, "CurrentBuild");
sUBR = HoleRegValue(skey2, "UBR");
sDisplayVersion = HoleRegValue(skey2, "DisplayVersion");
sEditionID = HoleRegValue(skey2, "EditionID");
sProductName = HoleRegValue(skey2, "ProductName");
sRegisteredOwner = HoleRegValue(skey2, "RegisteredOwner");
sReleaseId = HoleRegValue(skey2, "ReleaseId");
sInstallDate = HoleRegValue(skey2, "InstallDate");
sInstallTime = HoleRegValue(skey2, "InstallTime");
sCurrentMajorVersionNumber = HoleRegValue(skey2, "CurrentMajorVersionNumber");
sCurrentMinorVersionNumber = HoleRegValue(skey2, "CurrentMinorVersionNumber");
sCurrentVersion = HoleRegValue(skey2, "CurrentVersion");
Console.WriteLine("Windows " + sVer + " Version " + sDisplayVersion +
" (Build " + sCurrentBuild + "." + sUBR + ")\n");
string SysName = sOsVersion.Substring(0, 18) + sVer + " " + sEditionID + " " + sArchitektur;
Console.WriteLine("Betriebssystemname " + SysName);
Console.WriteLine("Installiert am " + sInstallDate);
Console.WriteLine("Registrierter Benutzer " + sRegisteredOwner);
return sVer; // 10 oder 11 oder 8.1 oder 7 oder XP
} // private static string WinVer()
//=============================================================
// Angaben zu einem Key aus der Registry holen
//=============================================================
private static string HoleRegValue(Microsoft.Win32.RegistryKey skey, string suKey)
{
// Problem: Groß- und Kleinschreibung ist nicht immer gleich, bei C# aber relevant
System.String[] ParaKeys = skey.GetValueNames();
for (int i = 0; i < ParaKeys.Length; i++)
{
if (suKey.ToLower() == ParaKeys[i].ToLower())
{
string rc = skey.GetValue(ParaKeys[i]).ToString(); // Original-Key benutzen
if (suKey == "InstallDate") // UNIX-Zeistempel ab dem 01.01.1970 00:00:00
{
DateTime AnfDate = new DateTime(1970, 1, 1);
var sec = skey.GetValue(ParaKeys[i]); // UINT32 = Sekunden seit dem 01.01.1970 00:00:00 Uhr
DateTime EndDate = AnfDate.AddSeconds((int)sec);
rc = EndDate.ToString();
}
if (suKey == "InstallTime") // Windows-Zeitstempel (?) ab dem 01.01.1600 00:00:00
{
DateTime MilliSec = new DateTime((long)skey.GetValue(ParaKeys[i])); // UINT64 = ulong MilliSekunden seit 1600
DateTime EndDate = MilliSec.AddYears(1600); // 01.01.1600 dazu zählen
rc = EndDate.ToString();
}
return rc;
}
} // for
return "";
} // private static string HoleRegValue
}
}
Zugriff verweigert kommt nur manchmal, beim zweiten CLEAN klappt es.
Ich möchte in einem Programm ermitteln, ob das Programm unter Windows 10 oder 11 (besser in welchem Windows XP, 7, 8.1. 10, 11) läuft.
Das Programm mache ich mit C# unter VS2022.
Es geht eigentlich ganz einfach mit
string description = RuntimeInformation.OSDescription;
Hier die Ergebnisse:
Windows 10 liefert ⇒ Microsoft Windows 10.0.19045 <= Build
Windows 11 liefert ⇒ Microsoft Windows 10.0.22621 <= Build
Muss man nun abfragen ; Build > 22000 = Win11, ansonsten Win10 ?
Ich vermute, dass der Defender der Blockierer ist.
Bei Win10 und 11 benutze ich jeweils nur den Defender als Virenschutz.
Offenbar arbeiten diese Programme bei Win10 und 11 nicht gleich.
Im abgesicherten Modus ist der Defender nicht aktiv.
Und das passiert bei Windows 10:
Microsoft DiskPart-Version 10.0.19041.964
Copyright (C) Microsoft Corporation.
Auf Computer: R980
DISKPART> list disk
Datenträger ### Status Größe Frei Dyn GPT
--------------- ------------- ------- ------- --- ---
Datenträger 0 Online 2794 GB 1024 KB *
Datenträger 1 Online 1863 GB 1024 KB *
Datenträger 2 Online 5589 GB 0 B *
Datenträger 3 Online 931 GB 1024 KB *
Datenträger 4 Online 931 GB 1024 KB *
Datenträger 5 Online 931 GB 1024 KB *
Datenträger 6 Online 960 MB 0 B
DISKPART> select disk 6
Datenträger 6 ist jetzt der gewählte Datenträger.
DISKPART> attributes disk
Aktueller schreibgeschützter Zustand: Nein
Schreibgeschützt : Nein
Startdatenträger : Nein
Auslagerungsdatei-Datenträger : Nein
Ruhezustandsdatei-Datenträger : Nein
Absturzabbild-Datenträger : Nein
Clusterdatenträger : Nein
DISKPART> clean
Der Datenträger wurde bereinigt.
DISKPART> attributes disk
Aktueller schreibgeschützter Zustand: Nein
Schreibgeschützt : Nein
Startdatenträger : Nein
Auslagerungsdatei-Datenträger : Nein
Ruhezustandsdatei-Datenträger : Nein
Absturzabbild-Datenträger : Nein
Clusterdatenträger : Nein
DISKPART>
So sieht es bei Windows 11 aus:
Microsoft DiskPart-Version 10.0.22621.1
Copyright (C) Microsoft Corporation.
Auf Computer: R980
DISKPART> list disk
Datenträger ### Status Größe Frei Dyn GPT
--------------- ------------- ------- ------- --- ---
Datenträger 0 Online 2794 GB 1024 KB *
Datenträger 1 Online 1863 GB 1024 KB *
Datenträger 2 Online 5589 GB 0 B *
Datenträger 3 Online 931 GB 1024 KB *
Datenträger 4 Online 931 GB 1024 KB *
Datenträger 5 Online 931 GB 1024 KB *
Datenträger 6 Online 960 MB 944 MB
DISKPART> select disk 6
Datenträger 6 ist jetzt der gewählte Datenträger.
DISKPART> attributes disk
Aktueller schreibgeschützter Zustand: Nein
Schreibgeschützt : Nein
Startdatenträger : Nein
Auslagerungsdatei-Datenträger : Nein
Ruhezustandsdatei-Datenträger : Nein
Absturzabbild-Datenträger : Nein
Clusterdatenträger : Nein
DISKPART> clean
Fehler in DiskPart: Zugriff verweigert
Weitere Informationen finden Sie im Systemereignisprotokoll.
DISKPART> clean
Der Datenträger wurde bereinigt.
DISKPART> attributes disk
Aktueller schreibgeschützter Zustand: Nein
Schreibgeschützt : Nein
Startdatenträger : Nein
Auslagerungsdatei-Datenträger : Nein
Ruhezustandsdatei-Datenträger : Nein
Absturzabbild-Datenträger : Nein
Clusterdatenträger : Nein
DISKPART>
Wenn ich eine byte[] Array auf ein USB-PhysicalDrive ausgeben will, dann bekomme ich von WIndows 10 den Fehler "Der Zugriff auf den Pfad wurde verweigert.". Unter Windows 11 auf dem gleichen PC funktioniert es ohne diesen Fehler. Bei Win10 klappt es auch im abgesicherten Modus.
Ich muss das USB-Gerät (USB-Stick oder SD-Card im CardReader) zuvor mit DiskPart-CLEAN löschen
und mein Programm bzw. VS2022 mit "Als Administrator ausführen" starten.
So sieht das Ergebnis bei WIndows 10 aus:
<CreateFile> des USB-Laufwerkes "\\.\PhysicalDrive6" = OK
<DeviceIoControl FSCTL_LOCK_VOLUME> OK
<DeviceIoControl FSCTL_DISMOUNT_VOLUME> OK
<FileStream(h, FileAccess.Write> OK
<outPutFile.Write> bei Offset 0x0000000000 von Ges = 0x0000F50000
Fehler bei <write>
~~~~~~~~~~~~~~~~<Exception-Anfang>~~~~~~~~~~~~~~~~~~~~~~
System.UnauthorizedAccessException: Der Zugriff auf den Pfad wurde verweigert.
bei System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
bei System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
bei System.IO.FileStream.Write(Byte[] array, Int32 offset, Int32 count)
bei HkDiskette.Form1.WriteUsb2() in V:\#PgmHK\VC20xx\HKcs\HkDiskette\Form1.cs:Zeile 2380.
~~~~~~~~~~~~~~~~~<Exception-Ende>~~~~~~~~~~~~~~~~~~~~~~~
Und so bei Windows 11
<CreateFile> des USB-Laufwerkes "\\.\PhysicalDrive6" = OK
<DeviceIoControl FSCTL_LOCK_VOLUME> OK
<DeviceIoControl FSCTL_DISMOUNT_VOLUME> OK
<FileStream(h, FileAccess.Write> OK
<outPutFile.Write> bei Offset 0x0000000000 von Ges = 0x0000F50000
DeviceIoControl FSCTL_UNLOCK_VOLUME = OK
"\\.\PhysicalDrive6" 0x80070000: handle closed.
Ausgabe fertig
Hier etwas Code
//#####################################
// USB ausgeben TEST (2)
//#####################################
private void WriteUsb2()
{
string deviceId = @"\\.\PhysicalDrive6";
string DsnEing = @"G:\Test\USB\CF16MB-CARDupd.vhd";
int intOut = 0;
int MaxLenPu = 0x7FFFFE00;
FileInfo f = new FileInfo(DsnEing);
if (!f.Exists)
{
PutLst("Datei " + DsnEing + " existiert nicht\n=> Abbruch");
return;
}
long LenEing = f.Length;
if (DsnEing.ToLower().EndsWith(".vhd"))
{
LenEing -= 512; // Ohne den Fuss-Sektor
}
int LenPu = (int)Math.Min(LenEing, MaxLenPu);
long RestLen = LenEing;
SafeFileHandle h = CreateFile(deviceId, GENERIC_READ | GENERIC_WRITE, 0,
IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (h.IsInvalid)
{
PutLst("Fehler <IsInvalid == true> bei <CreateFile> des USB-Laufwerkes \"" + deviceId + "\"");
return;
}
PutLst("<CreateFile> des USB-Laufwerkes \""+ deviceId + "\" = OK");
if (!DeviceIoControl(h, FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero))
{
PutLst("Fehler DeviceIoControl FSCTL_LOCK_VOLUME");
CloseHandle(h);
return;
}
PutLst("<DeviceIoControl FSCTL_LOCK_VOLUME> OK");
if (!DeviceIoControl(h, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero))
{
PutLst("Fehler DeviceIoControl FSCTL_DISMOUNT_VOLUME");
CloseHandle(h);
return;
}
PutLst("<DeviceIoControl FSCTL_DISMOUNT_VOLUME> OK");
Stream outPutFile = new FileStream(h, FileAccess.Write);
PutLst("<FileStream(h, FileAccess.Write> OK");
byte[] ByPu = null;
int Gelesen = 0;
long LenAusg = 0;
using (FileStream ReadVHD = new FileStream(DsnEing, FileMode.Open, FileAccess.Read,
FileShare.Read, 4096, FileOptions.SequentialScan))
{
while (RestLen > 0)
{
long LeseLen = Math.Min(RestLen, LenPu);
ByPu = new byte[LeseLen];
try
{
Gelesen = ReadVHD.Read(ByPu, 0, (int)LeseLen);
}
catch (Exception ex)
{
PutLst("Fehler beim Lesen der Datei \"" + DsnEing + "\"");
PutLst("~~~~~~~~~~~~~~~~<Exception-Anfang>~~~~~~~~~~~~~~~~~~~~~~");
PutLst(ex.ToString());
PutLst("~~~~~~~~~~~~~~~~~<Exception-Ende>~~~~~~~~~~~~~~~~~~~~~~~");
return;
}
if (Gelesen != LeseLen) break; // => EOF erreicht
try
{
PutLst("<outPutFile.Write> bei Offset 0x" + LenAusg.ToString("X10")+
" von Ges = 0x"+LenEing.ToString("X10"));
outPutFile.Write(ByPu, 0, (int)LeseLen);
LenAusg += LeseLen;
laDiskLw.Text = EdLong(LenAusg, 14) + " / " + EdLong(LenEing, 14) +
" Bytes ausgegeben.";
RestLen -= LeseLen;
Application.DoEvents();
}
catch (Exception ex)
{
PutLst("");
PutLst("Fehler bei <write>");
PutLst("~~~~~~~~~~~~~~~~<Exception-Anfang>~~~~~~~~~~~~~~~~~~~~~~");
PutLst(ex.ToString());
PutLst("~~~~~~~~~~~~~~~~~<Exception-Ende>~~~~~~~~~~~~~~~~~~~~~~~");
return;
}
} // while(RestLen > 0)
} // using (FileStream ReadVHD
if (!DeviceIoControl(h, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero))
{ PutLst("Fehler DeviceIoControl FSCTL_UNLOCK_VOLUME"); return; }
PutLst("DeviceIoControl FSCTL_UNLOCK_VOLUME = OK");
if (!CloseHandle(h))
{
PutLst("\"" + deviceId + "\" 0x" + Marshal.GetHRForLastWin32Error().ToString("X8") + ": close handle error: " +
Marshal.GetHRForLastWin32Error().ToString("X8"));
return;
}
PutLst("\"" + deviceId + "\" 0x" + Marshal.GetHRForLastWin32Error().ToString("X8") + ": handle closed.");
PutLst("Ausgabe fertig");
} // private void WriteUsb2()