|  | /* | 
|  | * Background Copy Job Interface for BITS | 
|  | * | 
|  | * Copyright 2007 Google (Roy Shea) | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  |  | 
|  | #include "qmgr.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(qmgr); | 
|  |  | 
|  | static void BackgroundCopyJobDestructor(BackgroundCopyJobImpl *This) | 
|  | { | 
|  | This->cs.DebugInfo->Spare[0] = 0; | 
|  | DeleteCriticalSection(&This->cs); | 
|  | HeapFree(GetProcessHeap(), 0, This->displayName); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI BITS_IBackgroundCopyJob_AddRef(IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_QueryInterface( | 
|  | IBackgroundCopyJob2 *iface, REFIID riid, LPVOID *ppvObject) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | TRACE("IID: %s\n", debugstr_guid(riid)); | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) | 
|  | || IsEqualGUID(riid, &IID_IBackgroundCopyJob) | 
|  | || IsEqualGUID(riid, &IID_IBackgroundCopyJob2)) | 
|  | { | 
|  | *ppvObject = &This->lpVtbl; | 
|  | BITS_IBackgroundCopyJob_AddRef(iface); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | *ppvObject = NULL; | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI BITS_IBackgroundCopyJob_Release(IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | if (ref == 0) | 
|  | BackgroundCopyJobDestructor(This); | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | /*** IBackgroundCopyJob methods ***/ | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_AddFileSet( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG cFileCount, | 
|  | BG_FILE_INFO *pFileSet) | 
|  | { | 
|  | ULONG i; | 
|  | for (i = 0; i < cFileCount; ++i) | 
|  | { | 
|  | HRESULT hr = IBackgroundCopyJob_AddFile(iface, pFileSet[i].RemoteName, | 
|  | pFileSet[i].LocalName); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  | } | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_AddFile( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPCWSTR RemoteUrl, | 
|  | LPCWSTR LocalName) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | IBackgroundCopyFile *pFile; | 
|  | BackgroundCopyFileImpl *file; | 
|  | HRESULT res; | 
|  |  | 
|  | /* We should return E_INVALIDARG in these cases.  */ | 
|  | FIXME("Check for valid filenames and supported protocols\n"); | 
|  |  | 
|  | res = BackgroundCopyFileConstructor(This, RemoteUrl, LocalName, (LPVOID *) &pFile); | 
|  | if (res != S_OK) | 
|  | return res; | 
|  |  | 
|  | /* Add a reference to the file to file list */ | 
|  | IBackgroundCopyFile_AddRef(pFile); | 
|  | file = (BackgroundCopyFileImpl *) pFile; | 
|  | EnterCriticalSection(&This->cs); | 
|  | list_add_head(&This->files, &file->entryFromJob); | 
|  | This->jobProgress.BytesTotal = BG_SIZE_UNKNOWN; | 
|  | ++This->jobProgress.FilesTotal; | 
|  | LeaveCriticalSection(&This->cs); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_EnumFiles( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | IEnumBackgroundCopyFiles **ppEnum) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return EnumBackgroundCopyFilesConstructor((LPVOID *) ppEnum, iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_Suspend( | 
|  | IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_Resume( | 
|  | IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | HRESULT rv = S_OK; | 
|  |  | 
|  | EnterCriticalSection(&globalMgr.cs); | 
|  | if (This->state == BG_JOB_STATE_CANCELLED | 
|  | || This->state == BG_JOB_STATE_ACKNOWLEDGED) | 
|  | { | 
|  | rv = BG_E_INVALID_STATE; | 
|  | } | 
|  | else if (This->jobProgress.FilesTransferred == This->jobProgress.FilesTotal) | 
|  | { | 
|  | rv = BG_E_EMPTY; | 
|  | } | 
|  | else if (This->state != BG_JOB_STATE_CONNECTING | 
|  | && This->state != BG_JOB_STATE_TRANSFERRING) | 
|  | { | 
|  | This->state = BG_JOB_STATE_QUEUED; | 
|  | SetEvent(globalMgr.jobEvent); | 
|  | } | 
|  | LeaveCriticalSection(&globalMgr.cs); | 
|  |  | 
|  | return rv; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_Cancel( | 
|  | IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_Complete( | 
|  | IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | HRESULT rv = S_OK; | 
|  |  | 
|  | EnterCriticalSection(&This->cs); | 
|  |  | 
|  | if (This->state == BG_JOB_STATE_CANCELLED | 
|  | || This->state == BG_JOB_STATE_ACKNOWLEDGED) | 
|  | { | 
|  | rv = BG_E_INVALID_STATE; | 
|  | } | 
|  | else | 
|  | { | 
|  | BackgroundCopyFileImpl *file; | 
|  | LIST_FOR_EACH_ENTRY(file, &This->files, BackgroundCopyFileImpl, entryFromJob) | 
|  | { | 
|  | if (file->fileProgress.Completed) | 
|  | { | 
|  | if (!MoveFileExW(file->tempFileName, file->info.LocalName, | 
|  | (MOVEFILE_COPY_ALLOWED | 
|  | | MOVEFILE_REPLACE_EXISTING | 
|  | | MOVEFILE_WRITE_THROUGH))) | 
|  | { | 
|  | ERR("Couldn't rename file %s -> %s\n", | 
|  | debugstr_w(file->tempFileName), | 
|  | debugstr_w(file->info.LocalName)); | 
|  | rv = BG_S_PARTIAL_COMPLETE; | 
|  | } | 
|  | } | 
|  | else | 
|  | rv = BG_S_PARTIAL_COMPLETE; | 
|  | } | 
|  | } | 
|  |  | 
|  | This->state = BG_JOB_STATE_ACKNOWLEDGED; | 
|  | LeaveCriticalSection(&This->cs); | 
|  |  | 
|  | return rv; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetId( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | GUID *pVal) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | *pVal = This->jobId; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetType( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_TYPE *pVal) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  |  | 
|  | if (!pVal) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *pVal = This->type; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetProgress( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_PROGRESS *pVal) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  |  | 
|  | if (!pVal) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | EnterCriticalSection(&This->cs); | 
|  | pVal->BytesTotal = This->jobProgress.BytesTotal; | 
|  | pVal->BytesTransferred = This->jobProgress.BytesTransferred; | 
|  | pVal->FilesTotal = This->jobProgress.FilesTotal; | 
|  | pVal->FilesTransferred = This->jobProgress.FilesTransferred; | 
|  | LeaveCriticalSection(&This->cs); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetTimes( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_TIMES *pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetState( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_STATE *pVal) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  |  | 
|  | if (!pVal) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | /* Don't think we need a critical section for this */ | 
|  | *pVal = This->state; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetError( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | IBackgroundCopyError **ppError) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetOwner( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPWSTR *pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetDisplayName( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPCWSTR Val) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetDisplayName( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPWSTR *pVal) | 
|  | { | 
|  | BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; | 
|  | int n; | 
|  |  | 
|  | if (!pVal) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | n = (lstrlenW(This->displayName) + 1) * sizeof **pVal; | 
|  | *pVal = CoTaskMemAlloc(n); | 
|  | if (*pVal == NULL) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy(*pVal, This->displayName, n); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetDescription( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPCWSTR Val) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetDescription( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPWSTR *pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetPriority( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_PRIORITY Val) | 
|  | { | 
|  | FIXME("(%p,0x%08x) stub\n", iface, Val); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetPriority( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_PRIORITY *pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyFlags( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG Val) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyFlags( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG *pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyInterface( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | IUnknown *Val) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyInterface( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | IUnknown **pVal) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetMinimumRetryDelay( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG Seconds) | 
|  | { | 
|  | FIXME("%u\n", Seconds); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetMinimumRetryDelay( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG *Seconds) | 
|  | { | 
|  | FIXME("%p\n", Seconds); | 
|  | *Seconds = 30; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNoProgressTimeout( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG Seconds) | 
|  | { | 
|  | FIXME("%u\n", Seconds); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNoProgressTimeout( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG *Seconds) | 
|  | { | 
|  | FIXME("%p\n", Seconds); | 
|  | *Seconds = 900; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetErrorCount( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | ULONG *Errors) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetProxySettings( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_PROXY_USAGE ProxyUsage, | 
|  | const WCHAR *ProxyList, | 
|  | const WCHAR *ProxyBypassList) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetProxySettings( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_PROXY_USAGE *pProxyUsage, | 
|  | LPWSTR *pProxyList, | 
|  | LPWSTR *pProxyBypassList) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_TakeOwnership( | 
|  | IBackgroundCopyJob2 *iface) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyCmdLine( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPCWSTR prog, | 
|  | LPCWSTR params) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyCmdLine( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPWSTR *prog, | 
|  | LPWSTR *params) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyProgress( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_JOB_REPLY_PROGRESS *progress) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyData( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | byte **pBuffer, | 
|  | UINT64 *pLength) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetReplyFileName( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPCWSTR filename) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyFileName( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | LPWSTR *pFilename) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_SetCredentials( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_AUTH_CREDENTIALS *cred) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI BITS_IBackgroundCopyJob_RemoveCredentials( | 
|  | IBackgroundCopyJob2 *iface, | 
|  | BG_AUTH_TARGET target, | 
|  | BG_AUTH_SCHEME scheme) | 
|  | { | 
|  | FIXME("Not implemented\n"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const IBackgroundCopyJob2Vtbl BITS_IBackgroundCopyJob_Vtbl = | 
|  | { | 
|  | BITS_IBackgroundCopyJob_QueryInterface, | 
|  | BITS_IBackgroundCopyJob_AddRef, | 
|  | BITS_IBackgroundCopyJob_Release, | 
|  | BITS_IBackgroundCopyJob_AddFileSet, | 
|  | BITS_IBackgroundCopyJob_AddFile, | 
|  | BITS_IBackgroundCopyJob_EnumFiles, | 
|  | BITS_IBackgroundCopyJob_Suspend, | 
|  | BITS_IBackgroundCopyJob_Resume, | 
|  | BITS_IBackgroundCopyJob_Cancel, | 
|  | BITS_IBackgroundCopyJob_Complete, | 
|  | BITS_IBackgroundCopyJob_GetId, | 
|  | BITS_IBackgroundCopyJob_GetType, | 
|  | BITS_IBackgroundCopyJob_GetProgress, | 
|  | BITS_IBackgroundCopyJob_GetTimes, | 
|  | BITS_IBackgroundCopyJob_GetState, | 
|  | BITS_IBackgroundCopyJob_GetError, | 
|  | BITS_IBackgroundCopyJob_GetOwner, | 
|  | BITS_IBackgroundCopyJob_SetDisplayName, | 
|  | BITS_IBackgroundCopyJob_GetDisplayName, | 
|  | BITS_IBackgroundCopyJob_SetDescription, | 
|  | BITS_IBackgroundCopyJob_GetDescription, | 
|  | BITS_IBackgroundCopyJob_SetPriority, | 
|  | BITS_IBackgroundCopyJob_GetPriority, | 
|  | BITS_IBackgroundCopyJob_SetNotifyFlags, | 
|  | BITS_IBackgroundCopyJob_GetNotifyFlags, | 
|  | BITS_IBackgroundCopyJob_SetNotifyInterface, | 
|  | BITS_IBackgroundCopyJob_GetNotifyInterface, | 
|  | BITS_IBackgroundCopyJob_SetMinimumRetryDelay, | 
|  | BITS_IBackgroundCopyJob_GetMinimumRetryDelay, | 
|  | BITS_IBackgroundCopyJob_SetNoProgressTimeout, | 
|  | BITS_IBackgroundCopyJob_GetNoProgressTimeout, | 
|  | BITS_IBackgroundCopyJob_GetErrorCount, | 
|  | BITS_IBackgroundCopyJob_SetProxySettings, | 
|  | BITS_IBackgroundCopyJob_GetProxySettings, | 
|  | BITS_IBackgroundCopyJob_TakeOwnership, | 
|  | BITS_IBackgroundCopyJob_SetNotifyCmdLine, | 
|  | BITS_IBackgroundCopyJob_GetNotifyCmdLine, | 
|  | BITS_IBackgroundCopyJob_GetReplyProgress, | 
|  | BITS_IBackgroundCopyJob_GetReplyData, | 
|  | BITS_IBackgroundCopyJob_SetReplyFileName, | 
|  | BITS_IBackgroundCopyJob_GetReplyFileName, | 
|  | BITS_IBackgroundCopyJob_SetCredentials, | 
|  | BITS_IBackgroundCopyJob_RemoveCredentials | 
|  | }; | 
|  |  | 
|  | HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, | 
|  | GUID *pJobId, LPVOID *ppObj) | 
|  | { | 
|  | HRESULT hr; | 
|  | BackgroundCopyJobImpl *This; | 
|  | int n; | 
|  |  | 
|  | TRACE("(%s,%d,%p)\n", debugstr_w(displayName), type, ppObj); | 
|  |  | 
|  | This = HeapAlloc(GetProcessHeap(), 0, sizeof *This); | 
|  | if (!This) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | This->lpVtbl = &BITS_IBackgroundCopyJob_Vtbl; | 
|  | InitializeCriticalSection(&This->cs); | 
|  | This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BackgroundCopyJobImpl.cs"); | 
|  |  | 
|  | This->ref = 1; | 
|  | This->type = type; | 
|  |  | 
|  | n = (lstrlenW(displayName) + 1) *  sizeof *displayName; | 
|  | This->displayName = HeapAlloc(GetProcessHeap(), 0, n); | 
|  | if (!This->displayName) | 
|  | { | 
|  | This->cs.DebugInfo->Spare[0] = 0; | 
|  | DeleteCriticalSection(&This->cs); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | return E_OUTOFMEMORY; | 
|  | } | 
|  | memcpy(This->displayName, displayName, n); | 
|  |  | 
|  | hr = CoCreateGuid(&This->jobId); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | This->cs.DebugInfo->Spare[0] = 0; | 
|  | DeleteCriticalSection(&This->cs); | 
|  | HeapFree(GetProcessHeap(), 0, This->displayName); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | return hr; | 
|  | } | 
|  | *pJobId = This->jobId; | 
|  |  | 
|  | list_init(&This->files); | 
|  | This->jobProgress.BytesTotal = 0; | 
|  | This->jobProgress.BytesTransferred = 0; | 
|  | This->jobProgress.FilesTotal = 0; | 
|  | This->jobProgress.FilesTransferred = 0; | 
|  |  | 
|  | This->state = BG_JOB_STATE_SUSPENDED; | 
|  |  | 
|  | *ppObj = &This->lpVtbl; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | void processJob(BackgroundCopyJobImpl *job) | 
|  | { | 
|  | for (;;) | 
|  | { | 
|  | BackgroundCopyFileImpl *file; | 
|  | BOOL done = TRUE; | 
|  |  | 
|  | EnterCriticalSection(&job->cs); | 
|  | LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob) | 
|  | if (!file->fileProgress.Completed) | 
|  | { | 
|  | done = FALSE; | 
|  | break; | 
|  | } | 
|  | LeaveCriticalSection(&job->cs); | 
|  | if (done) | 
|  | { | 
|  | transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRED); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!processFile(file, job)) | 
|  | return; | 
|  | } | 
|  | } |