Commit 230b52da authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

qmgr: Use winhttp for HTTP transfers instead of wininet.

parent 3b5991cd
MODULE = qmgr.dll MODULE = qmgr.dll
IMPORTS = uuid wininet urlmon ole32 advapi32 IMPORTS = uuid winhttp ole32 advapi32
C_SRCS = \ C_SRCS = \
enum_files.c \ enum_files.c \
......
...@@ -24,9 +24,8 @@ ...@@ -24,9 +24,8 @@
#include "winbase.h" #include "winbase.h"
#include "winuser.h" #include "winuser.h"
#include "winreg.h" #include "winreg.h"
#include "wininet.h" #include "winhttp.h"
#define COBJMACROS #define COBJMACROS
#include "urlmon.h"
#include "qmgr.h" #include "qmgr.h"
#include "wine/debug.h" #include "wine/debug.h"
...@@ -201,309 +200,241 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner, ...@@ -201,309 +200,241 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
This->fileProgress.BytesTransferred = 0; This->fileProgress.BytesTransferred = 0;
This->fileProgress.Completed = FALSE; This->fileProgress.Completed = FALSE;
This->owner = owner; This->owner = owner;
This->read_size = 0;
IBackgroundCopyJob3_AddRef(&owner->IBackgroundCopyJob3_iface); IBackgroundCopyJob3_AddRef(&owner->IBackgroundCopyJob3_iface);
*file = This; *file = This;
return S_OK; return S_OK;
} }
static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize, static HRESULT error_from_http_response(DWORD code)
LARGE_INTEGER totalTransferred,
LARGE_INTEGER streamSize,
LARGE_INTEGER streamTransferred,
DWORD streamNum,
DWORD reason,
HANDLE srcFile,
HANDLE dstFile,
LPVOID obj)
{ {
BackgroundCopyFileImpl *file = obj; switch (code)
{
case 200: return S_OK;
case 400: return BG_E_HTTP_ERROR_400;
case 401: return BG_E_HTTP_ERROR_401;
case 404: return BG_E_HTTP_ERROR_404;
case 407: return BG_E_HTTP_ERROR_407;
case 414: return BG_E_HTTP_ERROR_414;
case 501: return BG_E_HTTP_ERROR_501;
case 503: return BG_E_HTTP_ERROR_503;
case 504: return BG_E_HTTP_ERROR_504;
case 505: return BG_E_HTTP_ERROR_505;
default:
FIXME("unhandled response code %u\n", code);
return S_OK;
}
}
static void CALLBACK progress_callback_http(HINTERNET handle, DWORD_PTR context, DWORD status,
LPVOID buf, DWORD buflen)
{
BackgroundCopyFileImpl *file = (BackgroundCopyFileImpl *)context;
BackgroundCopyJobImpl *job = file->owner; BackgroundCopyJobImpl *job = file->owner;
ULONG64 diff;
EnterCriticalSection(&job->cs); TRACE("%p, %p, %x, %p, %u\n", handle, file, status, buf, buflen);
diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
? totalTransferred.QuadPart
: totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
file->fileProgress.BytesTotal = totalSize.QuadPart;
file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
job->jobProgress.BytesTransferred += diff;
LeaveCriticalSection(&job->cs);
return (job->state == BG_JOB_STATE_TRANSFERRING switch (status)
? PROGRESS_CONTINUE {
: PROGRESS_CANCEL); case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
} {
DWORD code, len, size;
typedef struct size = sizeof(code);
{ if (WinHttpQueryHeaders(handle, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER,
IBindStatusCallback IBindStatusCallback_iface; NULL, &code, &size, NULL))
IHttpNegotiate IHttpNegotiate_iface; {
BackgroundCopyFileImpl *file; if ((job->error.code = error_from_http_response(code)))
LONG ref; {
} DLBindStatusCallback; EnterCriticalSection(&job->cs);
static inline DLBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface) job->error.context = BG_ERROR_CONTEXT_REMOTE_FILE;
{ if (job->error.file) IBackgroundCopyFile2_Release(job->error.file);
return CONTAINING_RECORD(iface, DLBindStatusCallback, IBindStatusCallback_iface); job->error.file = &file->IBackgroundCopyFile2_iface;
} IBackgroundCopyFile2_AddRef(job->error.file);
static HRESULT WINAPI DLBindStatusCallback_QueryInterface( LeaveCriticalSection(&job->cs);
IBindStatusCallback *iface, transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
REFIID riid, }
void **ppvObject) else
{ {
DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface); EnterCriticalSection(&job->cs);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); job->error.context = 0;
if (job->error.file)
{
IBackgroundCopyFile2_Release(job->error.file);
job->error.file = NULL;
}
if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IBindStatusCallback)) LeaveCriticalSection(&job->cs);
}
}
size = sizeof(len);
if (WinHttpQueryHeaders(handle, WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER,
NULL, &len, &size, NULL))
{ {
*ppvObject = &This->IBindStatusCallback_iface; file->fileProgress.BytesTotal = len;
}
break;
} }
else if (IsEqualGUID(riid, &IID_IHttpNegotiate)) case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
{ {
*ppvObject = &This->IHttpNegotiate_iface; file->read_size = buflen;
break;
} }
else case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
{ {
*ppvObject = NULL; WINHTTP_ASYNC_RESULT *result = (WINHTTP_ASYNC_RESULT *)buf;
return E_NOINTERFACE; job->error.code = result->dwError;
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
break;
}
default: break;
} }
IBindStatusCallback_AddRef(iface); SetEvent(job->wait);
return S_OK;
}
static ULONG WINAPI DLBindStatusCallback_AddRef(IBindStatusCallback *iface)
{
DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
return InterlockedIncrement(&This->ref);
} }
static ULONG WINAPI DLBindStatusCallback_Release(IBindStatusCallback *iface) static DWORD wait_for_completion(BackgroundCopyJobImpl *job)
{ {
DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface); HANDLE handles[2] = {job->wait, job->cancel};
ULONG ref = InterlockedDecrement(&This->ref); DWORD error = ERROR_SUCCESS;
if (ref == 0) switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE))
{ {
IBackgroundCopyFile2_Release(&This->file->IBackgroundCopyFile2_iface); case WAIT_OBJECT_0:
HeapFree(GetProcessHeap(), 0, This); break;
}
return ref; case WAIT_OBJECT_0 + 1:
} error = ERROR_CANCELLED;
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_CANCELLED);
break;
static HRESULT WINAPI DLBindStatusCallback_GetBindInfo( default:
IBindStatusCallback *iface, error = GetLastError();
DWORD *grfBINDF, transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
BINDINFO *pbindinfo) break;
{ }
return E_NOTIMPL;
}
static HRESULT WINAPI DLBindStatusCallback_GetPriority( return error;
IBindStatusCallback *iface,
LONG *pnPriority)
{
return E_NOTIMPL;
} }
static HRESULT WINAPI DLBindStatusCallback_OnDataAvailable( static BOOL transfer_file_http(BackgroundCopyFileImpl *file, URL_COMPONENTSW *uc,
IBindStatusCallback *iface, const WCHAR *tmpfile)
DWORD grfBSCF,
DWORD dwSize,
FORMATETC *pformatetc,
STGMEDIUM *pstgmed)
{ {
return E_NOTIMPL; BackgroundCopyJobImpl *job = file->owner;
} HANDLE handle;
HINTERNET ses, con = NULL, req = NULL;
DWORD flags = (uc->nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0;
char buf[4096];
BOOL ret = FALSE;
static HRESULT WINAPI DLBindStatusCallback_OnLowResource( transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_CONNECTING);
IBindStatusCallback *iface,
DWORD reserved)
{
return E_NOTIMPL;
}
static HRESULT WINAPI DLBindStatusCallback_OnObjectAvailable( if (!(ses = WinHttpOpen(NULL, 0, NULL, NULL, WINHTTP_FLAG_ASYNC))) return FALSE;
IBindStatusCallback *iface, WinHttpSetStatusCallback(ses, progress_callback_http, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, 0);
REFIID riid, if (!WinHttpSetOption(ses, WINHTTP_OPTION_CONTEXT_VALUE, file, sizeof(file))) goto done;
IUnknown *punk)
{
return E_NOTIMPL;
}
static HRESULT WINAPI DLBindStatusCallback_OnProgress( if (!(con = WinHttpConnect(ses, uc->lpszHostName, uc->nPort, 0))) goto done;
IBindStatusCallback *iface, if (!(req = WinHttpOpenRequest(con, NULL, uc->lpszUrlPath, NULL, NULL, NULL, flags))) goto done;
ULONG progress,
ULONG progressMax,
ULONG statusCode,
LPCWSTR statusText)
{
DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
BackgroundCopyFileImpl *file = This->file;
BackgroundCopyJobImpl *job = file->owner;
ULONG64 diff;
EnterCriticalSection(&job->cs); if (!(WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, (DWORD_PTR)file))) goto done;
diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN if (wait_for_completion(job) || job->error.code) goto done;
? progress
: progress - file->fileProgress.BytesTransferred);
file->fileProgress.BytesTotal = progressMax ? progressMax : BG_SIZE_UNKNOWN;
file->fileProgress.BytesTransferred = progress;
job->jobProgress.BytesTransferred += diff;
LeaveCriticalSection(&job->cs);
return S_OK; if (!(WinHttpReceiveResponse(req, NULL))) goto done;
} if (wait_for_completion(job) || job->error.code) goto done;
static HRESULT WINAPI DLBindStatusCallback_OnStartBinding( transitionJobState(job, BG_JOB_STATE_CONNECTING, BG_JOB_STATE_TRANSFERRING);
IBindStatusCallback *iface,
DWORD dwReserved,
IBinding *pib)
{
return E_NOTIMPL;
}
static HRESULT WINAPI DLBindStatusCallback_OnStopBinding( handle = CreateFileW(tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
IBindStatusCallback *iface, if (handle == INVALID_HANDLE_VALUE) goto done;
HRESULT hresult,
LPCWSTR szError)
{
return E_NOTIMPL;
}
static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl = for (;;)
{ {
DLBindStatusCallback_QueryInterface, file->read_size = 0;
DLBindStatusCallback_AddRef, if (!(ret = WinHttpReadData(req, buf, sizeof(buf), NULL))) break;
DLBindStatusCallback_Release, if (wait_for_completion(job) || job->error.code)
DLBindStatusCallback_OnStartBinding, {
DLBindStatusCallback_GetPriority, ret = FALSE;
DLBindStatusCallback_OnLowResource, break;
DLBindStatusCallback_OnProgress, }
DLBindStatusCallback_OnStopBinding, if (!file->read_size) break;
DLBindStatusCallback_GetBindInfo, if (!(ret = WriteFile(handle, buf, file->read_size, NULL, NULL))) break;
DLBindStatusCallback_OnDataAvailable,
DLBindStatusCallback_OnObjectAvailable
};
static inline DLBindStatusCallback *impl_from_IHttpNegotiate(IHttpNegotiate *iface) EnterCriticalSection(&job->cs);
{ file->fileProgress.BytesTransferred += file->read_size;
return CONTAINING_RECORD(iface, DLBindStatusCallback, IHttpNegotiate_iface); job->jobProgress.BytesTransferred += file->read_size;
} LeaveCriticalSection(&job->cs);
}
static HRESULT WINAPI http_negotiate_QueryInterface( CloseHandle(handle);
IHttpNegotiate *iface, REFIID riid, void **ppv)
{
DLBindStatusCallback *callback = impl_from_IHttpNegotiate(iface);
return IBindStatusCallback_QueryInterface(&callback->IBindStatusCallback_iface, riid, ppv);
}
static ULONG WINAPI http_negotiate_AddRef( done:
IHttpNegotiate *iface) WinHttpCloseHandle(req);
{ WinHttpCloseHandle(con);
DLBindStatusCallback *callback = impl_from_IHttpNegotiate(iface); WinHttpCloseHandle(ses);
return IBindStatusCallback_AddRef(&callback->IBindStatusCallback_iface); if (!ret) DeleteFileW(tmpfile);
}
static ULONG WINAPI http_negotiate_Release( SetEvent(job->done);
IHttpNegotiate *iface) return ret;
{
DLBindStatusCallback *callback = impl_from_IHttpNegotiate(iface);
return IBindStatusCallback_Release(&callback->IBindStatusCallback_iface);
} }
static HRESULT WINAPI http_negotiate_BeginningTransaction( static DWORD CALLBACK progress_callback_local(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
IHttpNegotiate *iface, LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers) LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
DWORD streamNum, DWORD reason, HANDLE srcFile,
HANDLE dstFile, LPVOID obj)
{ {
DLBindStatusCallback *callback = impl_from_IHttpNegotiate(iface); BackgroundCopyFileImpl *file = obj;
FIXME("(%p)->(%s %s %u %p)\n", callback, debugstr_w(url), debugstr_w(headers), reserved, add_headers); BackgroundCopyJobImpl *job = file->owner;
return E_NOTIMPL; ULONG64 diff;
}
static HRESULT error_from_http_response(DWORD code) EnterCriticalSection(&job->cs);
{ diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
switch (code) ? totalTransferred.QuadPart
{ : totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
case 200: return S_OK; file->fileProgress.BytesTotal = totalSize.QuadPart;
case 400: return BG_E_HTTP_ERROR_400; file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
case 401: return BG_E_HTTP_ERROR_401; job->jobProgress.BytesTransferred += diff;
case 404: return BG_E_HTTP_ERROR_404; LeaveCriticalSection(&job->cs);
case 407: return BG_E_HTTP_ERROR_407;
case 414: return BG_E_HTTP_ERROR_414; return (job->state == BG_JOB_STATE_TRANSFERRING
case 501: return BG_E_HTTP_ERROR_501; ? PROGRESS_CONTINUE
case 503: return BG_E_HTTP_ERROR_503; : PROGRESS_CANCEL);
case 504: return BG_E_HTTP_ERROR_504;
case 505: return BG_E_HTTP_ERROR_505;
default:
FIXME("unhandled response code %u\n", code);
return S_OK;
}
} }
static HRESULT WINAPI http_negotiate_OnResponse( static BOOL transfer_file_local(BackgroundCopyFileImpl *file, const WCHAR *tmpname)
IHttpNegotiate *iface, DWORD code, LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
{ {
DLBindStatusCallback *callback = impl_from_IHttpNegotiate(iface); static const WCHAR fileW[] = {'f','i','l','e',':','/','/',0};
BackgroundCopyJobImpl *job = callback->file->owner; BackgroundCopyJobImpl *job = file->owner;
const WCHAR *ptr;
BOOL ret;
TRACE("(%p)->(%d %s %s %p)\n", callback, code, debugstr_w(resp_headers), debugstr_w(req_headers), transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
add_reqheaders);
if ((job->error.code = error_from_http_response(code))) if (strlenW(file->info.RemoteName) > 7 && !memicmpW(file->info.RemoteName, fileW, 7))
{ ptr = file->info.RemoteName + 7;
job->error.context = BG_ERROR_CONTEXT_REMOTE_FILE;
if (job->error.file) IBackgroundCopyFile2_Release(job->error.file);
job->error.file = &callback->file->IBackgroundCopyFile2_iface;
IBackgroundCopyFile2_AddRef(job->error.file);
}
else else
ptr = file->info.RemoteName;
if (!(ret = CopyFileExW(ptr, tmpname, progress_callback_local, file, NULL, 0)))
{ {
job->error.context = 0; WARN("Local file copy failed: error %u\n", GetLastError());
if (job->error.file) transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
{
IBackgroundCopyFile2_Release(job->error.file);
job->error.file = NULL;
}
} }
*add_reqheaders = NULL;
return S_OK;
}
static const IHttpNegotiateVtbl http_negotiate_vtbl = SetEvent(job->done);
{ return ret;
http_negotiate_QueryInterface,
http_negotiate_AddRef,
http_negotiate_Release,
http_negotiate_BeginningTransaction,
http_negotiate_OnResponse
};
static DLBindStatusCallback *DLBindStatusCallbackConstructor(
BackgroundCopyFileImpl *file)
{
DLBindStatusCallback *This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
if (!This)
return NULL;
This->IBindStatusCallback_iface.lpVtbl = &DLBindStatusCallback_Vtbl;
This->IHttpNegotiate_iface.lpVtbl = &http_negotiate_vtbl;
IBackgroundCopyFile2_AddRef(&file->IBackgroundCopyFile2_iface);
This->file = file;
This->ref = 1;
return This;
} }
BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
{ {
static const WCHAR prefix[] = {'B','I','T', 0}; static const WCHAR prefix[] = {'B','I','T', 0};
DLBindStatusCallback *callbackObj; WCHAR tmpDir[MAX_PATH], tmpName[MAX_PATH];
WCHAR tmpDir[MAX_PATH]; WCHAR host[MAX_PATH], path[MAX_PATH];
WCHAR tmpName[MAX_PATH]; URL_COMPONENTSW uc;
HRESULT hr; BOOL ret;
if (!GetTempPathW(MAX_PATH, tmpDir)) if (!GetTempPathW(MAX_PATH, tmpDir))
{ {
...@@ -521,14 +452,6 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) ...@@ -521,14 +452,6 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
return FALSE; return FALSE;
} }
callbackObj = DLBindStatusCallbackConstructor(file);
if (!callbackObj)
{
ERR("Out of memory\n");
transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
return FALSE;
}
EnterCriticalSection(&job->cs); EnterCriticalSection(&job->cs);
file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN; file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
file->fileProgress.BytesTransferred = 0; file->fileProgress.BytesTransferred = 0;
...@@ -540,37 +463,35 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) ...@@ -540,37 +463,35 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
debugstr_w(tmpName), debugstr_w(tmpName),
debugstr_w(file->info.LocalName)); debugstr_w(file->info.LocalName));
transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING); uc.dwStructSize = sizeof(uc);
uc.nScheme = 0;
DeleteUrlCacheEntryW(file->info.RemoteName); uc.lpszScheme = NULL;
hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0, uc.dwSchemeLength = 0;
&callbackObj->IBindStatusCallback_iface); uc.lpszUserName = NULL;
IBindStatusCallback_Release(&callbackObj->IBindStatusCallback_iface); uc.dwUserNameLength = 0;
if (hr == INET_E_DOWNLOAD_FAILURE) uc.lpszPassword = NULL;
{ uc.dwPasswordLength = 0;
TRACE("URLDownload failed, trying local file copy\n"); uc.lpszHostName = host;
if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback, uc.dwHostNameLength = sizeof(host)/sizeof(host[0]);
file, NULL, 0)) uc.nPort = 0;
{ uc.lpszUrlPath = path;
ERR("Local file copy failed: error %d\n", GetLastError()); uc.dwUrlPathLength = sizeof(path)/sizeof(path[0]);
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR); uc.lpszExtraInfo = NULL;
return FALSE; uc.dwExtraInfoLength = 0;
} ret = WinHttpCrackUrl(file->info.RemoteName, 0, 0, &uc);
} if (!ret)
else if (FAILED(hr))
{ {
ERR("URLDownload failed: eh 0x%08x\n", hr); TRACE("WinHttpCrackUrl failed, trying local file copy\n");
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR); if (!transfer_file_local(file, tmpName)) return FALSE;
return FALSE;
} }
else if (job->error.code) else if (!transfer_file_http(file, &uc, tmpName))
{ {
ERR("transfer error: 0x%08x\n", job->error.code); WARN("HTTP transfer failed\n");
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
return FALSE; return FALSE;
} }
if (transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED)) if (transitionJobState(job, BG_JOB_STATE_CONNECTING, BG_JOB_STATE_QUEUED) ||
transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED))
{ {
lstrcpyW(file->tempFileName, tmpName); lstrcpyW(file->tempFileName, tmpName);
......
...@@ -57,6 +57,9 @@ typedef struct ...@@ -57,6 +57,9 @@ typedef struct
HRESULT code; HRESULT code;
IBackgroundCopyFile2 *file; IBackgroundCopyFile2 *file;
} error; } error;
HANDLE wait;
HANDLE cancel;
HANDLE done;
} BackgroundCopyJobImpl; } BackgroundCopyJobImpl;
/* Background copy file vtbl and related data */ /* Background copy file vtbl and related data */
...@@ -69,6 +72,7 @@ typedef struct ...@@ -69,6 +72,7 @@ typedef struct
WCHAR tempFileName[MAX_PATH]; WCHAR tempFileName[MAX_PATH];
struct list entryFromJob; struct list entryFromJob;
BackgroundCopyJobImpl *owner; BackgroundCopyJobImpl *owner;
DWORD read_size;
} BackgroundCopyFileImpl; } BackgroundCopyFileImpl;
/* Background copy manager vtbl and related data */ /* Background copy manager vtbl and related data */
...@@ -104,14 +108,6 @@ void processJob(BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN; ...@@ -104,14 +108,6 @@ void processJob(BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN; BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
/* Little helper functions */ /* Little helper functions */
static inline char *
qmgr_strdup(const char *s)
{
size_t n = strlen(s) + 1;
char *d = HeapAlloc(GetProcessHeap(), 0, n);
return d ? memcpy(d, s, n) : NULL;
}
static inline HRESULT return_strval(const WCHAR *str, WCHAR **ret) static inline HRESULT return_strval(const WCHAR *str, WCHAR **ret)
{ {
int len; int len;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment