nUpdate - Die komfortable Updatelösung

    • Release
    • Open Source

    Es gibt 989 Antworten in diesem Thema. Der letzte Beitrag () ist von Archangel.

      nUpdate - Die komfortable Updatelösung

      Willkommen bei nUpdate,

      nUpdate ist ein umfangreiches Updatesystem für .NET-Anwendungen, mit dem man seine Programme automatisiert und bequem aktualisieren kann. Die Updatepakete werden hierbei mit SHA512-Hashes und 8192 Bit starken RSA-Schlüsselpaaren signiert. Damit ist eine Absicherung gegen das Einschleusen von Malware durch einen Angreifer und gleichzeitig eine Integritätsprüfung möglich.









      Aktuelle Version:
      v4.0.0

      Features:
      • Erstellung von Updatepaketen mit den regulären Einstellungen (Version, Beschreibung, Änderungen, zu ersetzende Dateien, ...) und erweiterten Einstellungen (notwendiges Update, Architektur, nicht unterstützte Versionen, ...).
      • Update Operations für flexibles Ausführen von Operationen während der Updateinstallation (Dateien löschen oder umbenennen, Prozesse oder Dienste starten, Zugriff auf die Registry oder Ausführen von C#-Skripten für komplett eigene Operationen)
      • Vollständige Anpassungsmöglichkeit der Benutzeroberfläche beim Client möglich, gewährleistet durch ServiceProvider, Schnittstellen und dem EAP bzw. TAP
      • Design im Aero-Stil, das auch auf höheren Systemen noch gut aussieht und sich gut integriert
      • Integrierte Benutzeroberfläche in der Bibliothek; Erstellung eigener Oberflächen ist dennoch möglich
      • Paketverwaltung und Fernwartung: Hinzufügen, Bearbeiten und Löschen von Paketen
      • Paket-Log verfügbar
      • Statistiken verfügbar, um in einer Diagrammansicht die verschiedenen Downloads der Pakete zu erfassen und auszuwerten
      • Unterstützung sehr großer Pakete (bis 18.446.744.073.709.551.616 Bytes :P)
      • Signierung der Pakete für den Schutz vor Angreifern und der Einschleusung von Malware (auch bei kompromittierten Servern)
      • Flexible Updatekonfiguration, die jederzeit durch das einfache JSON-Format angepasst werden kann
      • Mehrere Sprachen in der Bibliothek verfügbar: Deutsch, Englisch und Französisch
      • ...

      Web:
      nupdate.net
      GitHub

      Verwendete Programmiersprachen und IDE:
      C#, PHP und SQL; Visual Studio 2022 Community

      Lizenz:
      OpenSource, MIT

      Systemanforderungen:
      • .NET 4.6.1, Windows 7, 8/8.1, 10 und eine .NET Standard 2.0-kompatible .NET-Version für die nUpdate-Bibliothek
      • FTP-Server, Webspace
      • optional: MySQL-Datenbank und PHP

      Systemveränderungen:
      • Registryeintrag für die ".nupdproj"-Extension in der Administration (optional)

      Klassendiagramme:



      Bekannte Probleme:
      • Die Statistikerfassung ist teils noch etwas verbuggt, wenn man Daten diesbezüglich im Projekt ändert
      • Generell sind die Statistiken noch in einem Beta-Zustand und nicht ausgereift
      • Das Bearbeiten von Projekten führt manchmal noch zu Problemen


      Eigene Benutzeroberfläche im nUpdate UpdateInstaller

      Es muss ein neues Projekt erstellt werden, Typ "Klassenbibiliothek". Dieses muss das mitgelieferte nUpdate.Client.GuiInterface referenzieren und das IProgressReporter-Interface implementieren sowie dann einen IServiceProvider.
      Implementiert alle Methoden, InitializingFail kann theoretisch leer bleiben, weil bei einem Fehler beim Initialisieren zu 95% eh nicht mit der angegebenen Form gearbeitet werden kann, ihr könnt es aber sicherheitshalber mal machen.

      Beispielsweise könnte das so aussehen (das ist der integrierte Dialog im nUpdate UpdateInstaller):

      C#-Quellcode

      1. public partial class MainForm : Form, IProgressReporter
      2. {
      3. private bool _allowCancel;
      4. private bool _dataSet;
      5. public MainForm()
      6. {
      7. InitializeComponent();
      8. }
      9. public void Initialize()
      10. {
      11. Icon = Icon.ExtractAssociatedIcon(Program.ApplicationExecutablePath);
      12. Text = Program.AppName;
      13. copyingLabel.Text = Program.ExtractFilesText;
      14. ShowDialog(); // We currently only have an instance, so we show the form as a modal dialog now.
      15. }
      16. public void ReportUnpackingProgress(float percentage, string currentFile)
      17. {
      18. Invoke(new Action(() =>
      19. {
      20. if (!_dataSet)
      21. {
      22. extractProgressBar.Style = ProgressBarStyle.Blocks;
      23. percentageLabel.Visible = true;
      24. _dataSet = true;
      25. }
      26. extractProgressBar.Value = (int) percentage;
      27. copyingLabel.Text = String.Format(Program.CopyingText, currentFile);
      28. percentageLabel.Text = String.Format("{0}%", Math.Round(percentage, 1));
      29. }));
      30. }
      31. public void ReportOperationProgress(float percentage, string currentOperation)
      32. {
      33. Invoke(new Action(() =>
      34. {
      35. extractProgressBar.Value = (int) percentage;
      36. copyingLabel.Text = String.Format("{0}", currentOperation);
      37. percentageLabel.Text = String.Format("{0}%", Math.Round(percentage, 1));
      38. }));
      39. }
      40. public void Fail(Exception ex)
      41. {
      42. Invoke(
      43. new Action(
      44. () =>
      45. Popup.ShowPopup(this, SystemIcons.Error, Program.UpdatingErrorCaption,
      46. ex, PopupButtons.Ok)));
      47. }
      48. public void InitializingFail(Exception ex)
      49. {
      50. Popup.ShowPopup(this, SystemIcons.Error, Program.InitializingErrorCaption, ex,
      51. PopupButtons.Ok);
      52. }
      53. public void Terminate()
      54. {
      55. _allowCancel = true;
      56. Invoke(new Action(Close));
      57. }
      58. private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
      59. {
      60. if (!_allowCancel)
      61. e.Cancel = true;
      62. }
      63. }


      Dann braucht Ihr einen Service, z. B. so:

      C#-Quellcode

      1. using System;
      2. using nUpdate.UpdateInstaller.Client.GuiInterface;
      3. using nUpdate.UpdateInstaller.UI.Dialogs;
      4. namespace nUpdate.UpdateInstaller
      5. {
      6. public class ProgressReporterService : IProgressReporter
      7. {
      8. private readonly MainForm _mainForm;
      9. public ProgressReporterService()
      10. {
      11. _mainForm = new MainForm();
      12. }
      13. public void Fail(Exception ex)
      14. {
      15. _mainForm.Fail(ex);
      16. }
      17. public void Initialize()
      18. {
      19. _mainForm.Initialize();
      20. }
      21. public void InitializingFail(Exception ex)
      22. {
      23. _mainForm.InitializingFail(ex);
      24. }
      25. public void ReportOperationProgress(float progress, string currentOperation)
      26. {
      27. _mainForm.ReportOperationProgress(progress, currentOperation);
      28. }
      29. public void ReportUnpackingProgress(float progress, string currentFile)
      30. {
      31. _mainForm.ReportUnpackingProgress(progress, currentFile);
      32. }
      33. public void Terminate()
      34. {
      35. _mainForm.Terminate();
      36. }
      37. }
      38. }


      ... und dann noch einen ServiceProvider, Beispiel wieder der integrierte:

      C#-Quellcode

      1. using System;
      2. using System.Collections.Generic;
      3. using nUpdate.UpdateInstaller;
      4. using nUpdate.UpdateInstaller.Client.GuiInterface;
      5. [assembly: ServiceProvider(typeof(InstallerServiceProvider))]
      6. namespace nUpdate.UpdateInstaller
      7. {
      8. public class InstallerServiceProvider : IServiceProvider
      9. {
      10. private readonly Dictionary<Type, object> _services;
      11. public InstallerServiceProvider()
      12. {
      13. _services = new Dictionary<Type, object>();
      14. InitializeServices();
      15. }
      16. private void InitializeServices()
      17. {
      18. _services.Add(typeof(IProgressReporter), new ProgressReporterService());
      19. }
      20. public object GetService(Type serviceType)
      21. {
      22. if (serviceType == null)
      23. throw new ArgumentNullException("serviceType");
      24. object service;
      25. return !_services.TryGetValue(serviceType, out service) ? null : service;
      26. }
      27. }
      28. }




      [b]Danksagung:

      Danke an @nafets für das Icon.
      Danke an @Artentus für den ExplorerNavigationButton.

      Download:
      Neueste Versionen: Auf GitHub
      NuGet):

      PM> Install-Package nUpdate -Version 4.0.0
      PM> Install-Package nUpdate.UI.WindowsForms -Version 4.0.0
      PM> Install-Package nUpdate.UI.WPF -Version 4.0.0

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Dieser Beitrag wurde bereits 88 mal editiert, zuletzt von „Trade“ ()

      Yay, finally! :D Gute Arbeit. Werde ich morgen austesten.

      Eine Frage hab ich aber:
      Als Lizenz steht zwar SugarCRM aber in der LICENSE-Datei ist die Mozilla Public License. Oder ist es so zu sagen dasselbe?
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Danke, mal sehen, ob es läuft. ;)
      Jou, das ist die, siehe tldrlegal.com/license/sugarcrm…e-v1.1.3-(sugarcrm-1.1.3)

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Habe gerade schon mal einen Blick drauf geworfen, ist schön, dass das ganze so an UpdateSystem.Net angelehnt ist, sodass man sich nicht komplett umgewöhnen muss.

      Sicher, dass ich auf den Desktop mit %temp% komme? :D
      Und irgendwie hört sich "How does the updating work" komisch an (bin kein Englischprofi!). Vielleicht eher "How does the update process work"?


      Was hat das zu bedeuten? (Kommt, wenn ich auf Preferences klicke)
      Mfg
      Vincent

      Wenn ich die Einstellungen in der Administration öffnen will bekomme ich folgenden Fehler:



      EDIT: Auch beim erstellen der neuen UpdateManager-Instanz



      Anscheinend versucht es auf D:\ zuzugreifen, was bei mir das DVD-Laufwerk ist.
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „KaskadekingDE“ ()

      @VincentTB Danke, das war meine Intention.
      Kannst Du bei der Meldung bitte bei dem Fehlertext einen Rechtsklick machen und den StackTrace posten?

      Das mit dem "%temp%" scheint ein Kopierfehler zu sein, ich werde das beheben, danke!

      @KaskadekingDE
      Auch bitte ganzen StackTrace posten, sonst bringt mir das nix. ;)
      Beim zweiten Fehler, was genau ist die Meldung bzw. wo wird das ausgelöst?

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      @Trade
      Spoiler anzeigen

      Quellcode

      1. System.IO.DirectoryNotFoundException: Ein Teil des Pfades "D:\Desktop\en.json" konnte nicht gefunden werden.
      2. bei System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
      3. bei System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      4. bei System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      5. bei System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost)
      6. bei System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
      7. bei nUpdate.Updating.UpdateManager..ctor(Uri updateConfigurationFileUri, String publicKey, UpdateVersion currentVersion, CultureInfo languageCulture) in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate\Updating\UpdateManager.cs:Zeile 64.
      8. bei nUpdate.Administration.UI.Dialogs.PreferencesDialog..ctor() in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate Administration\nUpdate Administration\UI\Dialogs\PreferencesDialog.cs:Zeile 19.
      9. bei nUpdate.Administration.UI.Dialogs.MainDialog.sectionsListView_Click(Object sender, EventArgs e) in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate Administration\nUpdate Administration\UI\Dialogs\MainDialog.cs:Zeile 278.
      10. bei System.Windows.Forms.ListView.WmReflectNotify(Message& m)
      11. bei System.Windows.Forms.ListView.WndProc(Message& m)
      12. bei nUpdate.Administration.UI.Controls.ExplorerListView.WndProc(Message& m) in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate Administration\nUpdate Administration\UI\Controls\ExplorerListView.cs:Zeile 77.
      13. bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
      Mfg
      Vincent

      Ok hier der vollständige Stacktrace:

      Spoiler anzeigen

      Quellcode

      1. System.IO.IOException wurde nicht behandelt.
      2. HResult=-2147024875
      3. Message=Das Gerät ist nicht bereit.
      4. Source=mscorlib
      5. StackTrace:
      6. bei System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
      7. bei System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      8. bei System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      9. bei System.IO.StreamWriter.CreateFile(String path, Boolean append, Boolean checkHost)
      10. bei System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost)
      11. bei System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
      12. bei System.IO.File.WriteAllText(String path, String contents)
      13. bei nUpdate.Updating.UpdateManager..ctor(Uri updateConfigurationFileUri, String publicKey, UpdateVersion currentVersion, CultureInfo languageCulture) in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate\Updating\UpdateManager.cs:Zeile 64.
      14. bei ---.UI.Forms.FrmMain..ctor() in c:\Users\Kaskadeking\Documents\Visual Studio 2013\Projects\...\...\UI\Forms\FrmMain.cs:Zeile 46.
      15. bei ---.Program.Main() in c:\Users\Kaskadeking\Documents\Visual Studio 2013\Projects\...\...\Program.cs:Zeile 17.
      16. bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
      17. bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
      18. bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
      19. bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
      20. bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
      21. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
      22. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
      23. bei System.Threading.ThreadHelper.ThreadStart()
      24. InnerException:


      Dabei ist mir das aufgefallen: d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate\Updating\UpdateManager.cs:Zeile 64.. Die Datei exestiert aber nicht (wie gesagt ist D:\ bei mir das DVD-Laufwerk)


      Der Fehler tritt bei der Instanziierung auf (UpdateManager _manager = new UpdateManager([...])
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Da scheint in beiden Fällen etwas mit dem UpdateManager nicht ganz zu wollen, der nimmt da anscheinend hardcoded die Pfade von mir, ich werde das mal prüfen.
      Edit: Ich glaube, ich habe es, @VincentTB und @KaskadekingDE, ich habe nach dem Commit für das Language Template noch schnell eine Zeile eingefügt, die den Content der LocalizationProperties bei mir in eine Datei auf dem Desktop speichert und dieser Pfad ist hardcoded.

      Da habe ich zu früh erstellt gehabt, sodass diese Zeile noch drin ist. :whistling:
      Update in weigen Minuten.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Trade“ ()

      Update auf Version 0.1.0.0 Alpha 2

      Changelog:
      github.com/ProgTrade/nUpdate/c…32c4adaf6d4e029d7f382fb1c
      • Fixed a bug that caused an IOException when instantiating the
        UpdateManager
      • Fixed typo in the updating information dialog
      • Adjusted window titles

      Sollte jetzt klappen, ich habe es mal neu erstellt und mir erlaubt, die erste Version aus dem Startpost zu nehmen, da die ja praktisch gar nicht ging.
      Ich werde schauen, dass ich evtl. die Änderungen ab jetzt in einzelne Commits aufsplitte.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

      Direkt neuer Fehler bei der Instanziierung :rolleyes:

      Spoiler anzeigen

      Quellcode

      1. System.InvalidOperationException ist aufgetreten.
      2. HResult=-2146233079
      3. Message=Die Sequenz enthält kein übereinstimmendes Element.
      4. Source=System.Core
      5. StackTrace:
      6. bei System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
      7. bei nUpdate.Updating.UpdateManager.Initialize() in d:\Documents\Visual Studio 2013\Projects\nUpdate\nUpdate\nUpdate\Updating\UpdateManager.cs:Zeile 660.
      8. InnerException:
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Das ist sehr komisch, denn die Exception wird eig. genau aus dem Grund abgefangen. Ich werde das durch eine Abfrage ersetzen, ist eh besser.
      Ist der Debugger zu der Stelle gesprungen? Zeige mir dann mal einen Screenshot davon, also dem Exceptionfenster.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Kann sein, da ich nähmlich in den Ausnahmeeinstellungen die CLR-Exceptions auch auslöse wenn die Exception gecatcht werden. Das mach ich eigentlich immer weil ja Exceptions im Load-Event unter anderen einfach vom Framework verschluckt werden. Also wahrscheinlich "Fehlalarm" ^^
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Jou, sowas hatte ich vermutet (kenne das ;)).
      Aber ganz verkehrt war's nicht, denn Abfragen sind da eh besser, kommt im nächsten Update.

      Hat sonst mal alles geklappt?

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Er zeigt jetzt erstmal keine Fehler mehr an. Ob das updaten funktioniert werde ich gleich austesten ;)

      EDIT2: Ok hab's gefunden ^^
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „KaskadekingDE“ ()

      Das ​UpdaterUi regelt das alles bereits automatisiert, das heißt, das passiert da schon alles intern, Du musst nix mehr suchen o. ä.
      Falls Du auf Updates prüfen willst und dem User das nicht anzeigen willst, also im Hintergrund, dann nutze die UseHiddenSearch-Property.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Also wenn kein Update gefunden wird bekomme ich immer eine Meldung das die Anwendung auf dem neusten Stand ist (was ich nicht möchte, sondern nur wenn ein Update verfügbar ist soll ein Dialog angezeigt werden). Jetzt hab ich's einfach übers UpdateSearchFinished-Event gelöst.
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Wie sieht Dein Code aus? Hast Du die Property verwendet?

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Ja schon. Aber wie zeige ich dann den Dialog an wenn ein Update verfügbar ist, wenn ich UseHiddenSearch verwende?

      BTW:


      Edit: Sieht aus als ob das UpdaterUi auch nochmal das UpdateSearchFinished-Event feuert.
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Wie gesagt, Du musst gar nichts machen, das ​UpdaterUi macht alles ganz von selbst. Du musst also nicht mehr ​SearchForUpdates aufrufen, das wird dort alles intern geregelt.
      github.com/ProgTrade/nUpdate/b…ate/Updating/UpdaterUi.cs

      Du musst praktisch nur den Code vom Startpost implementieren.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!: