Autor Beitrag
Csharp-programmierer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 17.01.17 17:29 
Hallo liebes Forum,
ich entwickle gerade den Updater für mein Programm.

Wenn ich den in Visual Studio ausführe, funktioniert alles tadellos. Wenn ich diese .exe nehme, in den ZIP reinlade, diesen ZIP signiere und auf den Server lade, die Anwendung dann installiere und ich dort den Updater ausführe, wird zwar die neue GUI angezeigt, aber nicht der neue Code. Als Fehlermeldung bekomme ich dann, dass der Zugriff auf einen Pfad verweigert wurde, was aber in VS nicht passiert. Jetzt habe ich in VS alle Try Catches rausgenommen in der Hoffnung, dass er mir die Zeit markiert, aber dort scheint alles zu funktionieren. Hier mal der Code:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
public void LoadAndInstallNewUpdate()
        {
                WebClient client = new WebClient();
                Uri URL = new Uri(@"http://.....zip");
                string LocalPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NewUpdate.zip");

                client.DownloadFile(URL, LocalPath);

                if (HasValidSignature(LocalPath) == 1)
                {
                    InstallUpdate(LocalPath);
                }
                if (HasValidSignature(LocalPath) == 0)
                {
                    Form2 f = new Form2();
                    f.ShowDialog();

                    if (f.Action == 1)
                    {
                        File.Delete(LocalPath);
                        Application.Exit();
                    }
                }
                if (HasValidSignature(LocalPath) == 2)
                {
                    MessageBox.Show("Bei der Prüfung der Signatur ist ein unbekannter Fehler aufgetreten.\rBitte versuchen Sie es erneut.""unbekannter Fehler", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                }
        }
        private int HasValidSignature(string filename)
        {
                var fileContent = File.ReadAllBytes(filename);

                if (fileContent.Length < 260)
                {
                    return 0;
                }

                byte[] signature = null;
                int signatureLength = 0;

                // Signatur auslesen, sie hängt hinten an der Datei
                using (var stream = new MemoryStream(fileContent))
                {
                    using (var reader = new BinaryReader(stream))
                    {
                        stream.Seek(-4, SeekOrigin.End);
                        signatureLength = reader.ReadInt32();
                        if (signatureLength != 256)
                        {
                            return 0;
                        }
                        else
                        {
                            stream.Seek(-4 - signatureLength, SeekOrigin.End);
                            signature = reader.ReadBytes(signatureLength);
                        }
                    }
                }

                var contentLength = fileContent.Length - signatureLength - 4;
                var rsaKey = "Schlüssel";

                // Signatur gegen den vorhergehenden Teil der Datei (= das zip Archiv) prüfen
                using (var rsa = new RSACryptoServiceProvider(2048))
                {
                    rsa.FromXmlString(rsaKey);
                    if (rsa.VerifyData(fileContent, 0, contentLength, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
                        return 1;
                    else
                        return 0;
                }
            
        }
        private void InstallUpdate(string filename)
        {
                using (StreamReader reader = new StreamReader(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MeinOrdner""meineDatei.txt")))
                {
                    string InstallationsPfad = Path.Combine(reader.ReadLine(), "Mainlysoft Devassist");
                    if (InstallationsPfad != "")
                    {
                        // Alte Programmdaten löschen
                        // Installationspfad: Dokumente -> Mainlysoft Devassist -> Programm DLL's, .exe's ...
                        DeleteFiles(InstallationsPfad);
                        MessageBox.Show("Hier 1");

                        // Neue Programmdaten aufspielen
                        ZipFile.ExtractToDirectory(filename, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MSUpd"));
                        DirectoryCopy(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MSUpd"), InstallationsPfad, true);
                        MessageBox.Show("Hier 2");

                        // Installationsordner löschen
                        if (File.Exists(filename))
                        {
                            File.Delete(filename);
                            MessageBox.Show("Hier 3");
                        }

                        if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MSUpd")))
                        {
                            DeleteFiles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MSUpd"));
                            Directory.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MSUpd"));
                            MessageBox.Show("Hier 4");
                        }

                        MessageBox.Show("Hier 5");
                        System.Diagnostics.Process.Start(Path.Combine(InstallationsPfad, "Entwicklertool.exe"));
                        Application.Exit();
                    }
                }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            LoadAndInstallNewUpdate();
        }

        private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);

            DirectoryInfo[] dirs = dir.GetDirectories();
            if (!Directory.Exists(destDirName))
            {
                Directory.CreateDirectory(destDirName);
            }

            FileInfo[] files = dir.GetFiles();
            foreach (FileInfo file in files)
            {
                string temppath = Path.Combine(destDirName, file.Name);
                file.CopyTo(temppath, false);
            }

            if (copySubDirs)
            {
                foreach (DirectoryInfo subdir in dirs)
                {
                    string temppath = Path.Combine(destDirName, subdir.Name);
                    DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                }
            }
        }
        private static void DeleteFiles(string Pfad)
        {
            DirectoryInfo dir = new DirectoryInfo(Pfad);

            DirectoryInfo[] dirs = dir.GetDirectories();

            FileInfo[] files = dir.GetFiles();
            foreach (FileInfo file in files)
            {
                file.Delete();
            }
        }


Woran kann das liegen?


Moderiert von user profile iconTh69: Topic aus Programmierwerkzeuge verschoben am Mi 18.01.2017 um 13:13

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 475
Erhaltene Danke: 51



BeitragVerfasst: Di 17.01.17 18:35 
An dir. :mahn:

Es ist nicht gerade leicht, deine Frage überhaupt zu verstehen. Ins Blaue geraten: Hast du auf dem Server vielleicht schlicht andere Zugriffsrechte als lokal? Was ist das überhaupt für ein Server? Existiert der Pfad? Ist die Datei ggf. schon in Benutzung?
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 17.01.17 18:54 
So ich habe das Programm jetzt nochmal gedebuggt.

Jetzt werden die ganzen MessageBoxen angezeigt, jedoch kommt hier der Fehler: var fileContent = File.ReadAllBytes(filename);
Angeblich wird die Datei nicht gefunden.

So, jetzt habe ich das Programm Schritt für Schritt gedebuggt, der ZIP wurde heruntergeladen, und als ich das Programm gestoppt habe, war der Kompiller schon in der Methode "InstallUpdate". Es wurden alle MessageBoxen angezeigt, aber zum Schluss kam der oben genannte Fehler. Wie kann das sein?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 475
Erhaltene Danke: 51



BeitragVerfasst: Di 17.01.17 18:54 
Du hast die Pfade versemmelt.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 17.01.17 19:07 
In wie fern?`Ich habe gerade ein echtes Brett vor dem Kopf :oops:

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 475
Erhaltene Danke: 51



BeitragVerfasst: Di 17.01.17 19:08 
Hast du mal spaßeshalber versucht, meine Fragen zur Kenntnis zu nehmen?
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 17.01.17 19:12 
Es handelt sich um einen Webserver, auf dem der ZIP gehostet wird. Auf diesem Server habe ich volle Admin Rechte und die URL funktioniert. Der ZIP wird ja auch erst gedownloaded, aber anscheinend wird der Code in einer falschen Reihenfolge ausgeführt

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Di 17.01.17 22:41 
Dein Problem liegt nicht beim Server.

Du hast den Vorgang offenbar noch nicht gründlich genug nachverfolgt. Aber immerhin weißt du bereits, dass der Fehler in der Zeile var fileContent = File.ReadAllBytes(filename); liegt. Mein erster Instinkt wäre jetzt, dort einen Breakpoint zu setzen.

Dann müsstest du feststellen, dass dieser mehr als nur einmal getroffen wird. Das ist der Fehler, denn beim zweiten Mal existiert die Datei nicht mehr!


Grund ist einfach:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
                if (HasValidSignature(LocalPath) == 1)
                {
                    InstallUpdate(LocalPath);
                }
                if (HasValidSignature(LocalPath) == 0)
                {
                    Form2 f = new Form2();
                    f.ShowDialog();

                    if (f.Action == 1)
                    {
                        File.Delete(LocalPath);
                        Application.Exit();
                    }
                }
                if (HasValidSignature(LocalPath) == 2)
                {
                    MessageBox.Show("Bei der Prüfung der Signatur ist ein unbekannter Fehler aufgetreten.\rBitte versuchen Sie es erneut.""unbekannter Fehler", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                }


Hier rufst du völlig unnötigerweise mehrfach die Funktion HasValidSignature() auf. Beim erstem Mal bekommst du 1 zurück und die if-Abfrage schlägt an. Das Update wird installiert.
In der Mitte von InstallUpdate() löschst du dann die Update-Datei weil du sie nicht mehr brauchst. Aber dann geht der Programmablauf zurück nach LoadAndInstallNewUpdate() und die nächste Abfrage ist.....
ausblenden C#-Quelltext
1:
if (HasValidSignature(LocalPath) == 0)					

Was dann wieder die Datei öffnen will und fehl schlägt.

Das alles hättest du eigentlich finden müssen, wenn du mit F10 ("Prozedurschritt") und F11 ("Einzelschritt") über den Ablauf gegangen wärst. (Am Besten machst du das direkt und schaust, ob ich richtig lag. So 100% sicher bin ich mir ja auch nicht :P )

Verbesserungsvorschläge:
1. Ruf die Funktion HasValidSignature() einmal auf und merke dir das Ergebnis.
2. Führe die anderen Sachen nur aus, wenn das erste nicht ausgeführt wurde.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
var isSignatureValid = HasValidSignature(LocalPath);
if (1)
{
    InstallUpdate(LocalPath);
}
else if (0)
{
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 17.01.17 23:03 
user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:
Verbesserungsvorschläge:
1. Ruf die Funktion HasValidSignature() einmal auf und merke dir das Ergebnis.
2. Führe die anderen Sachen nur aus, wenn das erste nicht ausgeführt wurde.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
var isSignatureValid = HasValidSignature(LocalPath);
if (1)
{
    InstallUpdate(LocalPath);
}
else if (0)
{


Der Code ist sicher nicht toll an der Stelle aber das ist maximal der halbe Weg zu "schönem" Code. Den Status sollte man sicher nicht als integer rumreichen sondern als enum und die Prüfung ist keine if else if Kette sondern ein simpler switch case.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 18.01.17 14:12 
Oder einfach als bool.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 18.01.17 14:21 
Du hast Wert 2 übersehen.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 18.01.17 14:53 
Ich habe den Methoden-Code von HasValidSignature durchgeschaut und dort gibt es kein return 2 (oder aber ich bin blind?).
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 18.01.17 14:58 
Scheinst recht zu haben.
Allerdings scheint der OP das anders geplant zu haben den später prüft er selber if (HasValidSignature(LocalPath) == 2).
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mi 18.01.17 16:42 
Na toll, ich habe es jetzt genau so gemacht, woi jheins geschrieben hat:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
client.DownloadFile(URL, LocalPath);
                int HashValue = HasValidSignature(LocalPath);

                if (HashValue == 1)
                {
                    InstallUpdate(LocalPath);
                }
                if (HashValue == 0)
                {
                    Form2 f = new Form2();
                    f.ShowDialog();

                    if (f.Action == 1)
                    {
                        File.Delete(LocalPath);
                        Application.Exit();
                    }
                }


Jetzt ist genau das selbe Problem. Ich VS Funktioniert alles tadellos, aber wenn das Programm ohne VS arbeiten soll, macht das Programm nicht das, was es soll

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 18.01.17 17:15 
Entweder debugge dann den Code (per VS "an Prozess hängen") oder aber logge dir den Ablauf (und z.B. die Pfade) sowie Exceptions (in die Console oder in eine Datei).
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mi 18.01.17 20:51 
Soo, ich habe jetzt mal Schritt für Schritt drauf geachtet, was das Programm macht und jetzt ist alles einleuchtend:
In dem ZIP war auch der Updater, der dann durch das Hauptprogramm gestartet wurde. Und der Updater wollte sich dann selbst löschen, was natürlich nicht möglich ist, weil er gerade in Betrieb ist. Und in VS hat es funktioniert, da der Updater von einem anderen Pfad gestartet wurde, also ist des Rätseln Lösung jetzt geklärt.

Jetzt mal noch eine Erfahrungsfrage von Entwicklern: Sollte man einen Updater auch immer aktuell halten oder kann man den so lassen? Weil wenn ich den auch immer aktuell halten muss, dann müsste das Hauptprogramm diesen installieren. Was meint ihr dazu?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 18.01.17 21:17 
Zitat:
Jetzt mal noch eine Erfahrungsfrage von Entwicklern: Sollte man einen Updater auch immer aktuell halten oder kann man den so lassen? Weil wenn ich den auch immer aktuell halten muss, dann müsste das Hauptprogramm diesen installieren. Was meint ihr dazu?


Der Updater entpackt dein runtergeladenes Zip in einen temp Ordner, startet den im Zip enthaltenen Updater(eine andere Anwendung mir fällt nur kein weiterer anderer Name ein) dort mit passenden Parametern und beendet sich. Der im temp Ordner gestartete Updater(der aus dem zip) kann jetzt alles ins ursprüngliche Programmverzeichnis kopieren.
Der Updater (der Anwendung) muss eigentlich nur das Zip runterladen, prüfen, entpacken und was aus dem entpackten starten(den Updater im zip). Die Installationsintelligenz hingegen (das bei einer Installation/Update nur Dateien kopiert werden ist denke ich eher ein Sonderfall als das normal, irgendwas zusätzliches muss oft genug auch erledigt werden) sitzt dann im zip und nicht im Programm und wird mit dem zip runtergeladen. Ein Updaten der Updatemethodik ist so eher weniger ein Problem.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mi 18.01.17 21:41 
Also ich habe es bis jetzt immer so gemacht:
- Die Hauptanwendung sucht nach Updates
- ist eins vorhanden wird ein Wert in einer Text Datei geändert, dann wird der Updater.exe gestartet, der den ZIP mit den neuesten Programmdaten heruntergeladen. In diesem ZIP ist dann der Installer, das Hauptprogramm samt DLLs, und eine Textdatei mit der aktuellen Versionsnummer. Der Updater extrahiert die Daten in einen anderen Ordner, nachdem er die Signierung überprüft hat, wenn alle Daten anschließend in den Hauptprogrammordner kopiert wurden, ändert dieser wieder einen Wert einer Textdatei und startet die Hauptanwendung.
- Diese prüft dann den Wert und kopiert anschließend (wenn nötig) den Updater in den Hauptprogrammordner
- Fertig

Was haltet ihr von der Idee?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein