![]() |
Update-Vorgang in einen Thread auslagern
Hallo Delphianer,
vorsicht, es wird ein kleiner Roman, aber, ich versuche so weit es geht Missverständnisse und sicher auch gut gemeinte Vorschläge über Alternativen von vorneherein auszuschließen. Und dazu braucht es eben auch ein paar Zeilen. Ich habe für meine SW ein Update-Programm, das über ein mit Blowfish gesichertes TCP/IP-Protokoll eine Datenbank-Verbindung zu meinem Update-Server (NexusDB-Server) herstellt, eventuell neuere Dateien herunterlädt, und dann installiert. Der selbe DB-Server (nur eine andere Datenbank) wird für die Bereitstellung der Lizenzen verwendet. Soweit nichts besonderes. Läuft auch seit 2 Jahren prima. Wenn ich meine SW mit meinem selbst geschriebenen Installationsprogramm installiere, ist der Ablauf (Ausschnitt) wie folgt: 1. Der User gibt die Lizenznummer ein 2. Die Lizenz(datei) wird heruntergeladen 3. Installation wird fortgesetzt Nach der Installaton wird meine SW mit Admin-Rechten gestartet und die SW ruft dann in festgelegten Zeiträumen das Updateprogramm auf. Das passiert normalerweise nach einer Update-Installation via CD beim ersten Programmstart. Und nun das eigentliche Problem: Die Firewall blockiert das Updateprogramm natürlich bei der Erstinstallation und nach jeder Aktualisierung. Wir wissen ja, was User alles weg klicken, oder wohin sie "nicht" klicken, wenn sie sollen. Stichwort "Ach ja, die Meldung kommt immer..:" Der Gedanke ist also, wenn ich bei der Installation die Lizenz abfrage (da passen die User noch richtig auf, weil sie die Lizenz ja installieren wollen/müssen) und anschließend herunterlade, dann habe ich ja zu dem Zeitpunkt schon eine aktive Verbindung und könnte doch in der Zeit wo ich die SW installiere, parallel dazu eventuell vorhandene Updates herunterladen. - Das sollte ein eigener Thread sein, damit die Installation ungehindert fortgesetzt wird - Das Installationsprogramm muss den Fortschritt des Downloadvorganges abfragen können. - Wenn die Installation fertig und der Download noch nicht abgeschlossen ist, sollte auch der Downloadfortschritt angezeigt werden können - Der Code sollte so "verpackt" sein, dass er auch vom eigentlichen Updateprogramm verwendet werden kann. Im Updateprogramm sind getrennt: Form (das was der User sieht), Logik (der Downloadvorgang, das Ersetzen der vorhandenen Dateien) in einer Unit, und der Datenbankzugriff in einem Datenmodul. Nun habe ich über Threads schon einiges gelesen, so richtig kapiert hab ich das allerdings noch nicht. Noch dazu gibt's ja - wenn man sich die Beiträge hier so ansieht - auch sehr unterschiedliche und differenzierte Meinungen und Ansichten, wie man Threads einsetzt bzw. damit umgeht. Das macht es für mich nicht einfacher. Ich bin Autodidakt, kein studierter Informatiker. Damit ich aber bei Problemen reagieren kann, muss ich das Ganze auch "verstehen" können. Darum meine Frage und Bitte nach Vorschlägen und Anregungen. Gerne gegen Bezahlung....in dem Fall bitte PN. |
AW: Update-Vorgang in einen Thread auslagern
Nicht das ich hier jemandem den Job wegnehmen will, aber Bezahlung wird nicht nötig sein.
Ob Du einen Download aufrufst und warten musst oder es in einen Thread auslagerst ist "erst mal" das Gleiche. Mit zwei unterschieden: 1. Deine Application läuft mit anderen aufgaben weiter. 2. Du musst in Deiner Download-Procedure Zugriffe auf ein Form oder die VCL syncronisieren. (Bedeutet mit Syncronize eine Procedure aufrufen, die z.B. eine Processbar updatet) Die eigentliche Frage lauten: An welcher Stelle kommst Du nicht weiter? Mavarik |
AW: Update-Vorgang in einen Thread auslagern
Hallo,
genauso einfach hab ich mir das ja vorgestellt...
Delphi-Quellcode:
Und jetzt scheitert es an der Synchronisierung. Also wie bekomme ich mit, wie weit der Download gerade ist (der Stand des Progressbar in FrmUpdate_Server)
unit uUpdateThread;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TMyUpdateThread = class(TThread) protected procedure Execute; override; end; TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } FMyUpdateThread: TMyUpdateThread; function UpdateStart: boolean; end; var Form1: TForm1; implementation uses Dat_Glo, // Globales Datenmodul Update_Server; // Update-Form {$R *.dfm} procedure Execute_INTERACTIVE; // Schnittstelle zur Update-Form in Update_Server.pas begin Application.CreateForm(TFrmUpdate_Server, FrmUpdate_Server); // Update-Form FrmUpdate_Server.Execute; // Update durchführen end; procedure TMyUpdateThread.Execute; begin Execute_INTERACTIVE; end; procedure TForm1.Button1Click(Sender: TObject); begin UpdateStart; end; procedure TForm1.FormCreate(Sender: TObject); begin FMyUpdateThread := nil; end; function TForm1.UpdateStart: boolean; begin Result := true; FMyUpdateThread := TMyUpdateThread.Create(True); try FMyUpdateThread.FreeOnTerminate := True; // Gibt sich selber frei FMyUpdateThread.Resume; // Start except on E:Exception do begin Result := false; ShowMessage(E.Message); end; end; end; end. Außerdem ist mir nicht klar, wann der Thread "vollkommen" fertig ist, damit ich FrmUpdate_Server wieder freigeben kann. |
AW: Update-Vorgang in einen Thread auslagern
OK! Erst mal in einem Thread kein FormCreate!
Der eigentlich download muss in den Thread... Es gibt ein nettes Beispiel für Anonyme Threads. Das Beispiel zeigt Dir auch direkt den Sync-Aufruf für Process & Ende... Mavarik |
AW: Update-Vorgang in einen Thread auslagern
Hallo,
erst mal vielen Dank für deine Bemühungen. Anonymer Thread bedeutet doch, dass die darin erstellten Objekte nicht geshared werden? Hmmmm....bedeutet das, dass ich dann außerhalb des Threads auf die Eigenschaften der Form zugreifen kann, also beispielsweise den Status des Progressbar abfragen? Weil ich die Form ja auch außerhalb des Thread erstellt habe. Das wäre ja einfach, dann müsste ich nur noch ein paar properties einbauen. Aber dann muss doch der Thread irgendwie die Form aktualisieren...oder stehe ich jetzt total auf dem Schlauch. Hast du mal bitte einen Link auf das obengenannte Beispiel? Hier habe ich unter "Anonyme Threads" nichts prickelndes gefunden. |
AW: Update-Vorgang in einen Thread auslagern
[OT]
Auch wenn du es nicht hören willst, ich sage es trotzdem (nicht das nachher noch jemand sagt, warum das keiner gesagt hat, und ich mir dann denke, warum hast du das denn nicht einfach gesagt ...): Wenn du den Krams umstellst auf
Aber du möchtest es ja nicht hören ... :stupid: [/OT] |
AW: Update-Vorgang in einen Thread auslagern
Ich habe Threads zuletzt immer über
TMultiReadExclusiveWriteSynchronizer oder TCriticalSection synchronisiert. Um Nachrichten zwischen zwei Threads auszutauschen kann mann sich z.B. ein Daten-Objekt bauen und dies in einer CriticalSection übergeben. Sowohl Lesen als auch schreiben muss dann in einer CriticalSection in beiden Threads geschehen. Oft macht es Sinn nicht einfach nur einzelnen Eigenschaften des Daten-Objects zu lesen sondern, statt dessen mit einer Kopie zu arbeiten. Denn die Kopie muss nicht in einer CriticalSection gefasst werden. Wenn man nicht mit Kopien arbeiten will nur um das Datenobjekt von verschiedenen Threads auslesen zu lassen kann man TMultiReadExclusiveWriteSynchronizer Verwenden. Der Blockt das lesen nur dann wenn gerade geschrieben wird. BZW.blockt das schreiben bis das Lesen beendet wurde. Dieses Verfahren ist in Versorger/Verbraucher Konstellationen brauchbar. Wenn Threads hauptsächlich "Warte" Kommt man mit TEvent und und WaitForSingleObject oder WaitForMultipleObjects weiter je nach dem ob man auf ein Event oder auf mehrere wartet. |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Ich möchte dich/euch damit nicht langweilen, aber was da (an dem Installationsprogramm) alles dran hängt, das ist mit keinem Standard-Tool wie Inno & Co lösbar. Wenn es dich/euch interessiert, dann bin ich sehr gerne bereit mal einen Einblick geben, was da alles drin und dran steckt. Dann machen wir woanders (beispielsweise unter "Sonstige Werkzeuge") einen neuen Thread dafür auf. Weil das aber nicht Bestandteil meines Problems ist, wollte ich "alternative Vorschläge" vermeiden. Diese führen in der Regel zu Diskussionen die in der Sache selber nicht weiterbringen. Dafür gibt es hier und in nahezu jedem größeren Internetforum endlose Beispiele. |
AW: Update-Vorgang in einen Thread auslagern
Möglicherweise bist du nicht beratungsresistent, aber dir fehlt es gerade an Fantasie ;)
Mit InnoSetup kann ich mir wunderbar etwas zusammenbauen, was mir aus dem Internet etwas lädt und installiert/ausführt. Ist das auf bestimmte Sachen beschränkt? Nö, muss ja nur etwas ausführbares sein. Also ich könnte mein eigenes Installationsprogramm laden/nachladen wenn nicht aktuell und ausführen. Ja, das ist möglich. Did you get the point? |
AW: Update-Vorgang in einen Thread auslagern
Hallo Andreas,
was du ansprichst sind genau die Dinge, von denen ich zu wenig bis gar keine Ahnung bzw. Praxis habe. Das Installationsprogramm benutzt Units die globale Ressourcen bereitstellen, z.B. die Registry-Einträge die in einem Rutsch beim Programmstart eingelesen werden, und wenn das Programm geschlossen wird, wieder in einem Rutsch zurück geschrieben werden. Das minimiert Registry-Zugriffe. Das Updateprogramm greift auch auf diese globalen Strukturen zu. Also müsste man da "vermutlich" mit Critical Sections arbeiten. Da das aber insgesamt über einen Zeitraum von mehreren Minuten gehen kann, und Critical Sections eher kurz gehalten werden sollen, wird es wieder (zumindest für mich) komplizierter bzw. komplexer, als es auf Anhieb aussieht. Darum war der ursprüngliche Ansatz (siehe Code) der, dass ich die ganze Form und deren Routinen in den Thread hinein packe. Was ich aber lt. Mavarik nicht tun sollte. Mich beschleicht langsam der Gedanke, dass ich mit einer separaten DLL, deren update-ausführende Routine ich in einem Thread lade, dem Ziel näher komme. Dann habe ich zwar keine Synchronisation, aber weniger (Speicher-)Probleme, und ich weiß am Ende der Installation auch, ob der Download läuft oder nicht. Wäre das nicht eine Alternative? @Sir Rufo Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz