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
BackgroundCopyFile_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
BackgroundCopyFile_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
BackgroundCopyFile_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
BackgroundCopyFile_GetRemoteName(
81 IBackgroundCopyFile
* iface
,
84 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
86 TRACE("(%p)->(%p)\n", This
, pVal
);
88 return return_strval(This
->info
.RemoteName
, pVal
);
91 static HRESULT WINAPI
BackgroundCopyFile_GetLocalName(
92 IBackgroundCopyFile
* iface
,
95 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
97 TRACE("(%p)->(%p)\n", This
, pVal
);
99 return return_strval(This
->info
.LocalName
, pVal
);
102 static HRESULT WINAPI
BackgroundCopyFile_GetProgress(
103 IBackgroundCopyFile
* iface
,
104 BG_FILE_PROGRESS
*pVal
)
106 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
108 TRACE("(%p)->(%p)\n", This
, pVal
);
110 EnterCriticalSection(&This
->owner
->cs
);
111 pVal
->BytesTotal
= This
->fileProgress
.BytesTotal
;
112 pVal
->BytesTransferred
= This
->fileProgress
.BytesTransferred
;
113 pVal
->Completed
= This
->fileProgress
.Completed
;
114 LeaveCriticalSection(&This
->owner
->cs
);
119 static const IBackgroundCopyFileVtbl BackgroundCopyFileVtbl
=
121 BackgroundCopyFile_QueryInterface
,
122 BackgroundCopyFile_AddRef
,
123 BackgroundCopyFile_Release
,
124 BackgroundCopyFile_GetRemoteName
,
125 BackgroundCopyFile_GetLocalName
,
126 BackgroundCopyFile_GetProgress
129 HRESULT
BackgroundCopyFileConstructor(BackgroundCopyJobImpl
*owner
,
130 LPCWSTR remoteName
, LPCWSTR localName
,
131 BackgroundCopyFileImpl
**file
)
133 BackgroundCopyFileImpl
*This
;
136 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName
), debugstr_w(localName
), file
);
138 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
140 return E_OUTOFMEMORY
;
142 n
= (lstrlenW(remoteName
) + 1) * sizeof(WCHAR
);
143 This
->info
.RemoteName
= HeapAlloc(GetProcessHeap(), 0, n
);
144 if (!This
->info
.RemoteName
)
146 HeapFree(GetProcessHeap(), 0, This
);
147 return E_OUTOFMEMORY
;
149 memcpy(This
->info
.RemoteName
, remoteName
, n
);
151 n
= (lstrlenW(localName
) + 1) * sizeof(WCHAR
);
152 This
->info
.LocalName
= HeapAlloc(GetProcessHeap(), 0, n
);
153 if (!This
->info
.LocalName
)
155 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
156 HeapFree(GetProcessHeap(), 0, This
);
157 return E_OUTOFMEMORY
;
159 memcpy(This
->info
.LocalName
, localName
, n
);
161 This
->IBackgroundCopyFile_iface
.lpVtbl
= &BackgroundCopyFileVtbl
;
164 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
165 This
->fileProgress
.BytesTransferred
= 0;
166 This
->fileProgress
.Completed
= FALSE
;
168 IBackgroundCopyJob2_AddRef(&owner
->IBackgroundCopyJob2_iface
);
174 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
175 LARGE_INTEGER totalTransferred
,
176 LARGE_INTEGER streamSize
,
177 LARGE_INTEGER streamTransferred
,
184 BackgroundCopyFileImpl
*file
= obj
;
185 BackgroundCopyJobImpl
*job
= file
->owner
;
188 EnterCriticalSection(&job
->cs
);
189 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
190 ? totalTransferred
.QuadPart
191 : totalTransferred
.QuadPart
- file
->fileProgress
.BytesTransferred
);
192 file
->fileProgress
.BytesTotal
= totalSize
.QuadPart
;
193 file
->fileProgress
.BytesTransferred
= totalTransferred
.QuadPart
;
194 job
->jobProgress
.BytesTransferred
+= diff
;
195 LeaveCriticalSection(&job
->cs
);
197 return (job
->state
== BG_JOB_STATE_TRANSFERRING
204 IBindStatusCallback IBindStatusCallback_iface
;
205 BackgroundCopyFileImpl
*file
;
207 } DLBindStatusCallback
;
209 static inline DLBindStatusCallback
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
211 return CONTAINING_RECORD(iface
, DLBindStatusCallback
, IBindStatusCallback_iface
);
214 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
215 IBindStatusCallback
*iface
,
219 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
221 if (IsEqualGUID(riid
, &IID_IUnknown
)
222 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
224 *ppvObject
= &This
->IBindStatusCallback_iface
;
225 IBindStatusCallback_AddRef(iface
);
230 return E_NOINTERFACE
;
233 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
235 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
236 return InterlockedIncrement(&This
->ref
);
239 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
241 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
242 ULONG ref
= InterlockedDecrement(&This
->ref
);
246 IBackgroundCopyFile_Release(&This
->file
->IBackgroundCopyFile_iface
);
247 HeapFree(GetProcessHeap(), 0, This
);
253 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
254 IBindStatusCallback
*iface
,
261 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
262 IBindStatusCallback
*iface
,
268 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
269 IBindStatusCallback
*iface
,
272 FORMATETC
*pformatetc
,
278 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
279 IBindStatusCallback
*iface
,
285 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
286 IBindStatusCallback
*iface
,
293 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
294 IBindStatusCallback
*iface
,
300 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
301 BackgroundCopyFileImpl
*file
= This
->file
;
302 BackgroundCopyJobImpl
*job
= file
->owner
;
305 EnterCriticalSection(&job
->cs
);
306 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
308 : progress
- file
->fileProgress
.BytesTransferred
);
309 file
->fileProgress
.BytesTotal
= progressMax
? progressMax
: BG_SIZE_UNKNOWN
;
310 file
->fileProgress
.BytesTransferred
= progress
;
311 job
->jobProgress
.BytesTransferred
+= diff
;
312 LeaveCriticalSection(&job
->cs
);
317 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
318 IBindStatusCallback
*iface
,
325 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
326 IBindStatusCallback
*iface
,
333 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl
=
335 DLBindStatusCallback_QueryInterface
,
336 DLBindStatusCallback_AddRef
,
337 DLBindStatusCallback_Release
,
338 DLBindStatusCallback_OnStartBinding
,
339 DLBindStatusCallback_GetPriority
,
340 DLBindStatusCallback_OnLowResource
,
341 DLBindStatusCallback_OnProgress
,
342 DLBindStatusCallback_OnStopBinding
,
343 DLBindStatusCallback_GetBindInfo
,
344 DLBindStatusCallback_OnDataAvailable
,
345 DLBindStatusCallback_OnObjectAvailable
348 static DLBindStatusCallback
*DLBindStatusCallbackConstructor(
349 BackgroundCopyFileImpl
*file
)
351 DLBindStatusCallback
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
355 This
->IBindStatusCallback_iface
.lpVtbl
= &DLBindStatusCallback_Vtbl
;
356 IBackgroundCopyFile_AddRef(&file
->IBackgroundCopyFile_iface
);
362 BOOL
processFile(BackgroundCopyFileImpl
*file
, BackgroundCopyJobImpl
*job
)
364 static const WCHAR prefix
[] = {'B','I','T', 0};
365 DLBindStatusCallback
*callbackObj
;
366 WCHAR tmpDir
[MAX_PATH
];
367 WCHAR tmpName
[MAX_PATH
];
370 if (!GetTempPathW(MAX_PATH
, tmpDir
))
372 ERR("Couldn't create temp file name: %d\n", GetLastError());
373 /* Guessing on what state this should give us */
374 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
378 if (!GetTempFileNameW(tmpDir
, prefix
, 0, tmpName
))
380 ERR("Couldn't create temp file: %d\n", GetLastError());
381 /* Guessing on what state this should give us */
382 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
386 callbackObj
= DLBindStatusCallbackConstructor(file
);
389 ERR("Out of memory\n");
390 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
394 EnterCriticalSection(&job
->cs
);
395 file
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
396 file
->fileProgress
.BytesTransferred
= 0;
397 file
->fileProgress
.Completed
= FALSE
;
398 LeaveCriticalSection(&job
->cs
);
400 TRACE("Transferring: %s -> %s -> %s\n",
401 debugstr_w(file
->info
.RemoteName
),
403 debugstr_w(file
->info
.LocalName
));
405 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSFERRING
);
407 DeleteUrlCacheEntryW(file
->info
.RemoteName
);
408 hr
= URLDownloadToFileW(NULL
, file
->info
.RemoteName
, tmpName
, 0,
409 &callbackObj
->IBindStatusCallback_iface
);
410 IBindStatusCallback_Release(&callbackObj
->IBindStatusCallback_iface
);
411 if (hr
== INET_E_DOWNLOAD_FAILURE
)
413 TRACE("URLDownload failed, trying local file copy\n");
414 if (!CopyFileExW(file
->info
.RemoteName
, tmpName
, copyProgressCallback
,
417 ERR("Local file copy failed: error %d\n", GetLastError());
418 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
424 ERR("URLDownload failed: eh 0x%08x\n", hr
);
425 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
429 if (transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_QUEUED
))
431 lstrcpyW(file
->tempFileName
, tmpName
);
433 EnterCriticalSection(&job
->cs
);
434 file
->fileProgress
.Completed
= TRUE
;
435 job
->jobProgress
.FilesTransferred
++;
436 LeaveCriticalSection(&job
->cs
);
442 DeleteFileW(tmpName
);