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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(qmgr
);
38 static inline BackgroundCopyFileImpl
*impl_from_IBackgroundCopyFile(IBackgroundCopyFile
*iface
)
40 return CONTAINING_RECORD(iface
, BackgroundCopyFileImpl
, IBackgroundCopyFile_iface
);
43 static HRESULT WINAPI
BackgroundCopyFile_QueryInterface(
44 IBackgroundCopyFile
* iface
,
48 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
50 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
52 if (IsEqualGUID(riid
, &IID_IUnknown
)
53 || IsEqualGUID(riid
, &IID_IBackgroundCopyFile
))
56 IBackgroundCopyFile_AddRef(iface
);
64 static ULONG WINAPI
BackgroundCopyFile_AddRef(IBackgroundCopyFile
* iface
)
66 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
67 ULONG ref
= InterlockedIncrement(&This
->ref
);
68 TRACE("(%p)->(%d)\n", This
, ref
);
72 static ULONG WINAPI
BackgroundCopyFile_Release(
73 IBackgroundCopyFile
* iface
)
75 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
76 ULONG ref
= InterlockedDecrement(&This
->ref
);
78 TRACE("(%p)->(%d)\n", This
, ref
);
82 IBackgroundCopyJob2_Release(&This
->owner
->IBackgroundCopyJob2_iface
);
83 HeapFree(GetProcessHeap(), 0, This
->info
.LocalName
);
84 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
85 HeapFree(GetProcessHeap(), 0, This
);
91 /* Get the remote name of a background copy file */
92 static HRESULT WINAPI
BackgroundCopyFile_GetRemoteName(
93 IBackgroundCopyFile
* iface
,
96 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
98 TRACE("(%p)->(%p)\n", This
, pVal
);
100 return return_strval(This
->info
.RemoteName
, pVal
);
103 static HRESULT WINAPI
BackgroundCopyFile_GetLocalName(
104 IBackgroundCopyFile
* iface
,
107 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
109 TRACE("(%p)->(%p)\n", This
, pVal
);
111 return return_strval(This
->info
.LocalName
, pVal
);
114 static HRESULT WINAPI
BackgroundCopyFile_GetProgress(
115 IBackgroundCopyFile
* iface
,
116 BG_FILE_PROGRESS
*pVal
)
118 BackgroundCopyFileImpl
*This
= impl_from_IBackgroundCopyFile(iface
);
120 TRACE("(%p)->(%p)\n", This
, pVal
);
122 EnterCriticalSection(&This
->owner
->cs
);
123 pVal
->BytesTotal
= This
->fileProgress
.BytesTotal
;
124 pVal
->BytesTransferred
= This
->fileProgress
.BytesTransferred
;
125 pVal
->Completed
= This
->fileProgress
.Completed
;
126 LeaveCriticalSection(&This
->owner
->cs
);
131 static const IBackgroundCopyFileVtbl BackgroundCopyFileVtbl
=
133 BackgroundCopyFile_QueryInterface
,
134 BackgroundCopyFile_AddRef
,
135 BackgroundCopyFile_Release
,
136 BackgroundCopyFile_GetRemoteName
,
137 BackgroundCopyFile_GetLocalName
,
138 BackgroundCopyFile_GetProgress
141 HRESULT
BackgroundCopyFileConstructor(BackgroundCopyJobImpl
*owner
,
142 LPCWSTR remoteName
, LPCWSTR localName
,
143 BackgroundCopyFileImpl
**file
)
145 BackgroundCopyFileImpl
*This
;
148 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName
), debugstr_w(localName
), file
);
150 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
152 return E_OUTOFMEMORY
;
154 n
= (lstrlenW(remoteName
) + 1) * sizeof(WCHAR
);
155 This
->info
.RemoteName
= HeapAlloc(GetProcessHeap(), 0, n
);
156 if (!This
->info
.RemoteName
)
158 HeapFree(GetProcessHeap(), 0, This
);
159 return E_OUTOFMEMORY
;
161 memcpy(This
->info
.RemoteName
, remoteName
, n
);
163 n
= (lstrlenW(localName
) + 1) * sizeof(WCHAR
);
164 This
->info
.LocalName
= HeapAlloc(GetProcessHeap(), 0, n
);
165 if (!This
->info
.LocalName
)
167 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
168 HeapFree(GetProcessHeap(), 0, This
);
169 return E_OUTOFMEMORY
;
171 memcpy(This
->info
.LocalName
, localName
, n
);
173 This
->IBackgroundCopyFile_iface
.lpVtbl
= &BackgroundCopyFileVtbl
;
176 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
177 This
->fileProgress
.BytesTransferred
= 0;
178 This
->fileProgress
.Completed
= FALSE
;
180 IBackgroundCopyJob2_AddRef(&owner
->IBackgroundCopyJob2_iface
);
186 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
187 LARGE_INTEGER totalTransferred
,
188 LARGE_INTEGER streamSize
,
189 LARGE_INTEGER streamTransferred
,
196 BackgroundCopyFileImpl
*file
= obj
;
197 BackgroundCopyJobImpl
*job
= file
->owner
;
200 EnterCriticalSection(&job
->cs
);
201 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
202 ? totalTransferred
.QuadPart
203 : totalTransferred
.QuadPart
- file
->fileProgress
.BytesTransferred
);
204 file
->fileProgress
.BytesTotal
= totalSize
.QuadPart
;
205 file
->fileProgress
.BytesTransferred
= totalTransferred
.QuadPart
;
206 job
->jobProgress
.BytesTransferred
+= diff
;
207 LeaveCriticalSection(&job
->cs
);
209 return (job
->state
== BG_JOB_STATE_TRANSFERRING
216 IBindStatusCallback IBindStatusCallback_iface
;
217 BackgroundCopyFileImpl
*file
;
219 } DLBindStatusCallback
;
221 static inline DLBindStatusCallback
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
223 return CONTAINING_RECORD(iface
, DLBindStatusCallback
, IBindStatusCallback_iface
);
226 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
227 IBindStatusCallback
*iface
,
231 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
233 if (IsEqualGUID(riid
, &IID_IUnknown
)
234 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
236 *ppvObject
= &This
->IBindStatusCallback_iface
;
237 IBindStatusCallback_AddRef(iface
);
242 return E_NOINTERFACE
;
245 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
247 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
248 return InterlockedIncrement(&This
->ref
);
251 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
253 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
254 ULONG ref
= InterlockedDecrement(&This
->ref
);
258 IBackgroundCopyFile_Release(&This
->file
->IBackgroundCopyFile_iface
);
259 HeapFree(GetProcessHeap(), 0, This
);
265 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
266 IBindStatusCallback
*iface
,
273 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
274 IBindStatusCallback
*iface
,
280 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
281 IBindStatusCallback
*iface
,
284 FORMATETC
*pformatetc
,
290 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
291 IBindStatusCallback
*iface
,
297 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
298 IBindStatusCallback
*iface
,
305 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
306 IBindStatusCallback
*iface
,
312 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
313 BackgroundCopyFileImpl
*file
= This
->file
;
314 BackgroundCopyJobImpl
*job
= file
->owner
;
317 EnterCriticalSection(&job
->cs
);
318 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
320 : progress
- file
->fileProgress
.BytesTransferred
);
321 file
->fileProgress
.BytesTotal
= progressMax
? progressMax
: BG_SIZE_UNKNOWN
;
322 file
->fileProgress
.BytesTransferred
= progress
;
323 job
->jobProgress
.BytesTransferred
+= diff
;
324 LeaveCriticalSection(&job
->cs
);
329 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
330 IBindStatusCallback
*iface
,
337 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
338 IBindStatusCallback
*iface
,
345 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl
=
347 DLBindStatusCallback_QueryInterface
,
348 DLBindStatusCallback_AddRef
,
349 DLBindStatusCallback_Release
,
350 DLBindStatusCallback_OnStartBinding
,
351 DLBindStatusCallback_GetPriority
,
352 DLBindStatusCallback_OnLowResource
,
353 DLBindStatusCallback_OnProgress
,
354 DLBindStatusCallback_OnStopBinding
,
355 DLBindStatusCallback_GetBindInfo
,
356 DLBindStatusCallback_OnDataAvailable
,
357 DLBindStatusCallback_OnObjectAvailable
360 static DLBindStatusCallback
*DLBindStatusCallbackConstructor(
361 BackgroundCopyFileImpl
*file
)
363 DLBindStatusCallback
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
367 This
->IBindStatusCallback_iface
.lpVtbl
= &DLBindStatusCallback_Vtbl
;
368 IBackgroundCopyFile_AddRef(&file
->IBackgroundCopyFile_iface
);
374 BOOL
processFile(BackgroundCopyFileImpl
*file
, BackgroundCopyJobImpl
*job
)
376 static const WCHAR prefix
[] = {'B','I','T', 0};
377 DLBindStatusCallback
*callbackObj
;
378 WCHAR tmpDir
[MAX_PATH
];
379 WCHAR tmpName
[MAX_PATH
];
382 if (!GetTempPathW(MAX_PATH
, tmpDir
))
384 ERR("Couldn't create temp file name: %d\n", GetLastError());
385 /* Guessing on what state this should give us */
386 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
390 if (!GetTempFileNameW(tmpDir
, prefix
, 0, tmpName
))
392 ERR("Couldn't create temp file: %d\n", GetLastError());
393 /* Guessing on what state this should give us */
394 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
398 callbackObj
= DLBindStatusCallbackConstructor(file
);
401 ERR("Out of memory\n");
402 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
406 EnterCriticalSection(&job
->cs
);
407 file
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
408 file
->fileProgress
.BytesTransferred
= 0;
409 file
->fileProgress
.Completed
= FALSE
;
410 LeaveCriticalSection(&job
->cs
);
412 TRACE("Transferring: %s -> %s -> %s\n",
413 debugstr_w(file
->info
.RemoteName
),
415 debugstr_w(file
->info
.LocalName
));
417 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSFERRING
);
419 DeleteUrlCacheEntryW(file
->info
.RemoteName
);
420 hr
= URLDownloadToFileW(NULL
, file
->info
.RemoteName
, tmpName
, 0,
421 &callbackObj
->IBindStatusCallback_iface
);
422 IBindStatusCallback_Release(&callbackObj
->IBindStatusCallback_iface
);
423 if (hr
== INET_E_DOWNLOAD_FAILURE
)
425 TRACE("URLDownload failed, trying local file copy\n");
426 if (!CopyFileExW(file
->info
.RemoteName
, tmpName
, copyProgressCallback
,
429 ERR("Local file copy failed: error %d\n", GetLastError());
430 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
436 ERR("URLDownload failed: eh 0x%08x\n", hr
);
437 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
441 if (transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_QUEUED
))
443 lstrcpyW(file
->tempFileName
, tmpName
);
445 EnterCriticalSection(&job
->cs
);
446 file
->fileProgress
.Completed
= TRUE
;
447 job
->jobProgress
.FilesTransferred
++;
448 LeaveCriticalSection(&job
->cs
);
454 DeleteFileW(tmpName
);