Laden...

Probleme mit Registry-Abfrage von zwei Registry-Pfaden

Erstellt von LittleTester vor 2 Jahren Letzter Beitrag vor 2 Jahren 324 Views
L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren
Probleme mit Registry-Abfrage von zwei Registry-Pfaden

Zunächst: Ich habe eine Lösung für das Problem, aber der daraus entstandene Code ist sehr umständlich und lang geworden. Ich hatte überlegt den Code erst in die Rubrik Code-Reviews zu posten und um Vorschläge zu bitten. Da ich aber selbst schon eine Vorstellung davon habe, wie das am Ende aussehen könnte (sollte?), aber daran scheitere habe ich es hier gepostet.

Ich habe hier eine Abfrage in der Registry. Tests auf verschiedenen Rechnern ergab, dass sich der gesuchte Schlüssel in zwei Pfaden verstecken kann.
Ich hatte es mir so vorgestellt, dass ich den Code wie folgt schreibe, aber nun weiß ich nicht, wie ich an den Wert von GetValue komme. Selbst, wenn ich GetValue extra nochmal abfrage, fehlt mir die Variable um auf den Registry-Pfad zuzugreifen. Alle Versuche da was vorne an zu stellen münden in einem Fehler. Könnt ihr mir bitte helfen?


            // Citrix Workspace Version ermitteln
            try
            {
                if (RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\CitrixOnlinePluginPackWeb").GetValue("DisplayVersion") == null)
                {
                    if (RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CitrixOnlinePluginPackWeb").GetValue("DisplayVersion") == null)
                    {
                        MessageBox.Show("Nicht installiert");
                    }
                    else
                    {
                        MessageBox.Show("???");
                    }
                } else
                {
                    MessageBox.Show("???");
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Problem im Abschnitt Citrix Workspace.");
            }

Edit: Achja: Sind beide Pfade ungültig ist der Debugger sehr unglücklich und gibt den gefürchteten "System.NullReferenceException: "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."-Fehler zurück. Ich habe den Beitrag dazu gelesen, komme damit aber nicht weiter.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

2.094 Beiträge seit 2012
vor 2 Jahren

var value = GetDisplayVersionOrNull("...")
    ?? GetDisplayVersionOrNull("...");

if (value == null)
{
    // ...
}
else
{
    // ...
}

Muss keine eigene Methode sein, macht das aber cleaner.

Ach und guck dir das an:
Registry.GetValue(String, String, Object) Methode (Microsoft.Win32)
Erspart dir vermutlich die eigene GetDisplayVersion-Methode.

Und Thema NullReference:

Packs in eine Variable und prüf drauf, in der eigenen Methode kein Problem.
Oder so:


var value = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey("...")?.GetValue("DisplayVersion");

Beachte das Fragezeichen vor "GetValue".

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

4.968 Beiträge seit 2008
vor 2 Jahren

Hallo Little Tester,

du scheinst ja mehrere dieser Registry-Lesemethoden zu haben (und anscheinend immer mit demselben Aufbau)?! Schreib dir eine Methode (mit passenden Parametern) dafür.
Und außerdem solltest du Datenzugriff (Registry) und UI (MessageBox) nicht mischen (s. [Artikel] Drei-Schichten-Architektur), also verwende dafür zwei verschiedene Methoden (in verschiedenen Klassen).

Und dein Exception-Handling ist auch etwas unspezifisch (und nicht sehr aussagefähig): du solltest wenigstens die Exception Message(s) ausgeben bzw. noch besser zusätzlich loggen (Abt wird vermutlich wieder eine Logging-Komponente dafür vorschlagen 😉.

Edit: Am besten legst du dir für die Parameter (Registry-Werte, Texte, ...) eine eigene Datenstruktur an und erzeugst dann ein (statisches) Array davon und rufst dann in einer Schleife die Methode auf (Trennung von Code und Daten).

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Danke für eure Antworten. Jetzt sieht der Code so aus, ist viel schöner und übersichtlicher und funktioniert 🙂. War das so gemeint? Warum muss man bei der Abfrage ?? verwenden und nicht ||. Ist ?? sowas wie eine "X ODER Y"-Abfrage? Dann müsste doch || genauso funktionieren? Für was steht das ? vor dem GetValue? Ich kannte das noch gar nicht.
Die MessageBoxen habe ich nur während der Entwicklung. Wenn es funktioniert landen die Werte natürlich in Variablen.


            // Citrix Workspace Version ermitteln
            try
            {
                var test = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\CitrixOnlinePluginPackWeb").GetValue("DisplayVersion") ?? 
                    RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CitrixOnlinePluginPackWeb").GetValue("DisplayVersion");
                if(test == null)    
                {
                    MessageBox.Show("Nicht installiert");
                    }
                else
                {
                    MessageBox.Show(test.ToString());
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Problem im Abschnitt Citrix Workspace.");
            }

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

309 Beiträge seit 2020
vor 2 Jahren

Warum muss man bei der Abfrage ?? verwenden und nicht ||. Ist ?? sowas wie eine "X ODER Y"-Abfrage? Dann müsste doch || genauso funktionieren? Für was steht das ?

Damit kannst du auf null prüfen, siehe:
https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/operators/conditional-operator
?? und ??= (Operatoren) – C#-Referenz

4.968 Beiträge seit 2008
vor 2 Jahren

Lies dir auch mal die Hinweise zu RegistryKey (bes. der "Wichtig"-Abschnitt) durch, also sollte der Code in eine using-Anweisung gepackt werden (auch wenn nur ausgelesen wird).
Dudurch sollte dein bisheriger Code auch leserlicher werden.

Auch macht m.E. das doppelte Abfragen der Registry (WOW6432Node) keinen Sinn - entweder du benötigst die 32 oder 64-Bit Variante.
Hast du "AnyCPU" im Projekt eingestellt?

Oder ist dein Programm nur ein Test für die installierten Komponenten und benutzt sie selber nicht?

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Danke euch. Ich habe das using bei den Abfragen überall vorne angestellt, wo ein IDisposable in der Definition ist. Das ist ja bei ManagementObjectCollection auch der Fall.

Das Projekt steht definitiv auf AnyCDU, sowohl bei Debug, als auch Release. Den Fehler mache ich nicht noch einmal 😉

Bei der in diesem Thread genannten Abfrage klappt das mit dem using aber nicht. Kann machen was ich will, endet immer in einem Fehler 😡. Das diese Doppelte Abfrage so kompliziert sein muss grummel

Warum sich der Citrix Workspace-Client manchmal in HKLM und manchmal in HKCU einträgt weiß ich nicht. Bei mir hier zu Hause und bei meinem Arbeitsplatz bei meinem einen Arbeitgeber findet sich der Eintrag in HKLM, bei meinem Arbeitsplatz beim anderen Arbeitgeber in HKCU.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

16.864 Beiträge seit 2008
vor 2 Jahren

Oder ist dein Programm nur ein Test für die installierten Komponenten und benutzt sie selber nicht?

Er baut offenbar ein rudimentäres Software-Inventartool.

4.968 Beiträge seit 2008
vor 2 Jahren

Scheint so.

Little Tester: Bei vielen Installationen kann man auswählen, ob für alle Anwender (HKLM) oder nur für den aktuellen Anwender (HKCU) installiert werden soll.

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Kann natürlich sein. Bei dem einen Arbeitgeber, wo ich der Admin installiere ich die Software immer als Admin von Hand. Habe da leider auch keinen Server der das machen könnte. Der zweite Arbeitgeber, wo ich nur ein kleines Licht in der Abteilung bin hat hingegen eine gigantische IT-Infrastruktur mit SCCM und co. zur Verfügung. Denke mal, dass es da deswegen anders installiert wurde. Aber so prüfe ich jetzt einfach beide Pfade. Schadet ja auch nicht und gelernt habe ich auch gleich was.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6