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
26 static inline BackgroundCopyFileImpl
*impl_from_IBackgroundCopyFile(IBackgroundCopyFile
*iface
)
28 return CONTAINING_RECORD(iface
, BackgroundCopyFileImpl
, IBackgroundCopyFile_iface
);
31 static HRESULT WINAPI
BITS_IBackgroundCopyFile_QueryInterface(
32 IBackgroundCopyFile
* iface
,
36 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
38 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
40 if (IsEqualGUID(riid
, &IID_IUnknown
)
41 || IsEqualGUID(riid
, &IID_IBackgroundCopyFile
))
44 IBackgroundCopyFile_AddRef(iface
);
52 static ULONG WINAPI
BITS_IBackgroundCopyFile_AddRef(IBackgroundCopyFile
* iface
)
54 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
55 ULONG ref
= InterlockedIncrement(&This
->ref
);
56 TRACE("(%p)->(%d)\n", This
, ref
);
60 static ULONG WINAPI
BITS_IBackgroundCopyFile_Release(
61 IBackgroundCopyFile
* iface
)
63 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
64 ULONG ref
= InterlockedDecrement(&This
->ref
);
66 TRACE("(%p)->(%d)\n", This
, ref
);
70 IBackgroundCopyJob2_Release(&This
->owner
->IBackgroundCopyJob2_iface
);
71 HeapFree(GetProcessHeap(), 0, This
->info
.LocalName
);
72 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
73 HeapFree(GetProcessHeap(), 0, This
);
79 /* Get the remote name of a background copy file */
80 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetRemoteName(
81 IBackgroundCopyFile
* iface
,
84 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
85 int n
= (lstrlenW(This
->info
.RemoteName
) + 1) * sizeof(WCHAR
);
87 *pVal
= CoTaskMemAlloc(n
);
91 memcpy(*pVal
, This
->info
.RemoteName
, n
);
95 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetLocalName(
96 IBackgroundCopyFile
* iface
,
99 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
100 int n
= (lstrlenW(This
->info
.LocalName
) + 1) * sizeof(WCHAR
);
102 *pVal
= CoTaskMemAlloc(n
);
104 return E_OUTOFMEMORY
;
106 memcpy(*pVal
, This
->info
.LocalName
, n
);
110 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetProgress(
111 IBackgroundCopyFile
* iface
,
112 BG_FILE_PROGRESS
*pVal
)
114 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
116 EnterCriticalSection(&This
->owner
->cs
);
117 pVal
->BytesTotal
= This
->fileProgress
.BytesTotal
;
118 pVal
->BytesTransferred
= This
->fileProgress
.BytesTransferred
;
119 pVal
->Completed
= This
->fileProgress
.Completed
;
120 LeaveCriticalSection(&This
->owner
->cs
);
125 static const IBackgroundCopyFileVtbl BITS_IBackgroundCopyFile_Vtbl
=
127 BITS_IBackgroundCopyFile_QueryInterface
,
128 BITS_IBackgroundCopyFile_AddRef
,
129 BITS_IBackgroundCopyFile_Release
,
130 BITS_IBackgroundCopyFile_GetRemoteName
,
131 BITS_IBackgroundCopyFile_GetLocalName
,
132 BITS_IBackgroundCopyFile_GetProgress
135 HRESULT
BackgroundCopyFileConstructor(BackgroundCopyJobImpl
*owner
,
136 LPCWSTR remoteName
, LPCWSTR localName
,
137 BackgroundCopyFileImpl
**file
)
139 BackgroundCopyFileImpl
*This
;
142 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName
), debugstr_w(localName
), file
);
144 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
146 return E_OUTOFMEMORY
;
148 n
= (lstrlenW(remoteName
) + 1) * sizeof(WCHAR
);
149 This
->info
.RemoteName
= HeapAlloc(GetProcessHeap(), 0, n
);
150 if (!This
->info
.RemoteName
)
152 HeapFree(GetProcessHeap(), 0, This
);
153 return E_OUTOFMEMORY
;
155 memcpy(This
->info
.RemoteName
, remoteName
, n
);
157 n
= (lstrlenW(localName
) + 1) * sizeof(WCHAR
);
158 This
->info
.LocalName
= HeapAlloc(GetProcessHeap(), 0, n
);
159 if (!This
->info
.LocalName
)
161 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
162 HeapFree(GetProcessHeap(), 0, This
);
163 return E_OUTOFMEMORY
;
165 memcpy(This
->info
.LocalName
, localName
, n
);
167 This
->IBackgroundCopyFile_iface
.lpVtbl
= &BITS_IBackgroundCopyFile_Vtbl
;
170 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
171 This
->fileProgress
.BytesTransferred
= 0;
172 This
->fileProgress
.Completed
= FALSE
;
174 IBackgroundCopyJob2_AddRef(&owner
->IBackgroundCopyJob2_iface
);
180 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
181 LARGE_INTEGER totalTransferred
,
182 LARGE_INTEGER streamSize
,
183 LARGE_INTEGER streamTransferred
,
190 BackgroundCopyFileImpl
*file
= obj
;
191 BackgroundCopyJobImpl
*job
= file
->owner
;
194 EnterCriticalSection(&job
->cs
);
195 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
196 ? totalTransferred
.QuadPart
197 : totalTransferred
.QuadPart
- file
->fileProgress
.BytesTransferred
);
198 file
->fileProgress
.BytesTotal
= totalSize
.QuadPart
;
199 file
->fileProgress
.BytesTransferred
= totalTransferred
.QuadPart
;
200 job
->jobProgress
.BytesTransferred
+= diff
;
201 LeaveCriticalSection(&job
->cs
);
203 return (job
->state
== BG_JOB_STATE_TRANSFERRING
210 IBindStatusCallback IBindStatusCallback_iface
;
211 BackgroundCopyFileImpl
*file
;
213 } DLBindStatusCallback
;
215 static inline DLBindStatusCallback
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
217 return CONTAINING_RECORD(iface
, DLBindStatusCallback
, IBindStatusCallback_iface
);
220 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
222 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
223 return InterlockedIncrement(&This
->ref
);
226 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
228 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
229 ULONG ref
= InterlockedDecrement(&This
->ref
);
233 IBackgroundCopyFile_Release(&This
->file
->IBackgroundCopyFile_iface
);
234 HeapFree(GetProcessHeap(), 0, This
);
240 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
241 IBindStatusCallback
*iface
,
245 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
247 if (IsEqualGUID(riid
, &IID_IUnknown
)
248 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
250 *ppvObject
= &This
->IBindStatusCallback_iface
;
251 DLBindStatusCallback_AddRef(iface
);
256 return E_NOINTERFACE
;
259 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
260 IBindStatusCallback
*iface
,
267 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
268 IBindStatusCallback
*iface
,
274 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
275 IBindStatusCallback
*iface
,
278 FORMATETC
*pformatetc
,
284 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
285 IBindStatusCallback
*iface
,
291 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
292 IBindStatusCallback
*iface
,
299 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
300 IBindStatusCallback
*iface
,
306 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
307 BackgroundCopyFileImpl
*file
= This
->file
;
308 BackgroundCopyJobImpl
*job
= file
->owner
;
311 EnterCriticalSection(&job
->cs
);
312 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
314 : progress
- file
->fileProgress
.BytesTransferred
);
315 file
->fileProgress
.BytesTotal
= progressMax
? progressMax
: BG_SIZE_UNKNOWN
;
316 file
->fileProgress
.BytesTransferred
= progress
;
317 job
->jobProgress
.BytesTransferred
+= diff
;
318 LeaveCriticalSection(&job
->cs
);
323 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
324 IBindStatusCallback
*iface
,
331 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
332 IBindStatusCallback
*iface
,
339 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl
=
341 DLBindStatusCallback_QueryInterface
,
342 DLBindStatusCallback_AddRef
,
343 DLBindStatusCallback_Release
,
344 DLBindStatusCallback_OnStartBinding
,
345 DLBindStatusCallback_GetPriority
,
346 DLBindStatusCallback_OnLowResource
,
347 DLBindStatusCallback_OnProgress
,
348 DLBindStatusCallback_OnStopBinding
,
349 DLBindStatusCallback_GetBindInfo
,
350 DLBindStatusCallback_OnDataAvailable
,
351 DLBindStatusCallback_OnObjectAvailable
354 static DLBindStatusCallback
*DLBindStatusCallbackConstructor(
355 BackgroundCopyFileImpl
*file
)
357 DLBindStatusCallback
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
361 This
->IBindStatusCallback_iface
.lpVtbl
= &DLBindStatusCallback_Vtbl
;
362 IBackgroundCopyFile_AddRef(&file
->IBackgroundCopyFile_iface
);
368 BOOL
processFile(BackgroundCopyFileImpl
*file
, BackgroundCopyJobImpl
*job
)
370 static const WCHAR prefix
[] = {'B','I','T', 0};
371 DLBindStatusCallback
*callbackObj
;
372 WCHAR tmpDir
[MAX_PATH
];
373 WCHAR tmpName
[MAX_PATH
];
376 if (!GetTempPathW(MAX_PATH
, tmpDir
))
378 ERR("Couldn't create temp file name: %d\n", GetLastError());
379 /* Guessing on what state this should give us */
380 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
384 if (!GetTempFileNameW(tmpDir
, prefix
, 0, tmpName
))
386 ERR("Couldn't create temp file: %d\n", GetLastError());
387 /* Guessing on what state this should give us */
388 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
392 callbackObj
= DLBindStatusCallbackConstructor(file
);
395 ERR("Out of memory\n");
396 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
400 EnterCriticalSection(&job
->cs
);
401 file
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
402 file
->fileProgress
.BytesTransferred
= 0;
403 file
->fileProgress
.Completed
= FALSE
;
404 LeaveCriticalSection(&job
->cs
);
406 TRACE("Transferring: %s -> %s -> %s\n",
407 debugstr_w(file
->info
.RemoteName
),
409 debugstr_w(file
->info
.LocalName
));
411 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSFERRING
);
413 DeleteUrlCacheEntryW(file
->info
.RemoteName
);
414 hr
= URLDownloadToFileW(NULL
, file
->info
.RemoteName
, tmpName
, 0,
415 &callbackObj
->IBindStatusCallback_iface
);
416 IBindStatusCallback_Release(&callbackObj
->IBindStatusCallback_iface
);
417 if (hr
== INET_E_DOWNLOAD_FAILURE
)
419 TRACE("URLDownload failed, trying local file copy\n");
420 if (!CopyFileExW(file
->info
.RemoteName
, tmpName
, copyProgressCallback
,
423 ERR("Local file copy failed: error %d\n", GetLastError());
424 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
430 ERR("URLDownload failed: eh 0x%08x\n", hr
);
431 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
435 if (transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_QUEUED
))
437 lstrcpyW(file
->tempFileName
, tmpName
);
439 EnterCriticalSection(&job
->cs
);
440 file
->fileProgress
.Completed
= TRUE
;
441 job
->jobProgress
.FilesTransferred
++;
442 LeaveCriticalSection(&job
->cs
);
448 DeleteFileW(tmpName
);