ungeleventes Programm startet einen erhöhten Updater, Updater sollte auf den Abschluss des Programms warten

8

Ich habe zwei Apps, Programm.exe und Updater.exe, beide in Delphi5 geschrieben. Programm läuft ohne Admin-Rechte (und ohne Manifest), Updater hat ein Manifest mit "requireAdministrator", da er in der Lage sein muss, im Programm-Ordner zu schreiben, um Programm.exe zu aktualisieren.

Das Problem besteht darin, den Updater zu starten und ihn warten zu lassen, bis das Programm geschlossen ist. Ich habe verschiedene Wege im Internet gefunden, aber keine funktioniert (in den meisten Fällen startet die 1. App die 2. App und wartet auf das Ende der 2. App, in meinem Fall sollte die 2. App auf das Ende der 1. App warten).

Updater sollte warten, das ist ganz einfach updater.exe

%Vor%

Weg 1
Updater mit CreateProcess starten:
programm.exe

%Vor%

Tut nichts, funktioniert nur, wenn der Updater kein Manifest mit requireAdministrator hat. Wenn ich ein Programm mit expliziten Administratorrechten ausführe, funktioniert es auch.

Weg 2 Starten von Updater mit ShellExecuteEx:
programm.exe

%Vor%

Funktioniert nicht, MyHandle hat jedes Mal einen anderen Wert, wenn ich diese Prozedur ausführe (ohne das Programm neu zu starten), daher kann Updater nicht damit arbeiten.

So habe ich keine Ahnung, wie updater.exe zu starten und schreiben Sie das Handle von program.exe in der Datei.

Ich bin nicht sehr vertraut mit diesen Teilen des Programmierens ... hat jemand eine Idee für mein Problem?

    
BjoernHH 10.06.2015, 14:29
quelle

3 Antworten

7

Ihr Code funktioniert nicht, da die Handle-Tabelle pro Prozess ist, was bedeutet, dass der zweite Prozess denselben Handle haben könnte, der auf ein anderes Kernel-Objekt verweist. Im Folgenden finden Sie eine von vielen möglichen Lösungen:

Übergeben Sie beim Erstellen des Prozesses 2 die PID des Prozesses 1 als Parameter:

%Vor%

Warten Sie im Updater auf das Beenden von process1:

%Vor%

Sie können auch WaitForSingleObject verwenden, um das Polling zu vermeiden:

%Vor%

Sie benötigen jedoch den Zugriff SYNCHRONIZE, um den Prozess zu öffnen:

%Vor%

Hinweis: Hier wird keine Fehlerprüfung durchgeführt. Sie sollten die Dokumente lesen und ordnungsgemäß auf Fehler überprüfen.

Hinweis 2: Ich möchte Ihre Aufmerksamkeit auf die Tatsache lenken, dass Sie einen Griff verlieren. Wenn Sie SEE_MASK_NOCLOSEPROCESS verwenden, ist der Aufrufer dafür verantwortlich, den Handle des Calees zu schließen. In deinem Fall denke ich, dass du diese Maske überhaupt nicht brauchst. Ich würde es entfernen.

    
EProgrammerNotFound 10.06.2015, 15:51
quelle
1

Hier ist ein einfaches Beispiel, wie dies mit Ereignissen erreicht werden kann:

program.exe :

%Vor%

updater.exe :

%Vor%

Sie sollten außerdem ein Manifest zu program.exe hinzufügen ( requestedExecutionLevel sollte level="asInvoker" sein), um eine Virtualisierung zu vermeiden.

    
kobik 11.06.2015 08:50
quelle
0

Ich sehe das Hauptproblem dort in unbestimmter Reihenfolge von zwei Ereignissen: Schließen von dem Programm und Starten von dem Updater Hauptcode.

Eine Möglichkeit, dies zu beheben, wäre die Verwendung von Ereignissen - Ссылка

Das Programm erstellt das Ereignis (mit einer Option für die untergeordneten Elemente) und startet das Aktualisierungsprogramm (übergibt die Handles sowohl des Ereignisses als auch des Prozesses des Prozesses als Integer über die Befehlszeile!), friert dann in WaitForSingleObject auf dem Event ein.

Dies stellt sicher, dass das Programm nicht beenden würde, bevor der Updater bereit wäre, es zu überwachen, sodass die PID nicht ungültig wird.

Der Updater ruft dann OpenProcess für die von der Kommandozeile erhaltene Programm-PID auf und ruft dann SignalAndWait auf, die sowohl das Event (von der Kommandozeile) klopft als auch das Handle einfriert (aus OpenProcess) - Ссылка

Das Programm, das jetzt vom Warten auf Ereignis befreit wird, wird beendet. Die Beendigung des Prozesses signalisiert dies, sodass nun der Updater nacheinander freigegeben wird und mit der Hauptarbeit beginnen kann.

Ein anderer Ansatz, der unter C ++, Wie ermittelt man, ob ein Windows-Prozess läuft? ist, fragt den Exit-Code von ab das Programm ProcessID - es wird gesagt, dass, während das Programm noch läuft, es einen spezifischen Fehlercode gibt und Sie können Sleep (100) dann versuchen Sie es erneut. Jedes andere Ergebnis bedeutet, dass das Programm bereits beendet hat.

Das Programm wird unmittelbar nach dem Start von dem Updater beendet, ohne darauf zu warten, dass es die Überwachung startet.

Das scheint ein netter Ansatz zu sein, außer dass ich jetzt keine Garantie dafür gebe, dass PID-Werte nicht wiederverwendet werden. Die Chancen sind infinitesimal, aber immer noch nicht Null.

Ich persönlich würde wahrscheinlich eine Flag-Datei verwenden. Die CreateFile-API hat ein sehr interessantes Flag - den temporären Dateimodus. Das bedeutet, dass Windows die Datei automatisch löscht, nachdem der Prozess beendet wurde. Also dann

  1. Das Programm erstellt eine neue GUID mithilfe der Windows-API (oder einen neuen Zufallswert unter Verwendung der Crypto-API).
  2. Das Programm erstellt im temporären Dateiordner die Datei im temporären Modus mit dem Namen, der auf der GUID oder dem Wert "Random" basiert. Wenn durch irgendein Glück eine solche Datei bereits existiert - Sie erhalten nur eine neue GUID oder einen zufälligen Wert.
  3. Das Programm startet den Updater und übergibt den Dateinamen über die Befehlszeile
  4. an diesen
  5. Das Programm wird unmittelbar nach dem Start von dem Updater beendet, ohne darauf zu warten, dass es die Überwachung startet.
  6. Der Updater prüft ständig, ob die Datei existiert (Pausen zwischen den Versuchen). Wenn die Datei nicht mehr existiert - das bedeutet, dass das Programm beendet und von Windows automatisch gelöscht wurde.

Auch hier gibt es eine winzige Chance, dass ein anderer Prozess die Flag-Datei mit genau dem gleichen Namen zwischen dem Programm und dem Updater erzeugt. aber das ist in der Praxis fast unmöglich

    
Arioch 'The 10.06.2015 15:50
quelle