Update-Funktion für Programme

  • VB.NET

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von BattleMaker.

    Update-Funktion für Programme

    Ich habe eine .NET-Anwendung geschrieben, die langsam aber sicher bekannter (und auch beliebter) wird. Mindestens 1 Mal pro Woche bringe ich eine neue Version raus, die es auf meiner Website zum Herunterladen gibt. :D

    Das nervige is, dass man ständig auf meine Website gehen, das Archiv herunterladen und entpacken muss, bis man die neue Version genießen kann. X(


    Ich wüsste gerne, wie ich eine Verbindung mit dem Internet aufbaue und die Programm-EXE mit einer neuen EXE-Datei (die auf meinem Webspace liegt) überschreibe. :rolleyes: In der FAQ stand leider nix... ;(

    Das hier betrifft .NET, doch dies sollte trotzdem das richtige Forum sein.

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

    Hi!

    Also Dateien kannst du ganz einfach über HTTP empfangen:

    Imports System
    Imports System.Net
    Imports System.IO
    Imports System.Text

    Module Main
    Sub Main()
    Dim myRequest As WebRequest = WebRequest.Create("http://www.deindomain.de/neueversion.exe")
    Dim myResponse As WebResponse = myRequest.GetResponse()
    Dim myStream As Stream = myResponse.GetResponseStream()
    Dim myData(myResponse.ContentLength) As Byte
    myStream.Read(myData,1,myResponse.ContentLength)
    Dim myEncoding As Encoding=Encoding.ascii
    Console.write(myEncoding.GetString(myData))
    myResponse.Close()
    End Sub
    End Module


    Du musst diesen Code nur noch umbauen:
    1.Momentan wird versucht die komplette Datei vom Server in einen einziges Byte-Array, später String zu speichern. Der Array, bzw. String läuft bei größeren Dateien dann über ...
    2. Momentan wird die empfangenen Datei nur in der Konsole ausgegeben. Du musst das Programm umbauen und die ankommenden Daten in eine Datei speichern ...
    FERTIG!

    Ich denke, dass du so viel Erfahrung hast, dass du den Programmteil selber umbauen kannst. :)

    Jue ;)

    (P.S.: Der Code kommt von ein paar Threads weiter unten ...)

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

    Wie soll das denn mit einer Exe-Datei gehen. ?(

    So wie es aussieht, lese ich ja den Inhalt der Datei aus. Wenn ich den aber in eine Datei namens \'programm.exe\' reinschreibe, dann funzt die EXE-Datei nicht. Denn EXE-Files werden in einem bestimmten Format abgespeichert, mit den Icons usw... X(

    Außerdem hab ich keine Ahnung wofür hier die ganzen Variablen nötig sind. Bitte erklärt doch die Variablen wie myRequest, etc... in Netzwerkprogrammierung hab ich absolut keine Ahnung. ;(

    Natürlich probier ichs währenddessen weiter! :D


    So weit bin ich bis jetzt gekommen. Was jetzt?

    Public Shared Sub UPDATEemaggo()
    \' Prozedur, die emaggO auf die neuste Version updatet
    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.bmaker.net/Downloads/emaggO.exe")
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse()
    myResponse.Close()
    End Sub

    Generelle Fragen
    1. Was kriege ich mit der Methode \'emaggOexeRequest.GetResponse\'?
    2. Wozu brauche ich nochmals eine Variable myResponse, wenn ich doch schon ein \'Respons\' per Objektmethode \'emaggOexeRequest.GetResponse\' bekomme.

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

    Noch ein großes Prob: die EXE kann man gar nicht editieren, da sie \'von einem anderen Prozess verwendet wird\'.

    Ich habs nämlich so probiert:

    Public Shared Sub UPDATEemaggo()
    \' Prozedur, die emaggO auf die neuste Version updatet
    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.bmaker.net/Downloads/emaggO.exe")
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse()
    FileOpen(1, "emaggO.exe", OpenMode.Output)
    FilePutObject(1, myResponse.GetResponseStream)
    myResponse.Close()
    End Sub
    Ich hab das Problem mittlerweile anders gelöst.

    Zwar updatet das Programm immer noch nicht automatisch, doch es wird viel komfortabler nach einer neuen Version "gesucht".


    Hier, ihr könnt ja mal ein wenig rumspielen:

    <form method="GET" action="http://battlemaker.funpic.de/emaggoversioncheck.php">
    Version: <input name="Version" type="Text">
    <input type="submit">
    </form>

    <hr>
    <font color="red"> Edit by LaMa5:

    Zitat aus den Boardregeln:
    "Mehrere Postings hintereinander in einem Thread (Thema) sind nur erlaubt, wenn dies unbedingt erforderlich ist, ... "

    In meinen Augen ist es nicht unbedingt erforderlich gewesen hier gleich 3 Postings hintereinander reinzusetzen!
    Benutze beim nächsten Mal bitte die Editierfunktion !!! </font>

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

    hi!

    zu deinem Auto-Update-System:
    Kennst du Antivir? und die updatefunktion von antivir? Wenn nicht erklär ichs dir halt mal:
    Antivir hat einmal das Hauptprogramm und ein kleines 2. Programm, welches die Inet-Updats ausführt. So würd ich das an deiner Stelle auch lösen: Du bastelst dir ein 2. Internet-Update-Programm. Du kannst dann die Exe des Hauptprogrammes problemlos überschreiben. Ich hab mal dein Code und deine Versionsabfrage mal verbunden:

    Public Shared Sub UPDATEemaggo()
    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://battlemaker.funpic.de/emaggoversioncheck.php?version="+aktVersi
    on)
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse()
    FileOpen(1, "emaggO.exe", OpenMode.Output)
    FilePutObject(1, myResponse.GetResponseStream)
    myResponse.Close()
    End Sub


    Du musst jetzt nur noch deine PHP-Datei umändern:
    1. Prüfen, ob eine neue Version vorliegt.
    2. Wenn ja, dann folgendes machen:
    $datei= zu übertragene Datei
    $fp = fopen($datei, "rb");
    echo fread($fp, filesize($datei));
    fclose($fp);
    Damit wird die Datei übertragen ...

    Zu den Variablen des Vb-Codes:
    emaggOexeRequest ist eine Anfragen, das ist so, als wenn du in deinen Inetexplorrer eine Adresse eintippst und Enter drückst
    myResponse ist dann halt das Ergebiniss

    Rest kommt ja von dir. Mein Code hat die anderen Variablen gebraucht, um alles in einen String umzuwandeln ...

    Ich hoffe dir geholfen zu haben,
    Jue ;)

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

    Jetzt hab ich alles gepeilt. Ich versuche zunächst, einen Updater zu erstellen, der auch aktualisiert, wenn es noch gar keine neue version gibt. Dazu hab ich halt einfach die emaggO.exe auf den Server geladen. :D

    <pre>
    ' Globale Variablen/Objekte
    Dim emaggOpath As String = "emaggO.exe"
    ' #########################

    Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    ' Prüfen, ob emaggO.exe in gleichem Verzeichnis
    If Not System.IO.File.Exists("emaggO.exe") Then
    MsgBox("emaggO.exe konnte nicht gefunden werden! Updater wird beendet!", 48, "Fehler")
    End
    End If
    End Sub

    Private Sub UpdateemaggO()
    ' Es wird immer aktualisiert, egal welche Version vorliegt
    StatusBar.Text = "Aktualisiere..."
    Try
    cbUpdate.Enabled = False ' Zweites Updaten verhindern

    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.bmaker.net/BM SoftWare/emaggO/emaggO.exe")
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse()

    ' Neue schreiben
    FileOpen(1, emaggOpath, OpenMode.Output, OpenAccess.Write, OpenShare.LockReadWrite)
    Print(1, myResponse.GetResponseStream)
    myResponse.Close()

    StatusBar.Text = "Bereit"
    Catch exc As Exception
    MsgBox(exc.Message, 16, "Fehler")
    StatusBar.Text = "Fehler!"
    End Try
    End Sub

    Private Sub cbUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbUpdate.Click
    ' Zuständige Sub aufrufen
    UpdateemaggO()
    End Sub

    </pre>

    Das funzt aber nicht so ganz, weil er bei FilePutObject bzw. FilePut meckert 'Fehlerhafter Dateimodus' und wenn ich Print verwende meckert er auch.
    Vor ner ganzen Weile hab ich ma was mit StreamWriter hingekriegt, aber ich hab keine Lust, diesen ganzen Mist nochmal zu machen.
    Das muss doch auch anders gehen! X(

    <font color="red"> Edit by Agent: Ist zu einem VB.net Thema geworden -> Verschoben </font>

    Edit by BattleMaker: Wie konvertiere ich einen Stream in einen String, damit ich diesen dann durchsuchen kann?

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

    Ich hab dein Programm mal 'n bisschen umgebaut:


    Sub UpdateemaggO() \'deine Sub die du zum Updaten benutzt
    Try
    \'Was vor dem Updatedownload zutun ist

    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.bmaker.net/BM SoftWare/emaggO/emaggO.exe") \'Request erstellen
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse() \'Respons speichern
    Dim myStream As Stream = myResponse.GetResponseStream() \'Datenstream aus dem Respons extrahieren
    Dim myReader As New BinaryReader(myStream) \'Binärer "leser" zum Lesen des Streams

    \'Datei speichern
    Dim myFile As New FileStream(emaggOpath,FileMode.Create) \'Datei auswählen

    Dim i As Long
    For i=1 To myResponse.ContentLength \'Byte für Byte in die Datei übertragen
    myFile.writeByte(myReader.ReadByte())
    Next i

    myFile.flush() \'noch mal spülen ...
    myFile.close()\' und schließen

    \'Was nach dem Updatedownload zutun ist
    Catch exc As Exception
    \'Fehlerbehandlung
    End Try
    End Sub


    Ich hoffe es funzt,
    Jue ;)

    Edit: Hab dein Edit grad eben erst gesehen. Das mit dem Stream in String umzuwandeln ist nicht all zu schwer. Ich hab das überigens bei meinem 1. Post verwendet. Folgender Ausschnitt ist für die Umwandlung zuständig:


    Dim myData(myResponse.ContentLength) As Byte
    myStream.Read(myData,1,myResponse.ContentLength)
    Dim myEncoding As Encoding=Encoding.ascii
    Console.write(myEncoding.GetString(myData))

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

    <pre>
    ' Stream von myResponse in String umwandeln
    Dim dataString As String
    Dim myData(myResponse.ContentLength) As Byte
    <font color="orangered">
    myResponse.GetResponseStream.Read(myData, 1, myResponse.ContentLength)[/COLOR] </font> Dim myEncoding As System.Text.Encoding = System.Text.Encoding.ASCII
    dataString = myEncoding.GetString(myData)</pre>

    Soweit so gut - ich habe nur noch ein Problem (naja, was heißt 'nur'? ?( ).
    Bei dem Befehl 'myResponse.GetResponseStream.Read(myData, 1, myResponse.ContentLength)' tritt ein Fehler auf - der Parameter 'offset' (die '1') soll außerhalb des gültigen Wertebereichs sein.

    Ich probier dann mal weiter. :))

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

    Ja, ich weiß, dass war etwas voreilig, den Code einfach nur zu kopieren. :D Er funktioniert nur in einem speziellen Fall, und zwar im Zusammenhang mit einem Netzwerkstream.

    Was für einen Stream hast du denn?

    Jue ;)


    Edit:
    Jetzt kapier ich den ganzen Eintrag ... (wer lesen kann ist klar im Vorteil :D ) ich setz mich gleich dran und versuch den fehler zu finden! Versprochen!


    Edit2:
    Bei mir funzt es problemlos. Ich hab folgenden Code verwendet:

    Imports System
    Imports System.Net
    Imports System.IO
    Imports System.Text

    Module Main
    Sub main() \'deine Sub die du zum Updaten benutzt
    Try
    \'Was vor dem Updatedownload zutun ist

    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.vb-paradise.de") \'Request erstellen
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse() \'Respons speichern
    \' Stream von myResponse in String umwandeln
    Dim dataString As String
    Dim myData(myResponse.ContentLength) As Byte

    myResponse.GetResponseStream.Read(myData, 1, myResponse.ContentLength)
    Dim myEncoding As System.Text.Encoding = System.Text.Encoding.ASCII
    dataString = myEncoding.GetString(myData)

    \'Hab ich eingebaut, um das Resultat zu überprüfen
    console.write (dataString)
    \'Was nach dem Updatedownload zutun ist
    Catch exc As Exception
    \'Fehlerbehandlung
    End Try
    End Sub
    End Module


    Kann es vllt. sein, dass die Datei zu groß ist???

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

    OK Leute, Jue hat mir per ICQ nochmals einen ordentlichen Code gegeben, der auch problemlos funktioniert.

    Für alle .NET-Programmierer, die das Leben ihrer User versüßen wollen, poste ich den Code an dieser Stelle:

    <pre>
    Try
    'Was vor dem Updatedownload zutun ist

    Dim emaggOexeRequest As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.bmaker.net/BM SoftWare/emaggO/emaggO.exe") 'Request erstellen
    Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse() 'Respons speichern
    Dim myStream As System.IO.Stream = myResponse.GetResponseStream() 'Datenstream aus dem Respons extrahieren
    Dim myReader As New System.IO.BinaryReader(myStream) 'Binärer "leser" zum Lesen des Streams

    'Datei speichern
    Dim myFile As New System.IO.FileStream(emaggOpath, System.IO.FileMode.Create) 'Datei auswählen

    Dim i As Long
    For i = 1 To myResponse.ContentLength 'Byte für Byte in die Datei übertragen
    myFile.writeByte(myReader.ReadByte())
    Next i

    myFile.flush() 'noch mal spülen ...
    myFile.close() ' und schließen

    'Was nach dem Updatedownload zutun ist
    Catch exc As Exception
    'Fehlerbehandlung
    End Try
    </pre>

    DANKE JUE! :D

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

    Öhm... wenn dus ohne .net aber mit INET-Control machen willst, schau mal auf "Binär (Datei)-Download" das is für alle wichtig, die nich .NET benutzen tun bzw. benutzen wollen...

    Wenn ich mal Zeit und Bock hab stell ich vielleicht mal meinen Updater online ;)
    Ich muss das Thema hier nochmals etwas aufwirbeln.

    Wie kann ich mein Programm davon abhalten, während dem Download nicht mehr zu reagieren. Threads?? Bitte keine Threads, hab ich noch nie mit gearbeitet.
    Es müsste doch irgendeine Prioritätseinstellung bei dem Response-Viech (sry) geben...
    Außerdem würde ich gerne die Größe der herunterzuladenden Datei anzeigen und den Fortschritt des Downloads.

    Danke im Voraus.


    MFG, BattleMaker
    kA wie das unter.Net geht aber unter 6.0 mit INET-Control ladet man immer einen Byte-Array (Buffer) hinunter, der dann abgespeichert wird. und man muss hald bei den schleifen DoEvents hinschreiben. Ich denk mal, dass es unter.net auch sowas wie DoEvents gibt.
    Hi BattleMaker!

    Ich gehe jetzt von den Code deines vorletzten geporteten Porting aus!

    Zu der Größe:
    Die Größe (in Bytes) ist ab der Zeile

    Quellcode

    1. Dim myResponse As System.Net.WebResponse = emaggOexeRequest.GetResponse()

    verfügbar. Sie ist unter "myResponse.ContentLength" abrufbar.
    Der Fortschirtt lässt sich in der For-Schleife des Codes bei jedem Durchlauf mit folgender Zeile, die du irgentwo in die For-Schleife baust, errechnen:

    Quellcode

    1. Progress=i/myResponse.ContentLength*100

    Die Variable "Progress" enthält jetzt den Fortschritt in Prozent! Vergiss nicht die Variable "Progress" vor der For-Schleife mit Dim zu deklarieren!

    Zum Hängen:
    Um Threads kommts du nicht rum!!! Aber es ist nicht so schlimm wie du denkst! Ersteinmal musst du Threading importieren:

    Quellcode

    1. Imports System.Threading

    dann musst du an der Stelle, an der du die Sub zum Downloaden aufrufst was ändern:
    Momentan sieht's so (oder ähnlich) aus:

    Quellcode

    1. Call UPDATEemaggo()


    Das musst du mit folgendem ersetzen:

    Quellcode

    1. Dim myThread As New Thread(AddressOf UPDATEemaggo) 'Neuen Thread erstellen (der Thread ruft automatisch die UPDATEemaggo-Sub auf und beendet sich selbst, wenn die UPDATEemaggo-Sub durchgelaufen ist)
    2. myThread.start() 'Thread starten


    Schon fertig! War's wirklich so schlimm? ;)
    Wenn du einen Abbrechen-Button bauen willst sag einfach bescheid!

    Ich hoffe es klapt, ist alles nicht getestet! Sonst einfach noch mal melden!

    Jue ;)

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

    Dim myThread As New System.Threading.Thread(AddressOf DownloadFileByURI) 'Neuen Thread erstellen (der Thread ruft automatisch die UPDATEemaggo-Sub auf und beendet sich selbst, wenn die UPDATEemaggo-Sub durchgelaufen ist)
    myThread.start() 'Thread starten

    Funzt natürlich nicht. Bei mir funzt ja nie was auf Anhieb... *heul* *kreisch*

    Ich hab mir das Threading auch schon mal angeschaut und bin sogar noch weiter gegangen als du hier, aber es funzte trotzdem noch nicht.
    Die Fehlermeldung bei diesem Beispiel hier ist, dass die Prozedur hinter 'AdressOf' nicht die gleiche Signatur habe, wie Delegat (oder so) von Thread.start()

    Ich hab es schon mit mehreren Prozeduren ausprobiert, aber es wollte einfach nicht so funzen, wie ich mir das vorgestellt habe (!).


    MFG, BattleMaker
    Ich denk mal, es liegt an der Sub selbst! Ein paar kleine Fragen:
    Befinden sich DownloadFileByURI und die Sub, die den Thread startet in dem gleichen Modul/Klasse?
    Befinden sie sich einem Modul oder Klasse?
    Wie heißt das Modul/die Klasse?
    Werden Variablen bei der DownloadFileByURI-Sub übergeben? Sprich die Sub sieht so oder so ähnlich aus:

    Quellcode

    1. Private Sub DownloadFileByURI(file As String, url As String)


    Es wäre gut, wenn du uns deinen Code mal offenbaren könntest oder ihn mir per PN/E-Mail/ICQ zu senden könntest, damit ich mal drüber schauen kann.

    Jue ;)
    Ich offenbare den Code gerne, denn er ist für den einen oder anderen sicher recht nützlich.
    1. Alle Subs sind in der selben Klasse ('Main').
    2.Wie unten zu sehen ist, werden tatsächlich Variablen übergeben und diese Argumente vertragen sich nicht mit diesem 'Delegat'-Schrott.


    Quellcode

    1. Public Sub DownloadFileByURI(ByVal link As String, ByVal ziel As String)
    2. ' Was vor dem Updatedownload zutun ist
    3. Dim FileRequest As System.Net.WebRequest = System.Net.WebRequest.Create(link) ' Request erstellen
    4. Dim FileResponse As System.Net.WebResponse = FileRequest.GetResponse() ' Response speichern
    5. Dim myStream As System.IO.Stream = FileResponse.GetResponseStream() ' Datenstream aus dem Respons extrahieren
    6. Dim myReader As New System.IO.BinaryReader(myStream) ' Binärer "leser" zum Lesen des Streams
    7. ' Datei speichern
    8. Dim myFile As New System.IO.FileStream(ziel, System.IO.FileMode.Create) ' Datei auswählen
    9. Dim i As Long
    10. For i = 1 To FileResponse.ContentLength ' Byte für Byte in die Datei übertragen
    11. myFile.WriteByte(myReader.ReadByte())
    12. Next i
    13. myFile.Flush() ' noch mal spülen...
    14. myFile.Close() ' und schließen
    15. ' Was nach dem Updatedownload zutun ist
    16. End Sub



    MFG, BattleMaker

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

    jup, das mit den übergeben von variablen ist wirklich nicht sehr angebracht ... in zusammenhang mit threads.
    ich hätt jetzt eine relativ unschöne lösung für dich:

    "Neuer" Code:

    Quellcode

    1. Private link As String
    2. Private ziel As String
    3. Public Sub DownloadFileByURI()
    4. ' Was vor dem Updatedownload zutun ist
    5. Dim FileRequest As System.Net.WebRequest = System.Net.WebRequest.Create(link) ' Request erstellen
    6. Dim FileResponse As System.Net.WebResponse = FileRequest.GetResponse() ' Response speichern
    7. Dim myStream As System.IO.Stream = FileResponse.GetResponseStream() ' Datenstream aus dem Respons extrahieren
    8. Dim myReader As New System.IO.BinaryReader(myStream) ' Binärer "leser" zum Lesen des Streams
    9. ' Datei speichern
    10. Dim myFile As New System.IO.FileStream(ziel, System.IO.FileMode.Create) ' Datei auswählen
    11. Dim i As Long
    12. For i = 1 To FileResponse.ContentLength ' Byte für Byte in die Datei übertragen
    13. myFile.WriteByte(myReader.ReadByte())
    14. Next i
    15. myFile.Flush() ' noch mal spülen...
    16. myFile.Close() ' und schließen
    17. ' Was nach nach dem Updatedownload zutun ist
    18. End Sub


    Um dann den Download in gang zu bringen:

    Quellcode

    1. ...
    2. link="der link"
    3. ziel="das ziel"
    4. Dim myThread As New Thread(AddressOf Main.DownloadFileByURI) 'Neuen Thread erstellen
    5. myThread.start() 'Thread starten
    6. ...



    Probier das mal ... viel Erfolg
    Jue ;)