[6/6] qmgr: Implement progress updates for downloads given by URL.
Dan Hipschman
dsh at linux.ucla.edu
Thu Mar 13 17:57:54 CDT 2008
This implements some file download progress updates when downloading from a
URL. In Wine, it doesn't update the total size of the file yet, but I think
this may be a problem with URLDownloadToFile. I haven't checked the behavior
of that function on Windows yet.
---
dlls/qmgr/file.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 170 insertions(+), 10 deletions(-)
diff --git a/dlls/qmgr/file.c b/dlls/qmgr/file.c
index fea84ec..84cd30c 100644
--- a/dlls/qmgr/file.c
+++ b/dlls/qmgr/file.c
@@ -20,6 +20,8 @@
#include <stdarg.h>
+#define COBJMACROS
+
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
@@ -209,9 +211,165 @@ static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize,
: PROGRESS_CANCEL);
}
+typedef struct
+{
+ const IBindStatusCallbackVtbl *lpVtbl;
+ BackgroundCopyFileImpl *file;
+ LONG ref;
+} DLBindStatusCallback;
+
+static ULONG WINAPI DLBindStatusCallback_AddRef(IBindStatusCallback *iface)
+{
+ DLBindStatusCallback *This = (DLBindStatusCallback *) iface;
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI DLBindStatusCallback_Release(IBindStatusCallback *iface)
+{
+ DLBindStatusCallback *This = (DLBindStatusCallback *) iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ if (ref == 0)
+ {
+ IBackgroundCopyFile_Release((IBackgroundCopyFile *) This->file);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_QueryInterface(
+ IBindStatusCallback *iface,
+ REFIID riid,
+ void **ppvObject)
+{
+ DLBindStatusCallback *This = (DLBindStatusCallback *) iface;
+
+ if (IsEqualGUID(riid, &IID_IUnknown)
+ || IsEqualGUID(riid, &IID_IBindStatusCallback))
+ {
+ *ppvObject = &This->lpVtbl;
+ DLBindStatusCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_GetBindInfo(
+ IBindStatusCallback *iface,
+ DWORD *grfBINDF,
+ BINDINFO *pbindinfo)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_GetPriority(
+ IBindStatusCallback *iface,
+ LONG *pnPriority)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnDataAvailable(
+ IBindStatusCallback *iface,
+ DWORD grfBSCF,
+ DWORD dwSize,
+ FORMATETC *pformatetc,
+ STGMEDIUM *pstgmed)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnLowResource(
+ IBindStatusCallback *iface,
+ DWORD reserved)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnObjectAvailable(
+ IBindStatusCallback *iface,
+ REFIID riid,
+ IUnknown *punk)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnProgress(
+ IBindStatusCallback *iface,
+ ULONG progress,
+ ULONG progressMax,
+ ULONG statusCode,
+ LPCWSTR statusText)
+{
+ DLBindStatusCallback *This = (DLBindStatusCallback *) iface;
+ BackgroundCopyFileImpl *file = This->file;
+ BackgroundCopyJobImpl *job = file->owner;
+ ULONG64 diff;
+
+ EnterCriticalSection(&job->cs);
+ diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
+ ? progress
+ : progress - file->fileProgress.BytesTransferred);
+ file->fileProgress.BytesTotal = progressMax ? progressMax : BG_SIZE_UNKNOWN;
+ file->fileProgress.BytesTransferred = progress;
+ job->jobProgress.BytesTransferred += diff;
+ LeaveCriticalSection(&job->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnStartBinding(
+ IBindStatusCallback *iface,
+ DWORD dwReserved,
+ IBinding *pib)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DLBindStatusCallback_OnStopBinding(
+ IBindStatusCallback *iface,
+ HRESULT hresult,
+ LPCWSTR szError)
+{
+ return E_NOTIMPL;
+}
+
+static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl =
+{
+ DLBindStatusCallback_QueryInterface,
+ DLBindStatusCallback_AddRef,
+ DLBindStatusCallback_Release,
+ DLBindStatusCallback_OnStartBinding,
+ DLBindStatusCallback_GetPriority,
+ DLBindStatusCallback_OnLowResource,
+ DLBindStatusCallback_OnProgress,
+ DLBindStatusCallback_OnStopBinding,
+ DLBindStatusCallback_GetBindInfo,
+ DLBindStatusCallback_OnDataAvailable,
+ DLBindStatusCallback_OnObjectAvailable
+};
+
+static DLBindStatusCallback *DLBindStatusCallbackConstructor(
+ BackgroundCopyFileImpl *file)
+{
+ DLBindStatusCallback *This = HeapAlloc(GetProcessHeap(), 0, sizeof This);
+ if (!This)
+ return NULL;
+
+ This->lpVtbl = &DLBindStatusCallback_Vtbl;
+ IBackgroundCopyFile_AddRef((IBackgroundCopyFile *) file);
+ This->file = file;
+ This->ref = 1;
+ return This;
+}
+
BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
{
static WCHAR prefix[] = {'B','I','T', 0};
+ IBindStatusCallback *callbackObj;
WCHAR tmpDir[MAX_PATH];
WCHAR tmpName[MAX_PATH];
HRESULT hr;
@@ -232,6 +390,14 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
return FALSE;
}
+ callbackObj = (IBindStatusCallback *) DLBindStatusCallbackConstructor(file);
+ if (!callbackObj)
+ {
+ ERR("Out of memory\n");
+ transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
+ return FALSE;
+ }
+
EnterCriticalSection(&job->cs);
file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
file->fileProgress.BytesTransferred = 0;
@@ -246,15 +412,9 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
DeleteUrlCacheEntryW(file->info.RemoteName);
- hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0, NULL);
- if (SUCCEEDED(hr))
- {
- FIXME("Do progress updates correctly with IBindStatusCallback\n");
- EnterCriticalSection(&job->cs);
- file->fileProgress.BytesTotal = 0;
- LeaveCriticalSection(&job->cs);
- }
- else if (hr == INET_E_DOWNLOAD_FAILURE)
+ hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0, callbackObj);
+ IBindStatusCallback_Release(callbackObj);
+ if (hr == INET_E_DOWNLOAD_FAILURE)
{
TRACE("URLDownload failed, trying local file copy\n");
if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback,
@@ -265,7 +425,7 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
return FALSE;
}
}
- else
+ else if (!SUCCEEDED(hr))
{
ERR("URLDownload failed: eh 0x%08x\n", hr);
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
More information about the wine-patches
mailing list