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
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
,
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
))
62 IBackgroundCopyFile2_AddRef(iface
);
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
);
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
);
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
);
94 /* Get the remote name of a background copy file */
95 static HRESULT WINAPI
BackgroundCopyFile_GetRemoteName(
96 IBackgroundCopyFile2
*iface
,
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
,
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
);
134 static HRESULT WINAPI
BackgroundCopyFile_GetFileRanges(
135 IBackgroundCopyFile2
*iface
,
137 BG_FILE_RANGE
**Ranges
)
139 BackgroundCopyFileImpl
*file
= impl_from_IBackgroundCopyFile2(iface
);
140 FIXME("(%p)->(%p %p)\n", file
, RangeCount
, Ranges
);
144 static HRESULT WINAPI
BackgroundCopyFile_SetRemoteName(
145 IBackgroundCopyFile2
*iface
,
148 BackgroundCopyFileImpl
*file
= impl_from_IBackgroundCopyFile2(iface
);
149 FIXME("(%p)->(%s)\n", file
, debugstr_w(Val
));
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
;
172 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName
), debugstr_w(localName
), file
);
174 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *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
;
200 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
201 This
->fileProgress
.BytesTransferred
= 0;
202 This
->fileProgress
.Completed
= FALSE
;
204 IBackgroundCopyJob2_AddRef(&owner
->IBackgroundCopyJob2_iface
);
210 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
211 LARGE_INTEGER totalTransferred
,
212 LARGE_INTEGER streamSize
,
213 LARGE_INTEGER streamTransferred
,
220 BackgroundCopyFileImpl
*file
= obj
;
221 BackgroundCopyJobImpl
*job
= file
->owner
;
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
240 IBindStatusCallback IBindStatusCallback_iface
;
241 BackgroundCopyFileImpl
*file
;
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
,
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
);
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
);
282 IBackgroundCopyFile2_Release(&This
->file
->IBackgroundCopyFile2_iface
);
283 HeapFree(GetProcessHeap(), 0, This
);
289 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
290 IBindStatusCallback
*iface
,
297 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
298 IBindStatusCallback
*iface
,
304 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
305 IBindStatusCallback
*iface
,
308 FORMATETC
*pformatetc
,
314 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
315 IBindStatusCallback
*iface
,
321 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
322 IBindStatusCallback
*iface
,
329 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
330 IBindStatusCallback
*iface
,
336 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
337 BackgroundCopyFileImpl
*file
= This
->file
;
338 BackgroundCopyJobImpl
*job
= file
->owner
;
341 EnterCriticalSection(&job
->cs
);
342 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
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
);
353 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
354 IBindStatusCallback
*iface
,
361 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
362 IBindStatusCallback
*iface
,
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
);
391 This
->IBindStatusCallback_iface
.lpVtbl
= &DLBindStatusCallback_Vtbl
;
392 IBackgroundCopyFile2_AddRef(&file
->IBackgroundCopyFile2_iface
);
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
];
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
);
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
);
422 callbackObj
= DLBindStatusCallbackConstructor(file
);
425 ERR("Out of memory\n");
426 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
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
),
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
,
453 ERR("Local file copy failed: error %d\n", GetLastError());
454 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
460 ERR("URLDownload failed: eh 0x%08x\n", hr
);
461 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
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
);
478 DeleteFileW(tmpName
);