Laden...

Mehrere Bildschirme ermitteln und getrennt! anzeigen und die echte Auflösung ermitteln

Erstellt von LittleTester vor 2 Jahren Letzter Beitrag vor 2 Jahren 1.030 Views
L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren
Mehrere Bildschirme ermitteln und getrennt! anzeigen und die echte Auflösung ermitteln

Ich möchte ermitteln, ob an einem Computer mehrere Bildschirme angeschlossen sind. Das ist mir bereits gelungen.
Nun möchte ich die Bildschirme aber auch sauber getrennt nach Bildschirm 1 und Bildschirm2 anzeigen lassen und da klemmt es momentan.

Außerdem möchte ich die Auflösung des Bildschirm ermitteln die er wirklich kann. Wenn ich die Auflösung beispielsweise auf 125% skaliere, dann sagt mir das Programm der Bildschirm hätte eine Auflösung von 1536 x 864. Stimmt natürlich nicht. Der Bildschirm kann eine Auflösung von 1920 x 1080 und nur das interessiert mich. Die Information, dass der Anwender skaliert hat wäre vielleicht nett zu wissen, aber so sehr als das ich da jetzt (schon) recherchiert habe interessiert mich das im Grunde nicht. Fürs Inventar spielt es keine Rolle was der Anwender eingestellt hat.

Außerdem muss ich feststellen, dass "monitorResolution" beim zweiten Bildschirm die gleiche Auflösung anzeigt wie beim ersten. Ich denke das liegt am "Screen.PrimaryScreen.Bounds.[...]". "screen.Bounds.ToString());" zeigt es richtig an, aber in einer Art und Weise, wie mir das nicht gefällt (Siehe Anhang)

Anbei erstmal der Code:


            // Monitor(e) ermitteln
            // https://mycsharp.de/forum/threads/111965/wmi-object-vom-typ-uint16-wie-in-string?page=1#forumpost-3758901
            try
            {
                foreach (var screen in Screen.AllScreens)
                {
                    ManagementObjectCollection mozReturn;
                    ManagementObjectSearcher mozSearch;

                    mozSearch = new ManagementObjectSearcher(@"root\wmi", "SELECT * FROM WmiMonitorID");
                    mozReturn = mozSearch.Get();
                    foreach (ManagementObject moz in mozReturn)
                    {
                        string monitorname = "";
                        string seriennummer = "";
                        dynamic dynName;
                        dynamic dynSerial;
                        dynName = moz["UserFriendlyName"];
                        dynSerial = moz["SerialNumberID"];

                        for (int i = 0; i < 10; i++)
                        {
                            monitorname += Char.ConvertFromUtf32(dynName[i]);
                            seriennummer += Char.ConvertFromUtf32(dynSerial[i]);
                        }
                        monitorModel += monitorname + " | ";
                        monitorSerial += seriennummer + " | ";
                    }
                    var screenWidth = Screen.PrimaryScreen.Bounds.Width.ToString();
                    var screenHeight = Screen.PrimaryScreen.Bounds.Height.ToString();

                    monitorResolution += screenWidth + " x " + screenHeight + " | ";

                    // For each screen, add the screen properties to a list box.
                    listBox1.Items.Add("Device Name: " + screen.DeviceName);
                    listBox1.Items.Add("Bounds: " + screen.Bounds.ToString());
                    listBox1.Items.Add("Type: " + screen.GetType().ToString());
                    listBox1.Items.Add("Working Area: " + screen.WorkingArea.ToString());
                    listBox1.Items.Add("Primary Screen: " + screen.Primary.ToString());
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Problem im Abschnitt Monitore.");
            }

Das listBox ist natürlich nur temporär während der Programmierung. Kommt später weg.

Freue mich, wenn ihr mir auch da weiterhelfen könnt.

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

C
2.121 Beiträge seit 2010
vor 2 Jahren

Ich denke das liegt am "Screen.PrimaryScreen.Bounds.[...]"

Wenn du nur nach dem ersten Bildschirm fragst, bekommst du in der Tat auch nur den ersten zu sehen.

screen.Bounds.ToString());" zeigt es richtig an, aber in einer Art und Weise, wie mir das nicht gefällt (Siehe Anhang)

Mal ne irrwitzige Idee, was wenn du die Ausgabe in der Form die du haben willst ganz einfach nicht immer nur mit dem selben Screen.PrimaryScreen.Bounds.Width machst, sondern mit dem aktuellen screen.Bounds.Width?

4.939 Beiträge seit 2008
vor 2 Jahren

Und warum hast du die 2 Schleifen verschachtelt (keine hat mit der anderen etwas zu tun)?

Und die Abfrage auf i < 10 (bzw. die ganze Zeichenumwandlung) ist äußerst fehlerhaft.

Naja, das kommt wohl, wenn man einfach Code aus dem Internet kopiert (ohne ihn zu verstehen)...

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

Das mit dem "screen.Bounds" ist echt gemein. Mit großen "Screen" wird das nämlich nicht angeboten. Ich hatte es mit "Screen.AllScreens" und "Screen.Bounds" probiert, aber ohne Erfolg.

Warum ich da zwei Schleifen ineinander gebaut habe? Tja, weil dumm. So Anfänger bin ich eigentlich nicht mehr als das ich das für mich selbst als Entschuldigung sehe. (Gilt vielleicht die Uhrzeit? 😄) Habs natürlich sofort getrennt.
Das mit dem "i < 10" ist natürlich Mist. Habe heute gemerkt, dass eine 12-Stellige Seriennummer nicht komplett angezeigt wird. Bei meinem Arbeitgeber mit Dell-Bildschirmen und 12 Stellen haben entsprechend zwei Stellen gefehlt. Ich gucke, wie man das lösen kann. seriennummer += Char.ConvertFromUtf32(dynSerial); ist zwar codetechnisch richtig (IDE gibt keinen Fehler), aber beim Debug gibts ne Exception.

Die beste Übereinstimmung für die überladene char.ConvertFromUtf32(int)-Methode enthält einige ungültige Argumente.

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

190 Beiträge seit 2012
vor 2 Jahren

Hallo,
schau dir mal dieses Programm an: WMI Code Creator v1.0.
Es erzeugt dir fertigen Code und du siehst gleich, was dabei rauskommt.

  • Wer lesen kann, ist klar im Vorteil
  • Meistens sitzt der Fehler vorm Monitor
  • "Geht nicht" ist keine Fehlermeldung!
  • "Ich kann programmieren" != "Ich habe den Code bei Google gefunden"

GidF

C
2.121 Beiträge seit 2010
vor 2 Jahren

Das mit dem "screen.Bounds" ist echt gemein. Mit großen "Screen" wird das nämlich nicht angeboten.

Was ist gemein und was wird nicht angeboten?

D
261 Beiträge seit 2015
vor 2 Jahren

Mit

großen "Screen"

meinte er den statischen Zugriff auf System.Windows.Forms.Screen (Api-Docs) direkt und nicht auf eine Instanz davon. Und dort gibt es eben kein statisches Property "Bounds".
Was aber natürlich auch logisch ist, weil es kein Bounds über alle Screens geben kann. Die Screens könnten total unterschiedlich groß sein und total wirr angeordnet sein.

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

Als Einsteiger kann das schon ne Falle sein ⚠

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

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

So, ich habe jetzt immer wieder und heute quasi den ganzen Tag (auch auch die Tage davor immer wieder mal) damit zugebracht eine neue Lösung zu finden. Nachdem Th69 geschrieben hat, dass die ganze Umwandlung vom ersten Post eh für den Eimer ist (womit er natürlich vollkommen Recht hat) habe ich jetzt hoffentlich die richtige Lösung gefunden. Leider schaffe ich es jetzt nicht mehr, dass beide Bildschirme gefunden werden. Kann hier bitte jemand nachhelfen? Ich will aber ohnehin, dass beide Bildschirme separat gelistet werden, also beispielsweise so:


Monitor 1: Modell, Seriennummer, Größe, Auflösung
Monitor 2: Modell, Seriennummer, Größe, Auflösung


                var searcher = new ManagementObjectSearcher (@"root\wmi", "SELECT * FROM WmiMonitorID");

                foreach (ManagementObject ufn in searcher.Get())
                {
                    if (ufn["UserFriendlyName"] == null)
                    {
                        monitorModel = "Keine Bezeichnung";
                    }
                    else
                    {
                        ushort[] ufnArray = (ushort[])ufn["UserFriendlyName"];
                        foreach (ushort ufnValue in ufnArray)
                        {
                            var ufnASCIIBytes = new byte[] { (byte)ufnValue };
                            monitorModel += Encoding.ASCII.GetString(ufnASCIIBytes);
                        }
                    }
                }

                foreach (ManagementObject sn in searcher.Get()) {
                    if (sn["SerialNumberID"] == null) {
                        monitorModel = "Keine Seriennummer";
                    } else {
                        ushort[] snArray = (ushort[])sn["SerialNumberID"];
                        foreach (ushort snValue in snArray) {
                            var snASCIIBytes = new byte[] { (byte)snValue };
                            monitorSerial += Encoding.ASCII.GetString(snASCIIBytes);
                        }
                    }
                }

Komischerweise werden mit dieser Lösung beide Auflösungen richtig erkannt


                // Bildschirm-Auflösung ermitteln.
                try {
                    foreach (var screen in Screen.AllScreens) {
                        var screenWidth = screen.Bounds.Width.ToString();
                        var screenHeight = screen.Bounds.Height.ToString();

                        monitorResolution += screenWidth + " x " + screenHeight + " | ";
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Systeminventory hat ein Problem im Abschnitt Bildschirm-Auflösung.");
                }

Und auch dieser Code gibt mit beide Bildschirmgrößen zurück, wenngleich mein Fernseher, der für diesen Test herhalten muss schon etwas größer als 7" ist. (19 Zoll Breitbild oder so, kleiner als mein 24" auf jeden Fall. Unterm Strich ist es auch egal.)


                // Monitorgröße ermitteln
                // https://www.c-sharpcorner.com/forums/get-the-monitor-size
                try 
                {
                    ManagementObjectCollection mozReturn1;
                    ManagementObjectSearcher mozSearch1;

                    mozSearch1 = new ManagementObjectSearcher(@"root\wmi", "SELECT * FROM WmiMonitorBasicDisplayParams");
                    mozReturn1 = mozSearch1.Get();

                    foreach (ManagementObject moz1 in mozReturn1) {
                        double width = (byte)moz1["MaxHorizontalImageSize"] / 2.54;
                        double height = (byte)moz1["MaxVerticalImageSize"] / 2.54;
                        double diagonal = Math.Sqrt(width * width + height * height);
                        monitorSize += Math.Round(diagonal, 0).ToString() + "\" | ";
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Systeminventory hat ein Problem im Abschnitt Bildschirmgröße.");
                }

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

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

Ich frage dann nochmal zaghaft nach, ob sich wer der Thematik annehmen will. Konnte es bislang nicht lösen.

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

4.939 Beiträge seit 2008
vor 2 Jahren

Verstehe ich das richtig, daß dein erster Code nicht beide Monitore liefert, die beiden anderen Codes aber schon?
Dann scheint das aber ein WMI-spezifisches Problem zu sein.

Um die Daten zusammenzuführen, solltest du eine eigene Klasse mit den passenden Eigenschaften erstellen (und davon dann eine List<> oder Dicitonary<> erzeugen) - und die ToString()-Methode überladen, welche den von dir gewünschten Text erzeugt.

Du benötigst dann aber jeweils ein eindeutiges Kriterium für die verschiedenen Abfragen, um einen Monitor zu identifizieren (z.B. MonitorId oder MonitorName), damit du die Daten dann dem richtigen Eintrag in der Liste zuordnen kannst.

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

Jetzt bin ich vollends irritiert.

Ich wollte euch eben zeigen, dass der Code funktionierte (in dem Sinn, dass er beide Bildschirme ausgab) als ich die Konvertierung noch falsch gemacht habe und habe es entsprechend rückgängig gemacht.
Das Ergebnis ist dann als Textbox:

// Wieso das doppelt ist verstehe ich nicht.
MSI MAG241 | ORIONMSI MAG241 | ORION

Als Label:

// Das Ausgabeformat war erstmal ganz OK, wenngleich noch nicht brauchbar.
MSI MAG241 | ORION

Naja, ist ja eh falsch gewesen, also den richtigen Code genommen, also das mit


monitorModel += Encoding.ASCII.GetString(ufnASCIIBytes);

Je nachdem wie ich mir das ausgeben lasse erhalte ich unterschiedliche Ergebnisse:
Als textBox2.Text ist es:

// Ergebnis wie erwartet und nachvollziehbar
MSI MAG241CRORION

Als label26.Text ist es:

// Ergebnis wie erwartet und nachvollziehbar. Durch das += hänge ich ja einen String an.
label26MSI MAG241CRORION

Als monitorModel, das weiter unten dann dem Label zugewiesen wird, also "lblMonitorModel.Text = monitorModel;" ist es dann

// Ergebnis nicht verständlich. Wieso wird der zweite Monitor jetzt unterschlagen?
MSI MAG241CR

Nimmt man das += raus und macht ein einfach = gibt es nichts aus.

Wisst ihr nun weiter? Von der Sache her werden doch eigentlich beide Bildschirme ermittelt und ausgegeben. ORION ist übrigens mein Fernseher der für diesen Test halt herhalten muss.

Edit: Achja, wenn ich mir das Trennzeichen am Ende hinmache, also


textBox2.Text += Encoding.ASCII.GetString(ufnASCIIBytes) + "|";

gibt es ein Ergebnis wie dieses: (Beispiel anhand von textBox2.Text)

M|S|I| |M|A|G|2|4|1|C|R|O|R|I|O|N|

Mir ist aber klar warum, wollte es nur der Vollständigkeit halber noch dazu schreiben, weil ich es ja im Gegensatz zu oben dann rausgenommen hatte.

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

2.298 Beiträge seit 2010
vor 2 Jahren

Ich würde schon mal vorschlagen, erst das Bytearray einzulesen und dann die Seriennummer auszugeben.
Spart dir nämlich eine ganze Schleife für die Ausgabe.

// EDIT: Ach nein. Du hast ja gar keine zusätzliche Schleifen.
// Dennoch weiterhin. Hole dir erst das vollständige Array und schreibe dann den Text in die Textbox.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |