Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

BurningWave

Alter Hase

  • »BurningWave« ist der Autor dieses Themas

Beiträge: 1 106

Wohnort: Filderstadt/Konstanz

Beruf: Student

  • Private Nachricht senden

1

23.01.2011, 21:11

Windows Forms - Datei downloaden - Erledigt

Hallo Welt,

ich bin gerade dabei, einen Updater für meine Programme zu schreiben, der wenn Updates für ein Programm verfügbar sind, diese herunterlädt und die alten Dateien mit den Heruntergeladenen automatisch überschreibt. Versionsnummern können schon überprüft werden und ein Downloadlink kann der Updater auch schon vom Server anfordern. Dateien möchte ich mit der Funktion URLDownloadToFile() (aus urlmon.h) downloaden. Das klappt im Großen und Ganzen schon. Aber folgende Probleme treten auf:
1. Wie kann ich die IBindStatusCallback Klasse korrekt überladen, um den Fortschritt des Downloads geliefert zu bekommen (irgendwie funktioniert es nicht so, wie ich es aus C++ gewöhnt bin)?
2. Wie kann ich den Download abbrechen?
3. Wie kann ich die Funktion anweisen, die Daten neu herunterzuladen und nicht aus dem Cache zu holen?

Ich habe schon Ewigkeiten im Internet nach Lösungen gesucht, aber nicht wirklich was gefunden, was in dem ekelhaften C++/CLI-.NET-Gemisch funktioniert. Hier sind mal Ausschnitte aus meinem Code, ich hoffe ihr könnt mir helfen.

Die Überladung der IBindStatusCallback-Klasse (aus dem Internet):

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class BindStatusCallback : public IBindStatusCallback 
{
public:
BindStatusCallback() {}

~BindStatusCallback() { }

// This one is called by URLDownloadToFile
STDMETHOD(OnProgress)(/* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR wszStatusText)
{
    Progress = ulProgress; //ulProgress und ulProgressMax sind fast immer 0?!
    ProgressMax = ulProgressMax;

    if(bCancel)
        return E_ABORT; //bewirkt kein Abbrechen??
    else
        return S_OK;
}

// The rest don't do anything...
STDMETHOD(OnStartBinding)(/* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR *pib)
{ return E_NOTIMPL; }

STDMETHOD(GetPriority)(/* [out] */ LONG __RPC_FAR *pnPriority)
{ return E_NOTIMPL; }

STDMETHOD(OnLowResource)(/* [in] */ DWORD reserved)
{ return E_NOTIMPL; }

STDMETHOD(OnStopBinding)(/* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError)
{ return E_NOTIMPL; }

STDMETHOD(GetBindInfo)(/* [out] */ DWORD __RPC_FAR *grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo)
{
    *grfBINDF = BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE; //Datei wird trotzdem aus dem Cache geladen...
    return S_OK;
}

STDMETHOD(OnDataAvailable)(/* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ STGMEDIUM __RPC_FAR *pstgmed)
{ return E_NOTIMPL; }

STDMETHOD(OnObjectAvailable)(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk)
{ return E_NOTIMPL; }

// IUnknown stuff
STDMETHOD_(ULONG,AddRef)()
{ return 0; }

STDMETHOD_(ULONG,Release)()
{ return 0; }

STDMETHOD(QueryInterface)(/* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{ return E_NOTIMPL; }
};


Der Aufruf von URLDownloadToFile():

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
    char wintemp_path[MAX_PATH];
    GetTempPath(MAX_PATH, wintemp_path);
    DeleteFile((string(wintemp_path) + "jbupdaterdownloaded.zip").c_str());

    BindStatusCallback BindStatus;
    DeleteUrlCacheEntry(sUpdateURL.c_str());
    if(URLDownloadToFile(NULL, sUpdateURL.c_str(), (string(wintemp_path) + "jbupdaterdownloaded.zip").c_str(), 0, &BindStatus) != S_OK)
    {
        Invoke(gcnew InvokeDelegate(this, &jbupdater::MainForm::DownloadUpdateFailure));
        return;
    }
    Invoke(gcnew InvokeDelegate(this, &jbupdater::MainForm::DownloadUpdateComplete));


Um mein Problem noch genauer zu erklären: URLDownloadToFile() wird aus einem 2. Thread heraus gestartet, so dass das Programm während dem Download noch reagiert. Wenn ich das Programm nun mit Environment::Exit(0); beende, während der Download läuft (und davor noch bCancel auf true setze), tritt immer eine Exception auf (bei URLDownloadToFile()). Wenn ich hingegen mit Application::Exit() beende, scheint es, als ob das Hauptprogramm beendet wird, aber der Download trotzdem weiterläuft. Außerdem bekomme ich in der BindStatusCallback::OnProgress()-Methode keine brauchbaren Werte geliefert, sondern meistens nur 0. Mir ist absolut unklar, warum die Datei aus dem Cache geladen wird, obwohl ich ihn mit DeleteUrlCacheEntry() lösche.

Danke im Voraus
BurningWave

EDIT1: Den Downloadstatus bekomme ich jetzt. Dass ich nur Nullen geliefert bekam, lag an einem dummen Rundungsfehler.
EDIT2: Nachdem ich den halben Code neu geschrieben habe, funktioniert jetzt alles, bis auf das Problem, dass der Cache nicht gelöscht wird.

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »BurningWave« (24.01.2011, 21:09)