Laden...

Forenbeiträge von LittleTester Ingesamt 158 Beiträge

10.07.2021 - 20:29 Uhr

Ich poste das mal in den Grundlagen, weil ich denke ein Datum in ein anderes Format umwandeln ist eine Grundlage der Programmierung. Hoffe das passt so.
Also folgender Code funktioniert bestens:


            // Letzter Boot-Zeitpunkt auslesen
            try
            {
                var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
                using (ManagementObjectCollection managementObjectCollection = searcher.Get())
                {
                    ManagementObject managementObject = managementObjectCollection.OfType<ManagementObject>().FirstOrDefault();

                    string stringDate = managementObject["LastBootUpTime"].ToString();
                    DateTime dt = ManagementDateTimeConverter.ToDateTime(stringDate);
                    systemLastStart = dt.ToLongDateString();
                    computerLocation = managementObject["Description"].ToString();
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Problem im Abschnitt Letzter Boot-Zeitpunkt");
            }

Bekomme dann ein gutes Ergebnis wie

Mittwoch, 7. Juli 2021

Ich benutze den gleichen Code nun für die Abfrage von Win32_QuickFixEngineering und dem managementObject["InstalledOn"].
Das gibt folgenden Fehler:

System.ArgumentOutOfRangeException: Das angegebene Argument liegt außerhalb des gültigen Wertebereichs.
Parametername: dmtfDate bei System.Management.ManagementDateTimeConverter.ToDateTime(String dmtfDate)

Schreibt man den Code wie folgt, dann gibt es ein Datum wie dieses zurück:


[...]
systemLastWindowsUpdate = managementObject["InstalledOn"].ToString();
[...]

6/22/2021

Also recherchiert, gemacht und getan, wie man das Format mm/dd/yyyy umwandeln kann.
Scheinbar guter Treffer hier.
Code umgesetzt, aber es gibt folgenden Fehler:



[...]
using System.Globalization;

string d = Convert.ToDateTime("09/25/2011").ToString("dd/MM/yyyy"); //returns 25/09/2011
DateTime date = DateTime.Parse("09/25/2011", new CultureInfo("en-GB")); // returns 09/25/2011
string d2 = date.ToString("dd/MM/yyyy"); //should return 25/09/2011
systemLastWindowsUpdate = d.ToString();
[...]

System.FormatException: Die Zeichenfolge wurde nicht als gültiges DateTime erkannt.
bei System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
bei System.Convert.ToDateTime(String value)

Auch folgender Versuch scheitert mit

System.ArgumentOutOfRangeException: Das angegebene Argument liegt außerhalb des gültigen Wertebereichs.
Parametername: dmtfDate bei System.Management.ManagementDateTimeConverter.ToDateTime(String dmtfDate)


            try
            {
                var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_QuickFixEngineering");
                using (ManagementObjectCollection managementObjectCollection = searcher.Get())
                {
                    ManagementObject managementObject = managementObjectCollection.OfType<ManagementObject>().FirstOrDefault();
                    string stringDate = managementObject["InstalledOn"].ToString();
                    DateTime dt = ManagementDateTimeConverter.ToDateTime(stringDate);

                    int day = dt.Day;
                    int month = dt.Month;
                    int year = dt.Year;

                    string date = (year + "-" + month + "-" + day).ToString();

                    systemLastWindowsUpdate = date;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                //MessageBox.Show("Problem im Abschnitt Windows Update.");
            }

Ich habe natürlich mehr recherchiert und probiert, aber ich komme nicht zum Erfolg. Kann mir bitte jemand sagen, wo es nun schon wieder klemmt?
Als kleiner Bonus suche ich noch die Möglichkeit Win32_QuickFixEngineering nach dem letzten Datum zu sortieren und nur dieses dann auszugeben.

10.07.2021 - 19:23 Uhr

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.

10.07.2021 - 10:08 Uhr

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.");
            }

10.07.2021 - 01:57 Uhr

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.

08.07.2021 - 15:32 Uhr

OK, ich frage dann einfach $später nochmal nach. Dachte es ist einfach nur ne Einstellung, wo man eine Zahl einträgt und fertig.

08.07.2021 - 02:50 Uhr

Ich kann die Gründe nachvollziehen, gerade das Argument des Vandalismus, wenn jemand (im Zorn) die Community verlässt oder wie hier, als jemandem geholfen wurde und zum "Dank" dann seinen Code wieder löschen wollte.

Ob es da nicht ausreichen würde das zu verhindern, sobald eine Antwort gekommen ist oder das Zeitlimit so "eng" gefasst sein muss ist eine andere Sache. Ich will da auch nicht weiter drauf rumreiten, weil es eine Entscheidung eurerseits ist. Ich hatte es angeregt, wurde begründet abgelehnt und es ist für mich auch OK.

Kann man es aber vielleicht trotzdem so machen, dass die ersten paar Minuten nach Absenden eine Änderung noch nicht als solche Markiert wird, wenn man eine vor nimmt? Ich mache das relativ häufig, trotz Vorschaufunktion. Ist irgendwie ne Krankheit, dass ich hinterher nochmal was ändere, vor allem klarer machen möchte oder dann doch noch ein (Rechtschreib-) Fehler auffällt. Ärgere mich dann selbst und würde es gerne vertuschen.

08.07.2021 - 02:35 Uhr

Danke für deine Hinweise Abt. Ich habe das Projekt wieder umgestellt. Das "Problem" ist wohl, dass beim Aufruf von regedit unter Windows die x64-Version genommen wird, während unter Visual Studio (zumindest C#) standardmäßig die x86-Version genommen wird. Da können die Pfade dann manchmal nicht identisch sein. (Quelle)

Ich habe mir jetzt so beholfen, dass ich folgenden Code verwende, wenn ich die explizit die x64-Version der Registry haben will. Ich hoffe das findet eure Zustimmung.


                RegistryKey findeEintrag = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"Pfad");

07.07.2021 - 17:53 Uhr

Ich habe mein kleines Projekt, dass momentan als .net 4.8 läuft, kurzerhand mal in eine .net 5 App kopiert. Läuft soweit auch ganz gut. Ob das bei meinem Mini-Projekt jetzt Sinn macht das auf .net 5 App umzustellen sei erstmal dahingestellt (was meint ihr? LTS wird es eh erst mit .net 6 geben.) Allerdings sind zwei Pakete nicht ganz mit .net 5 kompatibel und ich bekomme eine entsprechende Warnung. (Scheint trotzdem alles zu funktionieren, aber ist natürlich trotzdem keine Basis auf der man (weiter) arbeiten will) Auf Github wurde die Kompatibilität bereits hergestellt, aber noch nicht als Nuget veröffentlicht.

Bei dem einen Projekt handelt es sich um AutoUpdater.NET
Das Andere ist WindowsAPICodePack Bei diesem liegt die Bitte für ein Nuget-Release seit 8. Januar vor, aber ist halt bislang nicht passiert.

Die Frage ist also, ob man sich aus dem Github-Repository selbst ein Nuget Paket machen kann oder es anderweitig möglich ist die neusten Änderungen zu nutzen?

06.07.2021 - 22:01 Uhr

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.");
                }

05.07.2021 - 23:03 Uhr

Ich möchte es nicht "Resistenz" nennen. Das klingt so nach "uneinsichtig" und "besserwisserisch". Ich komme mit dem Stil besser klar. Das ist alles. Ich habe sonnst keine "Dafür" oder "Dagegen" Gründe.

Ich will aber gucken dran zu denken den Code anzupassen, wenn ich im Forum stelle, damit ihr es einfacher habt. Seid mir aber bitte nicht böse, wenn ich es mal vergesse oder mal ne Klammer übersehe.

05.07.2021 - 22:46 Uhr

Hmmm, es ist Java-Codestil? DAS wäre wirklich ein Argument von dem Stil Abstand zu nehmen. Wieso programmiert man in Java so und in anderen Programmiersprachen anders? Gibts da Gründe für?

Was das Programmieren in "etablierten" Teams angeht. So gut werde ich wohl nicht, als das ich da mitmischen könnte 😉. Bin ja froh, wenn ich mit meinem eigenen Code klar komme. - und ihr.

05.07.2021 - 21:55 Uhr

Also ich finde die Standardformatierung aus oben genannten Gründen nicht so toll. Als Argument kommt noch hinzu, dass der sich der Code unnötig in die Länge zieht. Mit "meiner" Methode ist er viel kompakter.

Ich denke da bin ich nicht der Einzige der "meinen" Codestil favorisiert, sonnst wäre das ja nicht in Visual Studio einstellbar, oder?

05.07.2021 - 21:43 Uhr

Ich würde mir wünschen, dass man so lange editieren kann, bis jemand geantwortet hat und darüber hinaus auch dann die Zeit in der Foren / Threadübersicht entsprechend aktualisiert wird.
Welchen Grund gibt es denn, dass man einen Beitrag nach 30 Minuten nochmal editieren muss?
Da ist doch wirklich mehr als genug Zeit, wenn etwas unüberlegt war. Diesen zum Beispiel oder wenn über Stunden noch keine Antwort kam und man selbst weitere Informationen hat oder schon etwas weiter kam. Anpassen von Datum / Uhrzeit deswegen falls schon jemand rein geguckt hat.

05.07.2021 - 21:34 Uhr

dannoe hatte Recht. Habe da wohl bissel rumgespielt gehabt. Danke dir.

Als ich die Zielplattform "Any CPU" umgestellt habe werden die beiden Softwares nicht mehr erkannt. Als ich es auf x64 umgestellt habe hingegen schon.

Ich habe es jetzt für den Debug-Modus und Release-Modus auf x64 gestellt. x86 ist ja eh veraltet und x86-Betriebssysteme werden bei uns nicht mehr eingesetzt. Oder spricht was dagegen die Architektur auf x64 umzustellen?

05.07.2021 - 19:45 Uhr

Ich hatte gerade das Problem, dass ich einen Beitrag editieren / was hinzufügen wollte, dass aber nur 30 Minuten nach Erstellung geht. Es gab noch keine Antwort.
Ich würde mir wünschen, dass man so lange editieren kann, bis jemand geantwortet hat und darüber hinaus auch dann die Zeit in der Foren / Threadübersicht entsprechend aktualisiert wird.

Außerdem erscheint eine 403-Fehlerseite (weil ich vor Ablauf der Zeit das Editieren begonnen habe, aber nach dem Ablauf posten wollte) und das editierte / neu hinzugefügte ist weg. War in dem Fall nicht schlimm, aber wenn man etwas mehr editiert kann das schon ärgerlich sein. 😠

Nett wäre es auch, wenn die ersten ~5 Minuten nach Erstellung nicht angezeigt wird, das editiert wurde.

05.07.2021 - 19:42 Uhr

Mist, paar Sekunden zu spät zum Editieren:

Ich habe das Programm gerade auf einem Rechner laufen lassen, wo ESET installiert ist. Auch hier das Problem, dass es im Debug-Modus nicht erkannt wird, im Release-Modus schon.
Der Pfad lautet:

Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ESET\ESET Security\CurrentVersion\Info");

Ich bin mit Adminrechnten auf den Rechner, weil ich da heute eh ne Fernwartung drauf mache. Es macht also keinen Unterschied, ob das Programm mit oder ohne Adminrechten läuft.

05.07.2021 - 19:10 Uhr

Danke für deine Antwort:

Also das Programm teste ich auf meinem Geschäftsrechner mit Benutzerrechten (keine Adminrechte), so wie das nachher auch laufen wird.
Ich teste die Release und Debug-Variante immer mit dem gleichen Benutzer.

Das mit der Variable habe ich korrigiert. Hast natürlich vollkommen Recht. Danke für diesen Hinweis.
Ich habe die Abfrage angepasst:


            // Dell Command Update Version ermitteln
            try 
            {
                RegistryKey findDCU = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Dell\UpdateService\Clients\CommandUpdate\Preferences\Settings");
                if (findDCU != null)
                {
                    Object dcuVersion = findDCU.GetValue("ProductVersion");
                    if (dcuVersion != null)
                    {
                        string version = dcuVersion.ToString();
                        softwareDellCommandUpdate = version;
                    } 
                    else
                    {
                        softwareDellCommandUpdate = "Version unbekannt";
                    }
                } 
                else
                {
                    softwareDellCommandUpdate = "Nicht installiert";
                }
            } 
            catch (Exception)
            {
                MessageBox.Show("Systeminventory hat ein Problem im Abschnitt Dell Command Update.");
            }

Im Debug-Modus steigt er bei "Nicht installiert" aus, scheint also ein Problem mit dem Pfad zu haben, aber warum? Was macht der Debug-Modus anders als der Release-Modus?

05.07.2021 - 12:22 Uhr

Wenn ich folgenden Code verwende, um den Versionsstand einer Software (in dem Fall Dell Command Update) auszulesen erhalte ich im Debug-Modus die Meldung, dass die Software nicht installiert sei. Im Release-Modus wird hingegen die Installation, bzw. die Version erkannt. Ich verwende die gleiche Methodik um auch andere Softwareversionen zu erfragen und das klappt sonnst ganz gut. Hier der Code der Problemsoftware:


            // Dell Command Update Version ermitteln
            try {
                RegistryKey findDCU = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Dell\UpdateService\Clients\CommandUpdate\Preferences\Settings");
                if (findDCU != null) {
                    Object dcuVersion = findDCU.GetValue("ProductVersion");
                    if (dcuVersion != null) {
                        string version = findDCU.GetValue("ProductVersion").ToString();
                        softwareDellCommandUpdate = version;
                    } else {
                        softwareDellCommandUpdate = "Nicht installiert";
                    }
                } else {
                    softwareDellCommandUpdate = "Nicht installiert";
                }
            } catch (Exception) {
                MessageBox.Show("Systeminfo hat ein Problem im Abschnitt Dell Command Update.");
            }

Und hier mal der Code, der sowohl im Debug-Modus, als auch im Release-Modus funktioniert.


            // MS-Teams Version ermitteln
            try {
                RegistryKey findMsTeams = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Teams");
                if (findMsTeams != null) {
                    Object msteamsVersion = findMsTeams.GetValue("DisplayVersion");
                    if (msteamsVersion != null) {
                        string version = findMsTeams.GetValue("DisplayVersion").ToString();
                        softwareMsTeams = version.Substring(0, 5);
                    } else {
                        softwareMsTeams = "Nicht installiert";
                    }
                } else {
                    softwareMsTeams = "Nicht installiert";
                }
            } catch (Exception) {
                MessageBox.Show("Systeminfo hat ein Problem im Abschnitt MS-Teams.");
            }

Jemand eine Idee, warum das so sein könnte?

03.07.2021 - 23:16 Uhr

Es gibt leider wirklich eine Exception. Offline oder nicht vorhandener Host ist offenbar nicht vorgesehen 🐛

03.07.2021 - 21:28 Uhr

Ja, ich fände eine Art "Danke"-Button oder so auch super. Ich habe jetzt schon so viel freundliche Hilfe bekommen, dass ich schon ein schlechtes Gewissen habe, weil man irgendwie so nichts zurückgeben kann. Denke treu dem "Jäger und Sammler"-Prinzip wäre es gut, wenn helfende Personen "Dankes" sammeln könnten.

03.07.2021 - 18:47 Uhr

Standardmäßig macht Visual Studio den Code ja so:


            try
            {
                if(Foo == Bar)
                {
                    // Mach was
                }
                else
                {
                    // Mach was anderes
                }
            } catch (Exception ex)
            {
                // Fehler
            }

Ich hätte das aber gerne so:


            try {
                if(Foo == Bar) {
                    // Mach was
                } else {
                    // Mach was anderes
                }
            } catch (Exception ex) {
                // Fehler
            }

Natürlich kann ich das immer von Hand so umformatieren, aber wenn ich dann irgendwas ändere und wieder Enter drücke, kann es sein das Visual Studio das wieder anpasst.
Gibt es eine Möglichkeit das zu ändern? Ich finde den Codestil von mir besser lesbar. Außerdem verballert man als kleinen Nebeneffekt keine extra Zeile für ein {.

03.07.2021 - 12:18 Uhr

Als Einsteiger kann das schon ne Falle sein ⚠

03.07.2021 - 01:32 Uhr

Ich habe die Funktion <checksum algorithm="MD5"></checksum> bzw. <checksum algorithm="SHA1"></checksum> ausprobiert und testweise eine MD5 und SHA1 Checksumme erstellt. Bekomme beim Update, bzw. schon beim Download immer:

Die Dateiintegritätsprüfung ist fehlgeschlagen und hat einige Fehler gemeldet.

Die Hashwerte wurden mittels


PowerShell
certutil -hashfile .\Update.zip MD5

bzw.


certutil -hashfile .\Update.zip SHA1

erstellt. Bestimmt liegt der Fehler bei mir.

02.07.2021 - 15:46 Uhr

Erstmal soll mir das reichen, ja. Dennoch wird es mit Fertigstellung der Version 1 an die Version 2 gehen.

02.07.2021 - 15:28 Uhr

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.

02.07.2021 - 14:57 Uhr

Cool, das funktioniert. Aber ob die anderen wollten, dass ich das erfahre? 😁

02.07.2021 - 02:31 Uhr

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.

01.07.2021 - 18:38 Uhr

Hmmm, also entweder habe ich mich jetzt total in die falsche Richtung verbissen oder es ist mit Flurl wirklich nicht möglich in C# eine Rückmeldung von PHP zu erhalten oder ich mache was grundlegend falsch mit der Libray. Ich habe folgenden PHP Code ergänzt:


	# Prüfen, ob es die Seriennummer in der Datenbank gibt.
	$db_read = "Select computerSerial from db_computer where computerSerial=?";
	$db_prepare = $db_connect->prepare($db_read);
	$data = array($_POST['computerSerial']);
	$db_prepare->execute($data);

	$number = $db_prepare->rowCount();
	# Falls kein Eintrag gefunden wurde, Vorgang abbrechen
	if ($number = 0) {
		echo "Computer nicht in der Datenbank";
[...]

Zumindest das "Computer nicht in der Datenbank" hätte ich gerne als MessageBox.Show in C#. Wenn MySQL selbst einen Fehler wirft, beispielsweise weil man Mist in der Syntax oder so gebaut hat, wäre es natürlich auch schön das zu bekommen.

01.07.2021 - 00:19 Uhr

Komplex Thematik und alles in englisch. Mach mich nicht unglücklich 😭

30.06.2021 - 18:13 Uhr

Danke für eure Antworten und die Aufklärung / Hinweise.

Kann mir nun noch jemand sagen, wie ich vom PHP eine Rückmeldung in C# verarbeiten kann? Wenn man nach "C# PHP" und vergleichbaren Suchbegriffen sucht findet man halt immer Beispiele und Anfragen, wie man von C# etwas nach PHP schicken kann, aber nicht umgekehrt. Wenn das mit Flurl zu bewerkstelligen ist wäre das natürlich echt Klasse. Ist mir ne sympathische Libray, weil sie so wenig Code erfordert und damit auch leicht zu verstehen ist 😄.

Zum Ablauf des Programms:

Im Webinterface trage ich die Seriennummer (und einige andere Dinge, wie beispielsweise Rechnungsdatum und so) des Rechners in ein Formular ein und schicke das in die Datenbank.
Das C# Tool soll dann die Inventardaten liefern und orientiert sich an der Seriennummer. Was nun aber, wenn es in der Datenbank die Seriennummer gar nicht gibt? Zumindest dafür braucht es eine Rückmeldung.

30.06.2021 - 09:47 Uhr

Ja, ich hatte mir überlegt, ob das eher ein Thema fürs PHP-Forum wäre, aber das PHP-Script wird ja aus C# heraus aufgerufen und mit Daten gefüttert. Daher denke ich muss auch alles von der Anwendung kommen? Zudem möchte ich die Antwort des PHP-Scripts in der C#-Anwendung sehen. Das SQL-Statement ist natürlich mittels Prepared Statement abgesichert.

30.06.2021 - 00:54 Uhr

Hallo liebe Gemeinschaft,

zunächst: Mir wurde in diesem Thread das das Erstellen einer Web-API mit ASP.NET Core empfohlen und ein Tutorial verlinkt. Ich habe es versucht nach zu bauen und absolut nichts verstanden. Ich schätze ich bin noch nicht so weit.

Ich wollte mich dann mit dem Thema WebClient befassen, aber irgendwie hatte ich immer nur Beispiele mit $_GET gefunden, woran ich mich ziemlich störte. Zudem habe ich sehr viele Daten zu übertragen. Das wäre über die URL totaler Quatsch gewesen, (wenn das überhaupt gegangen wäre).

Ich habe dann die Libray Fluent HTTP entdeckt. Genau mein Geschmack. Total einfach. Ruckzuck war der entsprechende Code geschrieben. Sieht im groben so aus:


using Flurl.Http;
        string securityKey = "$2y$10$GRcTbg!q2fj/7fSMgz0Eef4uFrbAFM8jILV2b((4bK323OFl57o1a";

var responseString = await "https://example.tld/update_db.php"
                .PostUrlEncodedAsync(new {
                    securityKey = securityKey,
                    computerName = computerName,
                    computerModel = computerModel,
                    computerType = computerType,
                    computerSerial = computerSerial
                })
                .ReceiveString();

Das PHP-Script sieht so aus:


if(isset($_POST['securityKey']) == "$2y$10$GRcTbg!q2fj/7fSMgz0Eef4uFrbAFM8jILV2b((4bK323OFl57o1a"){
# Datenfankverbindung herstellen
$db_connect = db_connect();

$db_update = "Update db_computer ...

Nun sind wir aber mal ehrlich. Ja, das funktioniert, aber glücklich kann man damit nicht sein. Wirklich sicher ist das mit dem "securityKey" ja nicht, oder? Außerdem steht er noch hardcoded im PHP-File wobei... naja, in der config-Datei zum Herstellen der Datenbankverbindung stehen die Daten ja auch im Klartext ❔
Außerdem bekomme ich keine Rückmeldung vom PHP-Script wenn was schief läuft. Auch nicht so toll.

Daher meine Fragen:

  1. Kann man es mit Fluent HTTP anstellen, dass man im C#-Programm (oder sonnst irgendwie) eine Rückmeldung bekommt oder wird der String einfach nur abgeschickt und der Rest ist der Libray egal? Mein Englisch hapert leider etwas, so dass ich auf der Seite nicht mit allem zurecht komme.

  2. Kann man die PHP-Datei sicherer machen, so dass nicht gerade jeder daher gelaufene Bot oder ein zufällig darüber stolperndes Script Kiddy Unfug anstellen kann?

Nur Klarstellung:
Ich will mich schon auch noch mit Rest-API und / oder SOAP näher befassen, aber mir wäre es wirklich wichtig erstmal ein Projekt zu Ende zu bringen. (Ich habe in den vielen Jahren so viele begonnen und nie zu Ende gebracht, bzw. wieder aufgehört weil es irgendwo klemmte. Das hier ist das erste auf der Zielgeraden und ich möchte es nicht kurz vor knapp wieder abbrechen, weils mal wieder Probleme gibt. Das demotiviert dann auch jedes mal). Danach will ich es komplett neu entwickeln auf einer völlig neuen Basis, beispielsweise mit Symfony oder Laravel als PHP-Framework.

Edit: Ich habe das Thema ganz bewusst nicht in der Rubrik Code-Reviews gepostet, weil es nicht um ein Review geht. Vielmehr habe ich ja Fragen zur Thematik. Ich schreib das nur, weil ich in letzter Zeit ein Händchen dafür hatte in der falschen Rubrik zu posten.

28.06.2021 - 19:09 Uhr

In der Fehlermeldung stehen die Richtlinien nicht, aber hinter dem Passwortfeld steht ja was verlangt ist und das deckte das Passwort ja ab (Bei dir ging es wohl auch) 😲

Vielleicht ist auch bei meinem Account was kaputt. Ich habe hier auch eine PN die sich nicht löschen lässt:

Fehler

Keine Nachricht mit der Id #45363 gefunden.

War ne PN als ich einen Thread von mir selbst gemeldet hatte, weil aus versehen doppelt erstellt.

28.06.2021 - 18:46 Uhr

Sorry, irgendwie müsst ihr meine Threads immer rumschieben 😦

Es geht glaube ich eher darum, dass ich das Programm in eine Endlosschleife schicke, sofern keine Internetverbindung besteht und es sich quasi aufhängt und der Fehler nicht sauber behandelt wird. So wurde mir das damals in einem anderen Forum (in dem ich nicht mehr aktiv bin) gesagt. Deswegen eben die Frage, ob und wie man das vernünftig löst.

28.06.2021 - 18:40 Uhr

Hab es eben hier probiert.

Fehler
Das Passwort konnte nicht geändert werden. Bitte überprüfe Deine Angaben.

Probiert mit folgendem Passwort:

tz34!c=v4Hfe24f!f4fDg

Hab das aber auch mit ( oder ohne = probiert.

28.06.2021 - 18:21 Uhr

Kann es sein, dass es nicht möglich ist das Passwort zurück zu setzen? Ich habe das vor einigen Wochen mal probiert und heute Mittag erneut. Obwohl alle Richtlinien eingehalten wurden, gab es immer einen Fehler.

Edit: Passwort wurde versucht über die "Passwort vergessen"-Funktion zurück zu setzen, weil ich vom Geschäft aus einen Beitrag einstellen wollte.

28.06.2021 - 18:17 Uhr

Also zunächst möchte ich nochmal sagen, dass ich Anfänger bin. Also steinigt mich für den folgenden Code (der ja immerhin schonmal funktioniert) nicht. Das das ganze ein bisschen Murks ist weis ich, deswegen möchte ich fragen, wie man es besser machen kann.

Ziel ist es, dass das Programm erst los läuft, sobald der Computer eine Internetverbindung hat. Dazu teste ich alle 10 Sekunden, ob www.google.de erreichbar ist. Erst wenn das geschieht hören die Versuche auf und das Programm läuft los. Aber hier erstmal, was ich so zusammengebaut habe:


        bool isOnline = false;

        public void testping() {
            try  {
                Ping ping = new Ping();
                PingReply pingReply = ping.Send("www.google.de");
                if (pingReply.Status == IPStatus.Success) {
                    isOnline = true;
                }
            } catch {
                Thread.Sleep(10000); // 10 Sekunden nichts machen
            }
        }

        private void Form1_Load(object sender, EventArgs e) {

            while(isOnline == false) {
                testping();
            }
// Und hier geht das eigentliche Programm los

28.06.2021 - 18:09 Uhr

Ja, solange es derart einfach ist steige ich da noch durch, aber sobald es eben komplexer wird bekomme ich da schon massive Probleme, sowohl mit der Sprache, als auch mit der Komplexität der Thematik. Das jetzt war ja jetzt nahezu selbsterklärend.

28.06.2021 - 00:17 Uhr

Danke Th69. Das ist ja schon unverschämt einfach. Hat prima geklappt. Echt klasse 🙂 Ist auf der Github Seite auch wirklich super erklärt worden.

27.06.2021 - 12:12 Uhr

Hallo,

ich suche deutschsprachtige Informationen, wie man einen Updater für sein Programm entwickeln kann. Das Thema Programmieren ist für mich ohnehin nicht einfach und mit englisch bin ich da einfach überfordert. Es gibt zwar auf YouTube Videos die das mehr oder weniger in groben Zügen erklären, aber eher so Proof of Concept-Mäßig. Heute muss man die Updates ja auch irgendwie absichern, dass einem nicht irgendwer ein Update unterjubelt, sondern es wirklich vom Entwickler kommt. Updates muss ich auf unserem Webspace zur Verfügung stellen.

Hat mir bitte dazu jemand ein gutes Tutorial? Gerne kann man mich auch auf kostenpflichtige Videotutorials oder Bücher aufmerksam machen, in denen das Thema für Anfänger verständlich und anhand von Beispielen erklärt wird. Es sollte wie gesagt aber deutschsprachig sein.

Benutze Visual Studio 2019 Community Edition.

06.06.2021 - 00:43 Uhr

Upsi, jetzt kann ich nicht mehr editieren:

Also das


	       # Datenbankverbindung schließen.
	       $db_connect->close();

habe ich rausgenommen, weils nen Fehler wirft. (Hatte es vorher auskommentiert)

Habe es durch


			$db_insert = NULL;
			$db_connect = NULL;

ersetzt. Gut so?

06.06.2021 - 00:10 Uhr

Das ist zwar ein CSharp-Forum, aber ein bisschen wurde das Thema PHP hier ja angeschnitten. Ich hoffe es ist OK, wenn ich das hier etwas weiter führe, da ich mich eurer Ratschläge annehmen wollte. Außerdem wurde ich hier nicht direkt abgespeist und darauf verwiesen wieder zu kommen, wenn ich programmieren kann. Danke 🙂

Zunächst möchte ich mal den PHP-Teil in Ordnung bringen. Passend dazu kamen jetzt auch die Bücher zu PHP 8 bei mir an (Einstieg in PHP 8 und MySQL und PHP 8 und MySQL Das umfassende Handbuch)

Naja, im Einsteigerbuch wird PDO nur grob im Zusammenhang mit SQLite3 angerissen. Da wird mehr so auf MySQLi gesetzt. Im umfassenden Handbuch ist ein sehr schönes Beispiel drin, dass ich übernehmen habe und jetzt nachfragen wollte ob nun alle Aspekte abgedeckt sind oder noch was fehlt.


    else {
		try {				
	        $db_insert = ("Insert into db_computer (computerSerial, controlBillDate, fk_controlCostcentre, controlInvestmentNumber, controlCheckNumber, controlExpires, otherComment, controlFirstEntry) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
	        $data = [$_POST['computerSerial'], $_POST['controlBillDate'], $_POST['fk_controlCostcentre'], $_POST['controlInvestmentNumber'], $_POST['controlCheckNumber'], $_POST['controlExpires'], $_POST['otherComment'], date('Y-m-d')];
	        
	        $unklareVariable = $db_connect->prepare($db_insert);
			$unklareVariable->execute($data);
	        	        
	       # Datenbankverbindung schließen.
	       $db_connect->close();
	        
	    	# Code 10 = "Eintrag gespeichert."
			$_SESSION['code'] = 10;
			header("Location: https://".$_SERVER['HTTP_HOST']."/computer/show.php"); exit;
		} catch (PDOException $e) {
			echo 'Fehler: ' . htmlspecialchars($e->getMessage());
		}
    }

Die Variable, die ich "$unklareVariable" genannt habe ist mir tatsächlich unklar. Sie wird zugewiesen, kommt aber nirgends zum Einsatz?

Davon abgesehen hatte ich beim Umschreiben noch Fehler im try-Block, aber der catch-Block funktionierte nicht. Was ich so ergoogelt habe ist das try/catch in PHP auch nicht vorgesehen. Wieso wird das dannin dem Buch verwendet, bzw. wenn mittlerweile doch, warum kam er nicht zur Anwendung?

Das Datenbankverbindung schließe, also $db_connect->close(); kommt in dem Beispiel nicht vor, finde das aber sauberer. Oder braucht es das gar nicht, bzw. ist aus anderen Gründen Blödsinn?

01.06.2021 - 01:59 Uhr

Danke für deine Worte.

Also das gepostete PHP-Script ist natürlich vom Webinterface und hat nichts mit der C#-Anwendung zu schaffen. Deswegen hatte ich es nie erwähnt. Ich hatte das nur gepostet, weil JimStark (mehr oder weniger) danach gefragt hat. Das PHP-Script, dass mit C# zusammen arbeiten soll müsste ich erst noch erstellen und wird dann auch nur Update-Befehle ausführen, keine Inserts und keine Deletes! (Anlegen der Computer in der Datenbank (mit Seriennummer) und Löschen erfolgen über das Webinterface). Ob die C#-Anwendung ein Select benötigtet muss ich gucken, ich glaube aber nicht. Ich wollte aber erstmal abklären, ob das mit PHP überhaupt Sinn ergibt, bevor ich das mache nur um es am Ende enttäuscht in die Tonne treten zu müssen.

Wenn wir aber schon dabei sind, einfach kurz zwischenrein:
Bist du noch so nett und sagst mir, was an dem geposteten PHP-Script nicht optimal ist? Bislang hieß es immer PDO sei sicher und man muss sich nicht wie bei MYSQL, bzw. MySQLi um das absichern der Variablen und Strings kümmern, weil das by design schon gegeben ist. Deswegen habe ich mich auch da umgestellt und den Absprung von der alten Methode geschafft. Gilt das nicht mehr?

Was ich inzwischen noch gemacht habe ist, den $db_connect erst innerhalb der if(isset($_POST['computerSave']))-Variable zu setzen. Ich glaube das ist aber egal, erscheint mir nur logischer vom Ablauf her.

01.06.2021 - 00:47 Uhr

Ja, ihr gebt mir wertvolle Tipps und Hilfestellungen. Das merke ich und versuche auch damit zurecht zu kommen. Aber ich fühle mich total überfordert 😦. Das Tutorial von der Microsoft-Seite verstehe ich nicht. Ich suche einfach ein ordentliches Beispiel, wo das ganze anschaulich, möglichst auch noch deutsch weil kompliziert genug, erklärt wird.

Warum ich PHP dafür verwenden will? Naja, bin zufällig drauf gestoßen und da ich PHP (mehr oder weniger) auch gut kann und mir vertraut ist und das scheinbar auch ohne Umwege funktioniert dachte ich, dass man das auch so machen kann. C#-Anwendung schickt Anfrage an PHP-Script-> PHP-Script macht die Datenbankeintrag. Einfacher könnte es für mich nicht sein und ich konnte den Vorgang nachvollziehen und habs verstanden.

31.05.2021 - 22:50 Uhr

Ich habe endlich ein Video gefunden und ich glaube es sogar verstanden zu haben. Taugt das was? Sieht sehr einfach aus.
Wäre vielleicht noch cool, wenns per post gehen würde, anstatt über get.

Edit: Das hier scheint besser zu sein, sogar mit Rückmeldung an die WinForm

31.05.2021 - 19:55 Uhr

Die Webseite habe ich gemacht und hält neben dem üblichen HTML und CSS eigentlich nur den PHP-Block zur Abfrage der Daten aus der Datenbank. Der einzige Insert der statt findet ist eigentlich nur die Seriennummer des Rechners die ich eintrage (und über die findet das Programm dann den passenden Rechner) und einige Daten, die die Buchhaltung eintragen kann (Rechnungsdatum, Kostenstelle...) Mehr passiert da nicht. Sieht so aus (Noch nicht fertig, fehlt jegliche Rechteprüfung) Ich hoffe ihr schlagt hier nicht auch schon wieder direkt die Hände überm Kopf zusammen. "control" steht in dem Fall für das "Controlling", nicht für ein Steuerelement.


<?php session_start();

# Diese Datei enthält Funktionen, welche für das Script zwingend benötigt werden.
require_once("../functions.inc.php");
# Diese Datei enthält die Fehlercodes.
require_once("../codes.php");

# Datenbankverbindung herstellen
$db_connect = db_connect();

// Prüfen, ob das Formular abgeschickt wurde.
if(isset($_POST['computerSave'])) {

	// Prüfen, ob Seriennummer gesetzt ist.
	if(empty($_POST['computerSerial'])) {
		# Code 13 = "Es wurden nicht alle Pflichtfelder ausgefüllt."
		$_SESSION['code'] = 13;
		header("Location: http://".$_SERVER['HTTP_HOST']."/computer/show.php"); exit;
	}
        # Prüfen, ob der Computer bereits angelegt wurde
        $db_read = $db_connect->prepare('select computerSerial from db_computer where computerSerial=?');
        $db_read->execute([$_POST['computerSerial']]);
        $number = $db_read->rowCount();
        # Falls ein Eintrag gefunden wurde, Vorgang abbrechen
        if($number >= 1){
            # Code 30 = Den Computer gibt es bereits."
            $_SESSION['code'] = 30;
            header("Location: http://".$_SERVER['HTTP_HOST']."/computer/show.php"); exit;
        }
    else {
        $db_insert = $db_connect->prepare("Insert into db_computer (computerSerial, controlBillDate, fk_controlCostcentre, controlInvestmentNumber, controlCheckNumber, controlExpires, otherComment, controlFirstEntry) VALUES (:computerSerial, :controlBillDate, :fk_controlCostcentre, :controlInvestmentNumber, :controlCheckNumber, :controlExpires, :otherComment, :controlFirstEntry)");
        $db_insert->execute([
            'computerSerial' => $_POST['computerSerial'],
            'controlBillDate' => $_POST['controlBillDate'],
            'fk_controlCostcentre' => $_POST['fk_controlCostcentre'],
            'controlInvestmentNumber' => $_POST['controlInvestmentNumber'],
            'controlCheckNumber' => $_POST['controlCheckNumber'],
            'controlExpires' => $_POST['controlExpires'],
            'otherComment' =>  $_POST['otherComment'],
            'controlFirstEntry' => date('Y-m-d')
        ]);

		# Code 10 = "Eintrag gespeichert."
		$_SESSION['code'] = 10;
		header("Location: http://".$_SERVER['HTTP_HOST']."/computer/show.php"); exit;
    }
}
else
{
	header("Location: http://".$_SERVER['HTTP_HOST']."/computer/show.php"); exit;
}
$db_connect->close();
?>

31.05.2021 - 19:15 Uhr

OK, Danke.

Das Problem war, dass ich überhaupt nicht wusste, wie es jetzt weitergehen soll. Die Antwort, dass es "nur" um die Übertragung der Daten geht hat mir jetzt geholfen. Jetzt komme ich hoffentlich erstmal weiter. Ich habe hier auch ein Buch (Einstieg in C# mit Visual Studio 2019), aber leider wird das Thema da nicht erklärt. Nur wie man in eine MySQL-Datenbank schreibt die "ohne Hindernisse" zugänglich ist. Es gibt zwar ein Kapitel "9.9 Datenbank im Internet ändern", aber das beinhaltet was ganz anderes. Schade, dass so etwas nicht erklärt wird. Das Stichwortverzeichnis gibt auch nichts her, wenn nach Rest API oder Web API sucht.

Ich lese also schon auch selbst und lasse mir nicht alles vorkauen. Es ist mir wichtig hier nicht den falschen Eindruck zu vermitteln, wenn ich blöde oder scheinbar ganz offensichtliche Fragen stelle.

Edit: Kann es sein, dass das Thema selbst in diesem umfassenden Handbuch nicht behandelt wird oder suche ich im Inhaltsverzeichnis nach etwas, das dort anders bezeichnet ist?

Kennt jemand Linkedin Learning und weiß zufällig, ob dort das Thema anschaulich erklärt wird?

31.05.2021 - 18:34 Uhr

Wieso wäre meine Umsetzung unseriös, wenn das Angebot an sich seriös ist? Schließt sich meiner Meinung nach dann aus.

Das mit der WebAPI habe ich absolut nicht kapiert. Muss ich das zusätzlich in meine Anwendung einbauen? Muss ich meine Anwendung über Board werfen und neu anfangen? Wie greife ich über eine Webanwendung auf WMI und Registry des Systems zu? Was steckt da überhaupt dahinter? Ist es noch WinForms?

Entschuldige bitte, wenn ich etwas nerve. Du hast es mit einer Person zu tun, die über einen sehr niedrigen Wissensstand in der Programmierung verfügt und der auch das so genannte "logische Denken" fehlt. Ich will es können, tue mich aber leider sehr schwer.

31.05.2021 - 18:13 Uhr

Danke für deine Antwort, auch wenn es natürlich nicht das ist, was ich lesen wollte 😄.

Ich habe noch einige Fragen, weil ich mich jetzt zwangsweise angefangen habe mit der Thematik zu befassen und verzweifelt irgend eine Lösung suche.

  1. Es gibt Anbieter im Internet, die Remote-Zugriff auf die Datenbank erlauben. Beispielsweise Cloudways oder Fritz Managed IT GmbH Ist das per se unseriös?

  2. Ich weis nicht, ob es einen Unterschied macht, aber im Grunde müssen zwar die Daten die die Anwendung sammelt irgendwie in die Datenbank gelangen, aber zum Abrufen der Daten würde es reichen, wenn das nur von einer einzigen IP aus möglich ist. Wir haben eine feste IP. Das Eintragen von Daten könnte man auf IPs aus der Region Baden-Württemberg beschränken. Woanders sind unsere Leute, auch jene mit Laptops, nicht. (wenn es da solche Filter gibt (Cloudways schreibt hier was davon, aber nur für SSH und SFPT, müsste man also erfragen, ob das auch für die Datenbank möglich ist).

  3. Es wäre kein Problem für mich den Webserver im eigenen Netzwerk der Geschäftsstelle verfügbar zu machen. Dort will ich die Daten ja abrufen. Einen OpenVPN-Server gibt es, eine feste IP haben wir auch. Ich konnte aber kein Ergebnis finden, wo es möglich ist, dass man eine C#-Anwendung so programmieren kann, dass diese eine VPN-Verbindung aufbaut und auch nur diese Anwendung dann das VPN nutzt. Über Nu-Get findet sich dahingehend auch kein Paket. Geht also nicht?

  4. In einem YouTube-Video wird gezeigt, wie man mittels SSH auf einen MySQL-Server zugreift. Mit SSH kenne ich mich aber nicht aus. Ich kenne das nur als Zugriffsmöglichkeit bei einigen IoT-Geräten. Wenn man SSH aber direkt beim Router zum MySQL-Server durchschleift hat das doch ohnehin den gleichen Effekt, als wenn ich den Server direkt offen ins Netz stelle. SSH ist ja nur ein anderes Protokoll. Also völlig schwachsinnig?

  5. Warum ist ein Datenbankserver im Internet unsicherer als ein SFTP-, Web- oder Mailserver? Was ist der Unterschied?

  6. Gibt es Möglichkeiten eine Datenbank, die man remote zugänglich machen will vernünftig abzusichern, beispielsweise in dem man einen Key in seine Anwendung einbaut der (neben Benutzername und Passwort natürlich) zur Authentifizierung abgefragt wird und das ein Zugriff nur zu bestimmten Uhrzeiten möglich ist, oder der Hashwert der anwendung geprüft wird, etc.

Das verlinkte Tutorial habe ich leider absolut nicht kapiert. Ich danke euch schonmal.

31.05.2021 - 00:00 Uhr

Verwendetes Datenbanksystem: MySQL 5.7 beim Provider IONOS

Ich habe mir in mühevoller Kleinarbeit ein Inventarisierungsprogramm in C# geschrieben, dass jetzt fast fertig ist. Nun wollte ich die ersten Daten in unsere MySQL-Datenbank speichern und eine Verbindung aufbauen. Schon das funktioniert nicht. Aus Sicherheitsgründen lässt IONOS keine externen Programme zu, sondern nur direkt über den Webspace.

Auf dem Webspace läuft schon die Webseite, wo ich die Daten aus der Datenbank abfragen und anzeigen kann.

Tja, jetzt stehe ich ziemlich doof da, weil die ganze Arbeit scheinbar völlig umsonst war 🙁 Weiß vielleicht jemand was ich nun machen kann? Klar, mein Arbeitgeber könnte einen Root-Server mieten, aber ist das nicht etwas weit ausgeholt? Außerdem bin ich eher Hobbyprogrammierer und Scripter (deswegen auch die mühevolle Kleinarbeit) und würde von daher nicht behaupten, dass meine Scripte und Anwendungen absolut sicher sind. Ich schätze mal die Angriffsmöglichkeiten sind außerhalb der IONOS Bubble deutlich größer und ein starkes Passwort alleine wird mich nicht schützen wenn ich einen Root-Server miete.

Vielleicht kann jemand von euch das Projekt noch retten und hat eine Idee, was machbar ist.

Edit: Noch eine Ergänzung: Das Programm soll bei jedem Systemstart ausgeführt werden und aktuelle Inventardaten in die Datenbank eintragen. Wir haben mehrere Startorte und auch Mobile Arbeitsplätze. Einfach einen Server ins Intranet stellen ist also keine Möglichkeit.