![]() |
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:
|
AW: Update-Vorgang in einen Thread auslagern
Die Kommunikation zwischen Threads und der Außenwelt geschieht über synchronisierte Events und geschützte Properties.
Der Thread ackert also im Hintergrund, möchte aber, das sein innerer Zustand (Was macht er gerade? Wie weit ist er?) in einer Form sichtbar ist. Fein. Dann unterhalten die sich eben, aber nicht direkt, bitte. Das ist praktisch, weil so eine Form auch gut für andere Threads verwendet werden kann und andererseits so ein Thread auch mit einer anderen Form reden kann (oder mit gar keiner, sollte ihm schnurz sein). Es bieten sich zum Unterhalten Events oder Interfaces an. Beides muss aber synchronisiert werden, d.h. Thread und Außenwelt laufen ja in unterschiedlichen Threads und die VCL ist nicht threadsafe, d.h. alles, was mit der VCL geschieht, muss im Hauptthread gemacht werden. Nehmen wir mal folgenden Thread;
Delphi-Quellcode:
Die fraglichen Methoden sind also 'ShowProgressBar', 'UpdateProgressBar' und 'HideProgressBar'.
Procedure TMyThread.Execute;
Begin ShowProgressBar(); MaxSteps := 1000; For i:=1 to MaxSteps do begin Self.Progress := I; UpdateProgressBar(); DoSomething(); end; HideProgressBar(); End; In jedem Fall müssen die erst einmal per 'Synchronize' (oder 'Queue') aufgerufen werden, denn diese beiden Methoden sorgen dafür, das die Aufrufe im Kontext des VCL-Threads durchgeführt werden. Also:
Delphi-Quellcode:
Ok. Nun gibt es (mindestens) zwei Ansätze, wie die konkrete Kommunikation mit einem Formular aussehen kann.
Procedure TMyThread.Execute;
Begin Synchronize(ShowProgressBar); MaxSteps := 1000; For i:=1 to MaxSteps do begin Self.Progress := I; Synchronize(UpdateProgressBar); DoSomething(); end; Synchronize(HideProgressBar); End; 1. Mit Events. Der Thread deklariert drei Eventhandler ,'OnShowProgressBar', 'OnHideProgressBar' und 'OnUpdateProgressBar' (geht auch mit einem Event, aber egal). Das Formular meldet sich auf die Events an und führt die VCL-Änderungen (Progressbar zeigen, verbergen, updaten) aus. So ungefähr
Delphi-Quellcode:
Oder mit einem Interface. Dabei erwartet der Thread eine 'View', die die drei Methoden zum Anzeigen der Progressbar bereitstellt.
Type
TMyThread = Class... public OnShowProgressBar : TNotifyEvent Read FOnShowProgressBar Write FOnShowProgressBar; OnHideProgressBar : TNotifyEvent Read FOnHideProgressBar Write FOnHideProgressBar ; ... end; Procedure TMyThread.ShowProgressbar; Begin if Assigned (FOnShowProgressBar) Then FOnShowProgressBar(Self); End; ... Procedure TMyForm.StartThread; Begin FmyThread := TmyThread.Create; FmyThread.OnShowProgressBar := ShowProgressBar; FmyThread.OnHideProgressBar := HideProgressBar; ... End; Procedure TMyForm.ShowProgressBar (Sender : TObject); Begin Progressbar.Visible := True; End;
Delphi-Quellcode:
Das geht alles viel einfacher und besser, aber das Prinzip sollte klar sein. Standardpattern bei Delphi sind die Events. In anderen Programmiersprachen eher die Interfaces (Java kennt z.B. gar keine Delegaten).
Type
IProgessBar = interface procedure ShowProgressBar; Procedure HideProgressBar; Procedure UpdateProgressBar (Position, Total : Integer); End; TMyThread = class (TThread) FProgess : IProgressBar; public Constructor Create (aProgress : IProgress); End; ... Procedure TMyThread.ShowProgressBar; Begin if Assigned (FProgress) then FProgess.ShowProgressBar; End; Procedure TMyThread.UpdateProgressBar; Begin if Assigned (FProgress) then FProgess.UpdateProgressBar (Self.Position, Self.Total); End; .... Type TMyForm = Class (TForm, IProgress) ... Procedure ShowProgressBar; Procedure HideProgressBar; Procedure UpdateProgressBar (Position, Total : Integer); End; |
AW: Update-Vorgang in einen Thread auslagern
Eigentlich ist das ein Fall für den asynchronen Prozeduraufruf.
Ältere Delphi-Versionen unterstützen das noch nicht. In jedem Fall muss der Hauptthread die Ereignisse selbst auslösen. A) Der Thread sendet Informationen über den Fortschritt mit Postmessage als Botschaft an ein Fenster, eine Komponente verarbeitet die Nachrichten und löst die Ereignisse aus. Es ist aber nicht zu 100% sichergestellt, das wirklich alle Nachrichten auch den Empfänger erreichen, insbesondere wenn sehr viele Nachrichten in kurzer Zeit anfallen. B) Der Thread legt Informationen über den aktuellen Progressstatus in einem geschützten Record ab, der Hauptthread prüft diesen Record periodisch (OnIDLE der Anwendung oder Timer). Dabei können aber auch einzelne Schritte übersprungen werden, insbesondere wenn der Thread sehr schnell arbeitet. C) Der Thread legt jede Ereignis z.B. als Objekt mit allen Informationen in einer geschützten Liste ab, der Hauptthread prüft die Liste periodisch (OnIDLE der Anwendung oder Timer). Der Aufwand ist wahrscheinlich größer, das scheint aber die sicherste Variante zu sein. |
AW: Update-Vorgang in einen Thread auslagern
Na, asynchron muss das Update der Progressbar hier nun doch nicht sein. Besser wäre es natürlich, aber es geht auch so.
Bei zeitkritischen Threads, die ihre Zeit nicht mit dem Update einer UI verplempern wollen, ist das natürlich anzuraten (wobei dann ein Timer in der UI noch einfacher umzusetzen ist. EDIT: Ach, das ist ja deine Antwort 'B'). |
AW: Update-Vorgang in einen Thread auslagern
Hallo !
Zitat:
Wie muss das in der Form1 dann aussehen (komplette Deklaration), ich meine damit durch den Thread ein Event in Form1 oder Form2, .... ausgelöst wird, das ist mir vollkommen unklar ? Ich denke damit kann man dann an mehreren Stellen im Programm auf Änderungen reagieren oder (ich denke hier z.B. an die Umstellung des Währungsformats, der Nachkommastellen, ....) ? |
AW: Update-Vorgang in einen Thread auslagern
Das mit dem Interface sieht natürlich klasse im Source aus...
Aber warum sendest Du nicht einfach aus dem Thread eine User-Message über Windows und schon sparst Du Dir das Syncronize!
Delphi-Quellcode:
Für Update einfach im WParam 0..100% übergeben und fertig.
Const
WM_PShow = WM_User + 400; WM_PHide = WM_USer + 401; WM_PUpdate = WM_USer + 402; type TMyForm = class(TForm) private procedure WMShowPBar(var Msg:Tmessage); message WM_PShow; procedure WMHidePBar(var Msg:Tmessage); message WM_PHide; procedure WMUpdatePBar(var Msg:Tmessage); message WM_PUpdate; end; Mavarik |
AW: Update-Vorgang in einen Thread auslagern
Hey Mavarik: Messages hab ich total vergessen. Sehr schöne Möglichkeit, speziell mit 'PostMessage' (asynchron)
Was mir daran als Pattern nicht so sehr gefällt ist die etwas problematische Übergabe komplexerer Informationen. Denn die müssen im Thread instantiiert und im Messagehandler (beim Postmessage) wieder freigegeben werden. Geht, ist sauber, aber imho nicht so schön (reine Geschmackssache) Was mir daran allerdings gefällt, ist der äußerst niedrige Footprint zum Erzeugen von asynchronen Updatemöglichkeiten. Zitat:
Delphi-Quellcode:
Type
TForm1 = class (TForm) ... Procedure UpdateProgressBar (Sender : TObject); // Das ist die Signatur eines TNotifyEvent ... Procedure TForm1.Button1Click(Sender : TObject); Begin FMyThread := TMyThread.Create; FMyThread.OnUpdateProgressBar := UpdateProgressbar; // Zuweisung des Eventhandlers an das Event ... Zitat:
|
AW: Update-Vorgang in einen Thread auslagern
Eventuell weil das zu stark mit der Plattform verbunden ist?
Weil man sich dafür einen MessageManager schreibt, den man dann für alles benutzen kann und vor allem verständliche und einfach zu handhabende Messages durch das System leiten kann. Auf den Trichter ist auch Emba gekommen ![]() Den Nachrichtentypen definieren:
Delphi-Quellcode:
Die Form damit verbinden
unit MyCustomMessages;
uses System.Messaging; type TProgressMessage = class( TMessage ) public constructor Create( Position, Max : Integer ); property Position : Integer read FProgress; property Max : Integer read FMax; end;
Delphi-Quellcode:
Der Thread schmeisst die Nachricht
uses
System.Messaging; TFoo = class( TForm ) Progressbar1 : TProgressBar; private procedure HandleProgressMessage( const Sender : TObject; const M : TMessage ); public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; implementation uses MyCustomMessages; procedure TFoo.AfterConstruction; begin inherited; TMessageManager.DefaultManager.SubscribeToMessage( TProgressMessage, HandleProgressMessage ); end; procedure TFoo.BeforeDestruction; begin TMessageManager.DefaultManager.Unsubscribe( TProgressMessage, HandleProgressMessge ); inherited; end; procedure TFoo.HandleProgressMessage( const Sender : TObject; const M : TMessage ); var LMsg : TProgressMessage absolute M; begin ProgressBar1.Position := LMsg.Position; ProgressBar1.Max := LMsg.Max; end;
Delphi-Quellcode:
Und schon klappt das auf jeder Plattform, auch ohne irgendwelche Fenster (Handle) offen zu haben, egal wer das empfangen möchte, kann sich einfach an den MessageManager hängen und alles ist gut.
uses
System.Messaging, MyCustomMessages; procedure TFooThread.Execute; var LPosition, LMax : Integer; begin while WorkInProgress do begin // Fortschritts-Nachricht verschicken Queue( procedure begin TMessageManager.DefaultManager.SendMessage( Self, TProgressMessage.Create( LPosition, LMax ) ); end ); ... end; end; |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Selbst wenn es ein mehr ist.. im thread ein guter alter Getmem und im Form der Freemem. Da man das kaum noch verwendet - ist sofort klar - Oh ein Getmem... Da muss sich jemand anderes darum kümmern das wieder frei zu geben... Mavarik |
AW: Update-Vorgang in einen Thread auslagern
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Aber er sprach von einem eigenen Installer - Sieht mir nicht nach iOS/Android oder Mac aus...:stupid: Also ist es - erst mal - nicht so schlimm, wenn es nur für Windows ist. Abgesehen davon spart man sich das Queue...:twisted: Mavarik PS.: Du schreibst jetzt 100x "Ich soll keinen kompletten Sourcecode im Forum posten" |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Aber ansonsten hast Du natürlich vollkommen recht. Dein Ansatz ist absolut gleichrangig und reine Geschmackssache (oder Starrsinn), das ich es nicht verwende. Also: bisher 4 schöne Pattern, um Aktualisierungen aus einem Thread in einen anderen zu übermitteln: 1. Events 2. Interfaces 3. Messages 4. Observer-Pattern (@Sir Rufo, einverstanden?) |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
|
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Es mag dich in keiner weise beeinflussen, aber ich finde es nicht notwendig parrallel updates runterzuladen. Ich mag alles schön der reihe nach. Es ist nur ein Setu. So oft macht man das nicht. Wofür brachst du zum Starten eines downloads die Aufmerksamkeit des Benutzers? Damit er sich auf einem Proxyanmeldet fals es sowas beim Kunden gibt? Ich habe as Problem noch nicht vollständig erkannt dass du gedenkst mit einem parallel laufenden Download lösen zu wollen. Man kann solche Downloads auf jeden Fall auch einfach in einem eigenen Prozess machen. Dann erübrigt sich die Thread-Problematik. |
AW: Update-Vorgang in einen Thread auslagern
Mir ist es ein Rätsel, wieso man den Download nicht einfach in einen kleinen Thread packt und mit einer der vier vorgestellten Methoden im Formular rummalt. Das kann doch nun jeder. Oder hab ich etwas verpasst?
|
AW: Update-Vorgang in einen Thread auslagern
Hallo zusammen,
so, ich war den halben Tag beschäftigt meinen Code umzubauen und die andere Hälfte mit Einkaufen (mit Frau...:thumb: ) und jetzt komme ich auch mal dazu, hier nachzuschauen was es neues gibt. Und war erst mal positiv überrascht von den vielen Antworten. Also, Stand der Dinge: Zuerst war es von der Aufgabenverteilung so: Update-Form für das UI, eine Unit mit der Logik (Connect, Download, Disconnect, Installation der neuen programmdateien usw.) und das Datenmodul. Das Datenmodul blieb bis auf ein paar kleine Änderungen wie es ist. Die Unit mit der Logik entfällt, die habe ich heute neu programmiert. Sie beinhaltet jetzt meinen Thread, der den Download durchführt. Die Beispiele im WEB (nicht die von euch hier...die habe ich ja jetzt erst gelesen) hatten hinsichtlich der Synchronisierung eines gemeinsam: Der Thread muss mit dem aufrufenden Objekt kommunizieren, damit er z.B. die Fortschrittanzeige aktualisieren kann. So eine Vorgehensweise geht mir gegen den Strich. Der Thread soll sich um den Download kümmern müssen, und sonst nichts! Das war der Ansatz. Und, aktueller Stand, es funktioniert. Das Installationsprogramm fordert irgendwann am Anfang die Eingabe der Lizenznummer. Dann wird die Lizenz vom WEB_Server heruntergeladen. Die Verbindung steht also zu dem Zeitpunkt schon. Normalerweise wird sie getrennt, und das Installationsprogramm fortgesetzt. Jetzt setze ich die Installation genauso fort, und starte den Thread. Während der weiteren Installation (das Setup kopiert die Dateien usw.) lädt der Thread eventuell vorhandene aktuellere Dateien herunter. Ist die Installation abgeschlossen, kann es im Großen und Ganzen nur zwei Zustände geben: Der Download-Thead arbeitet noch, oder ist schon fertig. Wenn er schon fertig ist, gibt (bzw. gab) es überhaupt keine Anforderung etwas zu synchronisieren, und wenn das Setup schon fertig ist und dann quasi auf den Thread warten muss...hat das Setup ja nichts mehr zu tun. Mit einem Timer frage ich dann die property "Progress" des Threads ab, aktualisiere den Progressbar in der MainForm, und warte bis der Thread fertig ist. Exakt so verwendet dann später mein Update-Programm den Thread. Es sind darin nur noch ein paar Zeilen Code zu ändern. UI, Logik und Daten voneinander zu trennen hat sich wieder mal bewährt. Das ist so einfach, dass ich mich im Nachhinein wundere, es nicht schon vorher so gemacht zu haben. Und die "Angst" vor Threads ist jetzt auch weg. Im Gegenteil, ich habe jetzt Lust auf mehr. Zitat:
Vielen Dank auch an alle die sich Mühe und Gedanken gemacht haben. Wie gesagt, es funzt momentan schon, aber ein paar kosmetische Kleinigkeiten sind noch zu erledigen. Und dann kommen ja noch ein paar neue Anforderungen auf mich zu. Das Setup ist nämlich nicht nur für Installation und Deinstallation zuständig, auch für Datensicherung, Datenrücksicherung, PC-Umzug(Migration), Datenbankprüfung usw. Also noch genügend Potential für Threads, um zum Beispiel gleichzeitig mehrere Mandanten(-Datenbanken) zu sichern. BTW wenn es "nur" ein popeliges Installationsprogramm wäre, hätte ich es ja nicht selber geschrieben, sondern mit Inno gemacht. |
AW: Update-Vorgang in einen Thread auslagern
Ich habe den Updatevorgang in meiner Software auch in einen Thread ausgelagert.
Ganz klarer Vorteil: - man kann ungestört weiterarbeiten und braucht die Software nicht erst zu beenden um einen "Update-Checker" zu starten. Nach erfolgreichem Download der Updates muss man logischerweise die Software neu starten und ein kleiner "Client", wenn man denn so programmiert hat, muss die Updates installieren. Aber immer noch, für mich, die beste Lösung. |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
|
AW: Update-Vorgang in einen Thread auslagern
Sehr schön :thumb: Solche Software mag ich. Für mich ist Usability das fast Wichtigste einer Software.
|
AW: Update-Vorgang in einen Thread auslagern
Da wird ein Update installiert, ohne mich zu fragen ??? Das ist aber benutzerfreundlich. ;-)
|
AW: Update-Vorgang in einen Thread auslagern
Liste der Anhänge anzeigen (Anzahl: 1)
Dich fragt ja auch keiner, oder hat keiner gefragt. Es ist vollkommend ausreichend, wenn ich meine Kunden um Erlaubnis frage.
|
AW: Update-Vorgang in einen Thread auslagern
Zitat:
|
AW: Update-Vorgang in einen Thread auslagern
Vielleicht so für den Anwender auswählbar:
a. Updates automatisch suchen, herunterladen und installieren b. Updates automatisch suchen herunterladen und manuell installieren c. Updates automatisch suchen, manuell herunterladen und manuell installieren d. Update manuell suchen. -> [Jetzt suchen] Und in einem Firmennetz muss es möglich sein, dass der Domänen-Admin bestimmen kann, wie geupdatet wird. Das kann ein Auskriterium bei Firmen sein. |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Es gibt auch eine Option, um Updates mit Bestätigung oder ohne, also Silent, zu installieren. Usability ;) Damals wurde mir beigebracht, selbst die dümmsten Szenarien zu beachten. Denn es gibt nichts, vorsicht, "Dümmeres" als den Endbenutzer. |
AW: Update-Vorgang in einen Thread auslagern
Hallo,
die angesprochenen Möglichkeiten gibt es natürlich. Meine Mitbewerber spielen ja fast ausnahmslos in der Champions-League-Größe mit über 20.000 Kunden, und da ist es manchmal nicht leichtr mitzuhalten. Der Kunde kann auswählen, ob er generell Updates installieren will, in welchem Intervall (wöchentlich, monatlich), an welchem Wochentag, und zu welchem Zeitpunkt. Diese Einstellungen gehören jedoch nicht in ein Installationsprogramm. Dafür gibt es die programminternen Systemeinstellungen mit einer Benutzerrechte-Verwaltung. Hier ist festgelegt, welcher Benutzer überhaupt an diesen Einstellungen Änderungen vornehmen darf. Der Benutzer, der das Update installiert, hat also nicht zwangsläufig auch das Recht, diese Einstellungen ändern zu dürfen. In diesem Fall geht es mir im Speziellen darum, den Lebenszyklus einer CD von etwa einem Jahr zu optimieren bzw. zu gewährleisten. Wenn die CD's zum Jahreswechsel gepresst werden, dann sollen sie auch das ganze Jahr über verwendbar sein. Denn, es sind natürlich neben den Kunden auch potentielle Interessenten, welche die CD erhalten. Mich ärgert in diesem Zusammenhang immer, wenn ich eine CD installiere, dass das installierte Programm beim bzw. nach dem ersten Start schon nach Updates sucht bzw. suchen muss. Zu diesem Zeitpunkt habe ich andere Vorstellungen und Interessen. Und zudem entsteht der Eindruck, dass die CD "veraltet" ist. Der erste Eindruck ist da schnell dahin. Beim Software-Download (ESD) sieht das natürlich wieder ganz anders aus, aber der ESD-Anteil liegt bei mir bei unter 10%. |
AW: Update-Vorgang in einen Thread auslagern
Ich habe derartiges nie anbieten müssen, da die Software vom Kunden installiert wird, d.h. ich 'liefere' an die Haustür, auch Updates und Bugfixes und der Kunde bzw. mein single point of contact ist dann dafür verantwortlich, die Updates zu testen und zu deployen.
Nicht, das das eine bessere Möglichkeit wäre, ich kam nur nie in Verlegenheit, eine derartige Funktion implementieren zu müssen. Oder habe mich drum drücken können. |
AW: Update-Vorgang in einen Thread auslagern
Zitat:
Die blöden Fehler rutschen doch bei allen Tests durch... Wenn nicht hätte man die ja schon beseitigt. Wenn also die ersten 100 Kunden die neue CD installiert haben, gibt es doch schon das 1. Update oder? Wer nein sagt werfe das 1. Byte... Deswegen legen einige Kunden immer eine neue CD erst in die Schublade... Bis Version := Version + 0.01 da ist... Mavarik |
AW: Update-Vorgang in einen Thread auslagern
Hallo Frank,
Zitat:
Etwa 1/3 meiner Kunden installiert ein neues Update innerhalb der ersten Woche nach Erscheinen und etwa 1/10 sogar innerhalb der ersten zwei Tage. Wenn mir also wirklich ein Fehler durch die Lappen geht, weiß ich das i.d.R. schon in ein paar Tagen. Mit der jetzigen Lösung bedeutet das, dass etwa 2/3 gar nichts mitbekommen würden, und das beruhigt schon enorm. Da half übrigens bisher auch das Update "nach" der Installation oft nichts, denn wir wissen ja, wo die User hinklicken sollen, und es trotzdem nicht tun. Ein WEB-Update braucht nun mal auch Admin-Rechte um Dateien überschreiben zu dürfen. Die Code-Signierung hat schon etwas gebracht, weil das blaue Fenster doch etwas vertrauenserweckender ist. Aber... - Haben Sie das blaue Fenster mit dem Hinweis nicht gesehen? - Doch, das habe ich immer weg gedrückt...mache ich immer so...es ging ja auch weiter... :cyclops: :cyclops: Zitat:
20.14.11210.18 entschlüsselt: 20.14 = Jahr 11210 = immer eine "1" und dann Monat und Tag des Build zweistellig, hier also der 10.12.2014 .18 = Fortlaufende Build-Nummer. Die Versions-Nummer wird also permanent größer, und hat niemals irgendwas mit ".01" oder so. Und, es hilft, hat sich bestens bewährt :-D |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:22 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