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 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
31 //#include "winuser.h"
38 #include <wine/debug.h>
40 WINE_DEFAULT_DEBUG_CHANNEL(qmgr
);
42 static void BackgroundCopyFileDestructor(BackgroundCopyFileImpl
*This
)
44 IBackgroundCopyJob_Release((IBackgroundCopyJob
*) This
->owner
);
45 HeapFree(GetProcessHeap(), 0, This
->info
.LocalName
);
46 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
47 HeapFree(GetProcessHeap(), 0, This
);
50 static ULONG WINAPI
BITS_IBackgroundCopyFile_AddRef(IBackgroundCopyFile
* iface
)
52 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
53 return InterlockedIncrement(&This
->ref
);
56 static HRESULT WINAPI
BITS_IBackgroundCopyFile_QueryInterface(
57 IBackgroundCopyFile
* iface
,
61 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
63 if (IsEqualGUID(riid
, &IID_IUnknown
)
64 || IsEqualGUID(riid
, &IID_IBackgroundCopyFile
))
66 *ppvObject
= &This
->lpVtbl
;
67 BITS_IBackgroundCopyFile_AddRef(iface
);
76 static ULONG WINAPI
BITS_IBackgroundCopyFile_Release(
77 IBackgroundCopyFile
* iface
)
79 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
80 ULONG ref
= InterlockedDecrement(&This
->ref
);
83 BackgroundCopyFileDestructor(This
);
88 /* Get the remote name of a background copy file */
89 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetRemoteName(
90 IBackgroundCopyFile
* iface
,
93 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
94 int n
= (lstrlenW(This
->info
.RemoteName
) + 1) * sizeof(WCHAR
);
96 *pVal
= CoTaskMemAlloc(n
);
100 memcpy(*pVal
, This
->info
.RemoteName
, n
);
104 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetLocalName(
105 IBackgroundCopyFile
* iface
,
108 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
109 int n
= (lstrlenW(This
->info
.LocalName
) + 1) * sizeof(WCHAR
);
111 *pVal
= CoTaskMemAlloc(n
);
113 return E_OUTOFMEMORY
;
115 memcpy(*pVal
, This
->info
.LocalName
, n
);
119 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetProgress(
120 IBackgroundCopyFile
* iface
,
121 BG_FILE_PROGRESS
*pVal
)
123 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
125 EnterCriticalSection(&This
->owner
->cs
);
126 pVal
->BytesTotal
= This
->fileProgress
.BytesTotal
;
127 pVal
->BytesTransferred
= This
->fileProgress
.BytesTransferred
;
128 pVal
->Completed
= This
->fileProgress
.Completed
;
129 LeaveCriticalSection(&This
->owner
->cs
);
134 static const IBackgroundCopyFileVtbl BITS_IBackgroundCopyFile_Vtbl
=
136 BITS_IBackgroundCopyFile_QueryInterface
,
137 BITS_IBackgroundCopyFile_AddRef
,
138 BITS_IBackgroundCopyFile_Release
,
139 BITS_IBackgroundCopyFile_GetRemoteName
,
140 BITS_IBackgroundCopyFile_GetLocalName
,
141 BITS_IBackgroundCopyFile_GetProgress
144 HRESULT
BackgroundCopyFileConstructor(BackgroundCopyJobImpl
*owner
,
145 LPCWSTR remoteName
, LPCWSTR localName
,
148 BackgroundCopyFileImpl
*This
;
151 TRACE("(%s,%s,%p)\n", debugstr_w(remoteName
),
152 debugstr_w(localName
), ppObj
);
154 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
156 return E_OUTOFMEMORY
;
158 n
= (lstrlenW(remoteName
) + 1) * sizeof(WCHAR
);
159 This
->info
.RemoteName
= HeapAlloc(GetProcessHeap(), 0, n
);
160 if (!This
->info
.RemoteName
)
162 HeapFree(GetProcessHeap(), 0, This
);
163 return E_OUTOFMEMORY
;
165 memcpy(This
->info
.RemoteName
, remoteName
, n
);
167 n
= (lstrlenW(localName
) + 1) * sizeof(WCHAR
);
168 This
->info
.LocalName
= HeapAlloc(GetProcessHeap(), 0, n
);
169 if (!This
->info
.LocalName
)
171 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
172 HeapFree(GetProcessHeap(), 0, This
);
173 return E_OUTOFMEMORY
;
175 memcpy(This
->info
.LocalName
, localName
, n
);
177 This
->lpVtbl
= &BITS_IBackgroundCopyFile_Vtbl
;
180 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
181 This
->fileProgress
.BytesTransferred
= 0;
182 This
->fileProgress
.Completed
= FALSE
;
184 IBackgroundCopyJob_AddRef((IBackgroundCopyJob
*) owner
);
186 *ppObj
= &This
->lpVtbl
;
190 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
191 LARGE_INTEGER totalTransferred
,
192 LARGE_INTEGER streamSize
,
193 LARGE_INTEGER streamTransferred
,
200 BackgroundCopyFileImpl
*file
= obj
;
201 BackgroundCopyJobImpl
*job
= file
->owner
;
204 EnterCriticalSection(&job
->cs
);
205 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
206 ? totalTransferred
.QuadPart
207 : totalTransferred
.QuadPart
- file
->fileProgress
.BytesTransferred
);
208 file
->fileProgress
.BytesTotal
= totalSize
.QuadPart
;
209 file
->fileProgress
.BytesTransferred
= totalTransferred
.QuadPart
;
210 job
->jobProgress
.BytesTransferred
+= diff
;
211 LeaveCriticalSection(&job
->cs
);
213 return (job
->state
== BG_JOB_STATE_TRANSFERRING
220 const IBindStatusCallbackVtbl
*lpVtbl
;
221 BackgroundCopyFileImpl
*file
;
223 } DLBindStatusCallback
;
225 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
227 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
228 return InterlockedIncrement(&This
->ref
);
231 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
233 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
234 ULONG ref
= InterlockedDecrement(&This
->ref
);
238 IBackgroundCopyFile_Release((IBackgroundCopyFile
*) This
->file
);
239 HeapFree(GetProcessHeap(), 0, This
);
245 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
246 IBindStatusCallback
*iface
,
250 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
252 if (IsEqualGUID(riid
, &IID_IUnknown
)
253 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
255 *ppvObject
= &This
->lpVtbl
;
256 DLBindStatusCallback_AddRef(iface
);
261 return E_NOINTERFACE
;
264 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
265 IBindStatusCallback
*iface
,
272 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
273 IBindStatusCallback
*iface
,
279 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
280 IBindStatusCallback
*iface
,
283 FORMATETC
*pformatetc
,
289 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
290 IBindStatusCallback
*iface
,
296 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
297 IBindStatusCallback
*iface
,
304 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
305 IBindStatusCallback
*iface
,
311 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
312 BackgroundCopyFileImpl
*file
= This
->file
;
313 BackgroundCopyJobImpl
*job
= file
->owner
;
316 EnterCriticalSection(&job
->cs
);
317 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
319 : progress
- file
->fileProgress
.BytesTransferred
);
320 file
->fileProgress
.BytesTotal
= progressMax
? progressMax
: BG_SIZE_UNKNOWN
;
321 file
->fileProgress
.BytesTransferred
= progress
;
322 job
->jobProgress
.BytesTransferred
+= diff
;
323 LeaveCriticalSection(&job
->cs
);
328 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
329 IBindStatusCallback
*iface
,
336 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
337 IBindStatusCallback
*iface
,
344 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl
=
346 DLBindStatusCallback_QueryInterface
,
347 DLBindStatusCallback_AddRef
,
348 DLBindStatusCallback_Release
,
349 DLBindStatusCallback_OnStartBinding
,
350 DLBindStatusCallback_GetPriority
,
351 DLBindStatusCallback_OnLowResource
,
352 DLBindStatusCallback_OnProgress
,
353 DLBindStatusCallback_OnStopBinding
,
354 DLBindStatusCallback_GetBindInfo
,
355 DLBindStatusCallback_OnDataAvailable
,
356 DLBindStatusCallback_OnObjectAvailable
359 static DLBindStatusCallback
*DLBindStatusCallbackConstructor(
360 BackgroundCopyFileImpl
*file
)
362 DLBindStatusCallback
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
366 This
->lpVtbl
= &DLBindStatusCallback_Vtbl
;
367 IBackgroundCopyFile_AddRef((IBackgroundCopyFile
*) file
);
373 BOOL
processFile(BackgroundCopyFileImpl
*file
, BackgroundCopyJobImpl
*job
)
375 static const WCHAR prefix
[] = {'B','I','T', 0};
376 IBindStatusCallback
*callbackObj
;
377 WCHAR tmpDir
[MAX_PATH
];
378 WCHAR tmpName
[MAX_PATH
];
381 if (!GetTempPathW(MAX_PATH
, tmpDir
))
383 ERR("Couldn't create temp file name: %d\n", GetLastError());
384 /* Guessing on what state this should give us */
385 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
389 if (!GetTempFileNameW(tmpDir
, prefix
, 0, tmpName
))
391 ERR("Couldn't create temp file: %d\n", GetLastError());
392 /* Guessing on what state this should give us */
393 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
397 callbackObj
= (IBindStatusCallback
*) DLBindStatusCallbackConstructor(file
);
400 ERR("Out of memory\n");
401 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
405 EnterCriticalSection(&job
->cs
);
406 file
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
407 file
->fileProgress
.BytesTransferred
= 0;
408 file
->fileProgress
.Completed
= FALSE
;
409 LeaveCriticalSection(&job
->cs
);
411 TRACE("Transferring: %s -> %s -> %s\n",
412 debugstr_w(file
->info
.RemoteName
),
414 debugstr_w(file
->info
.LocalName
));
416 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSFERRING
);
418 DeleteUrlCacheEntryW(file
->info
.RemoteName
);
419 hr
= URLDownloadToFileW(NULL
, file
->info
.RemoteName
, tmpName
, 0, callbackObj
);
420 IBindStatusCallback_Release(callbackObj
);
421 if (hr
== INET_E_DOWNLOAD_FAILURE
)
423 TRACE("URLDownload failed, trying local file copy\n");
424 if (!CopyFileExW(file
->info
.RemoteName
, tmpName
, copyProgressCallback
,
427 ERR("Local file copy failed: error %d\n", GetLastError());
428 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
434 ERR("URLDownload failed: eh 0x%08x\n", hr
);
435 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
439 if (transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_QUEUED
))
441 lstrcpyW(file
->tempFileName
, tmpName
);
443 EnterCriticalSection(&job
->cs
);
444 file
->fileProgress
.Completed
= TRUE
;
445 job
->jobProgress
.FilesTransferred
++;
446 LeaveCriticalSection(&job
->cs
);
452 DeleteFileW(tmpName
);