qmgr: Update to IBackgroundCopyFile2.
[wine.git] / dlls / qmgr / file.c
blob4399e7748de62cfa33e3c86ca79fea1916edbef3
1 /*
2 * Queue Manager (BITS) File
4 * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "wininet.h"
28 #define COBJMACROS
29 #include "urlmon.h"
30 #include "qmgr.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
35 static inline BackgroundCopyFileImpl *impl_from_IBackgroundCopyFile2(
36 IBackgroundCopyFile2 *iface)
38 return CONTAINING_RECORD(iface, BackgroundCopyFileImpl, IBackgroundCopyFile2_iface);
41 static HRESULT WINAPI BackgroundCopyFile_QueryInterface(
42 IBackgroundCopyFile2 *iface,
43 REFIID riid,
44 void **obj)
46 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
48 TRACE("(%p)->(%s %p)\n", file, debugstr_guid(riid), obj);
50 if (IsEqualGUID(riid, &IID_IUnknown) ||
51 IsEqualGUID(riid, &IID_IBackgroundCopyFile) ||
52 IsEqualGUID(riid, &IID_IBackgroundCopyFile2))
54 *obj = iface;
56 else
58 *obj = NULL;
59 return E_NOINTERFACE;
62 IBackgroundCopyFile2_AddRef(iface);
63 return S_OK;
66 static ULONG WINAPI BackgroundCopyFile_AddRef(
67 IBackgroundCopyFile2 *iface)
69 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
70 ULONG ref = InterlockedIncrement(&file->ref);
71 TRACE("(%p)->(%d)\n", file, ref);
72 return ref;
75 static ULONG WINAPI BackgroundCopyFile_Release(
76 IBackgroundCopyFile2 *iface)
78 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
79 ULONG ref = InterlockedDecrement(&file->ref);
81 TRACE("(%p)->(%d)\n", file, ref);
83 if (ref == 0)
85 IBackgroundCopyJob2_Release(&file->owner->IBackgroundCopyJob2_iface);
86 HeapFree(GetProcessHeap(), 0, file->info.LocalName);
87 HeapFree(GetProcessHeap(), 0, file->info.RemoteName);
88 HeapFree(GetProcessHeap(), 0, file);
91 return ref;
94 /* Get the remote name of a background copy file */
95 static HRESULT WINAPI BackgroundCopyFile_GetRemoteName(
96 IBackgroundCopyFile2 *iface,
97 LPWSTR *pVal)
99 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
101 TRACE("(%p)->(%p)\n", file, pVal);
103 return return_strval(file->info.RemoteName, pVal);
106 static HRESULT WINAPI BackgroundCopyFile_GetLocalName(
107 IBackgroundCopyFile2 *iface,
108 LPWSTR *pVal)
110 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
112 TRACE("(%p)->(%p)\n", file, pVal);
114 return return_strval(file->info.LocalName, pVal);
117 static HRESULT WINAPI BackgroundCopyFile_GetProgress(
118 IBackgroundCopyFile2 *iface,
119 BG_FILE_PROGRESS *pVal)
121 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
123 TRACE("(%p)->(%p)\n", file, pVal);
125 EnterCriticalSection(&file->owner->cs);
126 pVal->BytesTotal = file->fileProgress.BytesTotal;
127 pVal->BytesTransferred = file->fileProgress.BytesTransferred;
128 pVal->Completed = file->fileProgress.Completed;
129 LeaveCriticalSection(&file->owner->cs);
131 return S_OK;
134 static HRESULT WINAPI BackgroundCopyFile_GetFileRanges(
135 IBackgroundCopyFile2 *iface,
136 DWORD *RangeCount,
137 BG_FILE_RANGE **Ranges)
139 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
140 FIXME("(%p)->(%p %p)\n", file, RangeCount, Ranges);
141 return E_NOTIMPL;
144 static HRESULT WINAPI BackgroundCopyFile_SetRemoteName(
145 IBackgroundCopyFile2 *iface,
146 LPCWSTR Val)
148 BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
149 FIXME("(%p)->(%s)\n", file, debugstr_w(Val));
150 return E_NOTIMPL;
153 static const IBackgroundCopyFile2Vtbl BackgroundCopyFile2Vtbl =
155 BackgroundCopyFile_QueryInterface,
156 BackgroundCopyFile_AddRef,
157 BackgroundCopyFile_Release,
158 BackgroundCopyFile_GetRemoteName,
159 BackgroundCopyFile_GetLocalName,
160 BackgroundCopyFile_GetProgress,
161 BackgroundCopyFile_GetFileRanges,
162 BackgroundCopyFile_SetRemoteName
165 HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
166 LPCWSTR remoteName, LPCWSTR localName,
167 BackgroundCopyFileImpl **file)
169 BackgroundCopyFileImpl *This;
170 int n;
172 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName), debugstr_w(localName), file);
174 This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
175 if (!This)
176 return E_OUTOFMEMORY;
178 n = (lstrlenW(remoteName) + 1) * sizeof(WCHAR);
179 This->info.RemoteName = HeapAlloc(GetProcessHeap(), 0, n);
180 if (!This->info.RemoteName)
182 HeapFree(GetProcessHeap(), 0, This);
183 return E_OUTOFMEMORY;
185 memcpy(This->info.RemoteName, remoteName, n);
187 n = (lstrlenW(localName) + 1) * sizeof(WCHAR);
188 This->info.LocalName = HeapAlloc(GetProcessHeap(), 0, n);
189 if (!This->info.LocalName)
191 HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
192 HeapFree(GetProcessHeap(), 0, This);
193 return E_OUTOFMEMORY;
195 memcpy(This->info.LocalName, localName, n);
197 This->IBackgroundCopyFile2_iface.lpVtbl = &BackgroundCopyFile2Vtbl;
198 This->ref = 1;
200 This->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
201 This->fileProgress.BytesTransferred = 0;
202 This->fileProgress.Completed = FALSE;
203 This->owner = owner;
204 IBackgroundCopyJob2_AddRef(&owner->IBackgroundCopyJob2_iface);
206 *file = This;
207 return S_OK;
210 static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize,
211 LARGE_INTEGER totalTransferred,
212 LARGE_INTEGER streamSize,
213 LARGE_INTEGER streamTransferred,
214 DWORD streamNum,
215 DWORD reason,
216 HANDLE srcFile,
217 HANDLE dstFile,
218 LPVOID obj)
220 BackgroundCopyFileImpl *file = obj;
221 BackgroundCopyJobImpl *job = file->owner;
222 ULONG64 diff;
224 EnterCriticalSection(&job->cs);
225 diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
226 ? totalTransferred.QuadPart
227 : totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
228 file->fileProgress.BytesTotal = totalSize.QuadPart;
229 file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
230 job->jobProgress.BytesTransferred += diff;
231 LeaveCriticalSection(&job->cs);
233 return (job->state == BG_JOB_STATE_TRANSFERRING
234 ? PROGRESS_CONTINUE
235 : PROGRESS_CANCEL);
238 typedef struct
240 IBindStatusCallback IBindStatusCallback_iface;
241 BackgroundCopyFileImpl *file;
242 LONG ref;
243 } DLBindStatusCallback;
245 static inline DLBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
247 return CONTAINING_RECORD(iface, DLBindStatusCallback, IBindStatusCallback_iface);
250 static HRESULT WINAPI DLBindStatusCallback_QueryInterface(
251 IBindStatusCallback *iface,
252 REFIID riid,
253 void **ppvObject)
255 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
257 if (IsEqualGUID(riid, &IID_IUnknown)
258 || IsEqualGUID(riid, &IID_IBindStatusCallback))
260 *ppvObject = &This->IBindStatusCallback_iface;
261 IBindStatusCallback_AddRef(iface);
262 return S_OK;
265 *ppvObject = NULL;
266 return E_NOINTERFACE;
269 static ULONG WINAPI DLBindStatusCallback_AddRef(IBindStatusCallback *iface)
271 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
272 return InterlockedIncrement(&This->ref);
275 static ULONG WINAPI DLBindStatusCallback_Release(IBindStatusCallback *iface)
277 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
278 ULONG ref = InterlockedDecrement(&This->ref);
280 if (ref == 0)
282 IBackgroundCopyFile2_Release(&This->file->IBackgroundCopyFile2_iface);
283 HeapFree(GetProcessHeap(), 0, This);
286 return ref;
289 static HRESULT WINAPI DLBindStatusCallback_GetBindInfo(
290 IBindStatusCallback *iface,
291 DWORD *grfBINDF,
292 BINDINFO *pbindinfo)
294 return E_NOTIMPL;
297 static HRESULT WINAPI DLBindStatusCallback_GetPriority(
298 IBindStatusCallback *iface,
299 LONG *pnPriority)
301 return E_NOTIMPL;
304 static HRESULT WINAPI DLBindStatusCallback_OnDataAvailable(
305 IBindStatusCallback *iface,
306 DWORD grfBSCF,
307 DWORD dwSize,
308 FORMATETC *pformatetc,
309 STGMEDIUM *pstgmed)
311 return E_NOTIMPL;
314 static HRESULT WINAPI DLBindStatusCallback_OnLowResource(
315 IBindStatusCallback *iface,
316 DWORD reserved)
318 return E_NOTIMPL;
321 static HRESULT WINAPI DLBindStatusCallback_OnObjectAvailable(
322 IBindStatusCallback *iface,
323 REFIID riid,
324 IUnknown *punk)
326 return E_NOTIMPL;
329 static HRESULT WINAPI DLBindStatusCallback_OnProgress(
330 IBindStatusCallback *iface,
331 ULONG progress,
332 ULONG progressMax,
333 ULONG statusCode,
334 LPCWSTR statusText)
336 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
337 BackgroundCopyFileImpl *file = This->file;
338 BackgroundCopyJobImpl *job = file->owner;
339 ULONG64 diff;
341 EnterCriticalSection(&job->cs);
342 diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
343 ? progress
344 : progress - file->fileProgress.BytesTransferred);
345 file->fileProgress.BytesTotal = progressMax ? progressMax : BG_SIZE_UNKNOWN;
346 file->fileProgress.BytesTransferred = progress;
347 job->jobProgress.BytesTransferred += diff;
348 LeaveCriticalSection(&job->cs);
350 return S_OK;
353 static HRESULT WINAPI DLBindStatusCallback_OnStartBinding(
354 IBindStatusCallback *iface,
355 DWORD dwReserved,
356 IBinding *pib)
358 return E_NOTIMPL;
361 static HRESULT WINAPI DLBindStatusCallback_OnStopBinding(
362 IBindStatusCallback *iface,
363 HRESULT hresult,
364 LPCWSTR szError)
366 return E_NOTIMPL;
369 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl =
371 DLBindStatusCallback_QueryInterface,
372 DLBindStatusCallback_AddRef,
373 DLBindStatusCallback_Release,
374 DLBindStatusCallback_OnStartBinding,
375 DLBindStatusCallback_GetPriority,
376 DLBindStatusCallback_OnLowResource,
377 DLBindStatusCallback_OnProgress,
378 DLBindStatusCallback_OnStopBinding,
379 DLBindStatusCallback_GetBindInfo,
380 DLBindStatusCallback_OnDataAvailable,
381 DLBindStatusCallback_OnObjectAvailable
384 static DLBindStatusCallback *DLBindStatusCallbackConstructor(
385 BackgroundCopyFileImpl *file)
387 DLBindStatusCallback *This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
388 if (!This)
389 return NULL;
391 This->IBindStatusCallback_iface.lpVtbl = &DLBindStatusCallback_Vtbl;
392 IBackgroundCopyFile2_AddRef(&file->IBackgroundCopyFile2_iface);
393 This->file = file;
394 This->ref = 1;
395 return This;
398 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
400 static const WCHAR prefix[] = {'B','I','T', 0};
401 DLBindStatusCallback *callbackObj;
402 WCHAR tmpDir[MAX_PATH];
403 WCHAR tmpName[MAX_PATH];
404 HRESULT hr;
406 if (!GetTempPathW(MAX_PATH, tmpDir))
408 ERR("Couldn't create temp file name: %d\n", GetLastError());
409 /* Guessing on what state this should give us */
410 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
411 return FALSE;
414 if (!GetTempFileNameW(tmpDir, prefix, 0, tmpName))
416 ERR("Couldn't create temp file: %d\n", GetLastError());
417 /* Guessing on what state this should give us */
418 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
419 return FALSE;
422 callbackObj = DLBindStatusCallbackConstructor(file);
423 if (!callbackObj)
425 ERR("Out of memory\n");
426 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
427 return FALSE;
430 EnterCriticalSection(&job->cs);
431 file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
432 file->fileProgress.BytesTransferred = 0;
433 file->fileProgress.Completed = FALSE;
434 LeaveCriticalSection(&job->cs);
436 TRACE("Transferring: %s -> %s -> %s\n",
437 debugstr_w(file->info.RemoteName),
438 debugstr_w(tmpName),
439 debugstr_w(file->info.LocalName));
441 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
443 DeleteUrlCacheEntryW(file->info.RemoteName);
444 hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0,
445 &callbackObj->IBindStatusCallback_iface);
446 IBindStatusCallback_Release(&callbackObj->IBindStatusCallback_iface);
447 if (hr == INET_E_DOWNLOAD_FAILURE)
449 TRACE("URLDownload failed, trying local file copy\n");
450 if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback,
451 file, NULL, 0))
453 ERR("Local file copy failed: error %d\n", GetLastError());
454 transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
455 return FALSE;
458 else if (FAILED(hr))
460 ERR("URLDownload failed: eh 0x%08x\n", hr);
461 transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
462 return FALSE;
465 if (transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED))
467 lstrcpyW(file->tempFileName, tmpName);
469 EnterCriticalSection(&job->cs);
470 file->fileProgress.Completed = TRUE;
471 job->jobProgress.FilesTransferred++;
472 LeaveCriticalSection(&job->cs);
474 return TRUE;
476 else
478 DeleteFileW(tmpName);
479 return FALSE;