From 05826d5a6837dfb208b773639bd4f8ac8c4e0820 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 13 Nov 2017 21:41:48 +0100 Subject: [PATCH] urlmon/tests: Added IBindStatusCallback marshaling tests. Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/urlmon/tests/misc.c | 723 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 723 insertions(+) diff --git a/dlls/urlmon/tests/misc.c b/dlls/urlmon/tests/misc.c index ba10e3a127d..dc8b17997e8 100644 --- a/dlls/urlmon/tests/misc.c +++ b/dlls/urlmon/tests/misc.c @@ -108,6 +108,21 @@ static WCHAR *a2w(const char *str) return ret; } +static WCHAR *a2co(const char *str) +{ + WCHAR *ret; + int len; + + if(!str) + return NULL; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = CoTaskMemAlloc(len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + + return ret; +} + static void test_CreateFormatEnum(void) { IEnumFORMATETC *fenum = NULL, *fenum2 = NULL; @@ -1924,6 +1939,713 @@ static void test_internet_features(void) { test_CoInternetSetFeatureEnabled(); } +static BINDINFO rem_bindinfo = { sizeof(rem_bindinfo) }, in_bindinfo; +static DWORD rem_bindf; + +static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallbackEx *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IBindStatusCallbackEx, riid) + || IsEqualGUID(&IID_IBindStatusCallback, riid) + || IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallbackEx *iface) +{ + return 2; +} + +static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallbackEx *iface) +{ + return 1; +} + +static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallbackEx *iface, + DWORD dwReserved, IBinding *pib) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallbackEx *iface, LONG *pnPriority) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallbackEx *iface, DWORD reserved) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallbackEx *iface, ULONG ulProgress, + ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallbackEx *iface, HRESULT hresult, LPCWSTR szError) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallbackEx *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +{ + in_bindinfo = *pbindinfo; + *grfBINDF = rem_bindf; + *pbindinfo = rem_bindinfo; + return S_OK; +} + +static STGMEDIUM in_stgmed, rem_stgmed; + +static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallbackEx *iface, DWORD grfBSCF, + DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) +{ + in_stgmed = *pstgmed; + *pstgmed = rem_stgmed; + return S_OK; +} + +static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallbackEx *iface, REFIID riid, IUnknown *punk) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static HRESULT WINAPI BindStatusCallbackEx_GetBindInfoEx(IBindStatusCallbackEx *iface, DWORD *grfBINDF, + BINDINFO *pbindinfo, DWORD *grfBINDF2, DWORD *pdwReserved) +{ + in_bindinfo = *pbindinfo; + *grfBINDF = rem_bindf; + *pbindinfo = rem_bindinfo; + *grfBINDF2 = 11; + *pdwReserved = 12; + return S_OK; +} + +static const IBindStatusCallbackExVtbl BindStatusCallbackExVtbl = { + BindStatusCallback_QueryInterface, + BindStatusCallback_AddRef, + BindStatusCallback_Release, + BindStatusCallback_OnStartBinding, + BindStatusCallback_GetPriority, + BindStatusCallback_OnLowResource, + BindStatusCallback_OnProgress, + BindStatusCallback_OnStopBinding, + BindStatusCallback_GetBindInfo, + BindStatusCallback_OnDataAvailable, + BindStatusCallback_OnObjectAvailable, + BindStatusCallbackEx_GetBindInfoEx +}; + +static IBindStatusCallbackEx BindStatusCallback = { &BindStatusCallbackExVtbl }; + +typedef struct { + IUnknown IUnknown_iface; + LONG ref; +} RefUnk; + +static inline RefUnk *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, RefUnk, IUnknown_iface); +} + +static HRESULT WINAPI RefUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + if(!IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef(iface); + *ppv = iface; + return S_OK; +} + +static ULONG WINAPI RefUnk_AddRef(IUnknown *iface) +{ + RefUnk *This = impl_from_IUnknown(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI RefUnk_Release(IUnknown *iface) +{ + RefUnk *This = impl_from_IUnknown(iface); + return InterlockedDecrement(&This->ref); +} + +static const IUnknownVtbl RefUnkVtbl = { + RefUnk_QueryInterface, + RefUnk_AddRef, + RefUnk_Release +}; + +static RefUnk unk_in = {{&RefUnkVtbl}}, unk_out = {{&RefUnkVtbl}}; + +static HANDLE thread_ready; + +static DWORD WINAPI bsc_thread(void *arg) +{ + IStream *stream = arg; + LARGE_INTEGER zero; + MSG msg; + HRESULT hres; + + CoInitialize(NULL); + + hres = CoMarshalInterface(stream, &IID_IBindStatusCallback, (IUnknown*)&BindStatusCallback, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok(hres == S_OK, "CoMarshalInterface failed: %08x\n", hres); + + zero.QuadPart = 0; + hres = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); + ok(hres == S_OK, "Seek failed: 0x%08x\n", hres); + + SetEvent(thread_ready); + + while(GetMessageW(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + CoUninitialize(); + return 0; +} + +static void test_bsc_marshaling(void) +{ + FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM}; + IBindStatusCallbackEx *callbackex; + IBindStatusCallback *bsc; + BINDINFO bindinfo; + IStream *stream, *binding_stream; + HANDLE thread; + WCHAR *extra_info_out; + WCHAR *verb_out; + LARGE_INTEGER zero; + STGMEDIUM stgmed; + void *buf; + DWORD bindf; + HRESULT hres; + + hres = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hres == S_OK, "CreateStreamOnHGlobal returned: %08x\n", hres); + + thread_ready = CreateEventW(NULL, TRUE, FALSE, NULL); + thread = CreateThread(NULL, 0, bsc_thread, stream, 0, NULL); + WaitForSingleObject(thread_ready, INFINITE); + + hres = CoUnmarshalInterface(stream, &IID_IBindStatusCallback, (void**)&bsc); + ok(hres == S_OK, "CoUnmarshalInterface failed: %08x\n", hres); + + hres = CreateStreamOnHGlobal(NULL, TRUE, &binding_stream); + ok(hres == S_OK, "CreateStreamOnHGlobal returned: %08x\n", hres); + hres = IStream_Write(binding_stream, "xxx", 3, NULL); + ok(hres == S_OK, "Write failed: %08x\n", hres); + + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + bindinfo.grfBindInfoF = 12; + bindinfo.dwBindVerb = 13; + bindinfo.cbstgmedData = 19; + bindinfo.dwOptions = 14; + bindinfo.dwOptionsFlags = 15; + bindinfo.dwCodePage = 16; + bindinfo.securityAttributes.nLength = 30; + bindinfo.securityAttributes.lpSecurityDescriptor = (void*)0xdead0001; + bindinfo.securityAttributes.bInheritHandle = 31; + bindinfo.iid.Data1 = 17; + bindinfo.pUnk = (IUnknown*)0xdeadbeef; + bindinfo.dwReserved = 18; + bindinfo.stgmedData.pUnkForRelease = &unk_in.IUnknown_iface; + unk_in.ref = 1; + + memset(&rem_bindinfo, 0, sizeof(bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + rem_bindinfo.szExtraInfo = extra_info_out = a2co("extra info out"); + rem_bindinfo.grfBindInfoF = 22; + rem_bindinfo.dwBindVerb = 23; + rem_bindinfo.szCustomVerb = verb_out = a2co("custom verb out"); + rem_bindinfo.cbstgmedData = 29; + rem_bindinfo.dwOptions = 24; + rem_bindinfo.dwOptionsFlags = 25; + rem_bindinfo.dwCodePage = 16; + rem_bindinfo.securityAttributes.nLength = 40; + rem_bindinfo.securityAttributes.lpSecurityDescriptor = (void*)0xdead0002; + rem_bindinfo.securityAttributes.bInheritHandle = 41; + rem_bindinfo.iid.Data1 = 27; + rem_bindinfo.pUnk = (IUnknown*)0xdeadbeef; + rem_bindinfo.dwReserved = 18; + rem_bindinfo.stgmedData.pUnkForRelease = &unk_out.IUnknown_iface; + unk_out.ref = 1; + + hres = IBindStatusCallback_GetBindInfo(bsc, &bindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.szExtraInfo, "szExtraInfo = %s\n", wine_dbgstr_w(in_bindinfo.szExtraInfo)); + ok(in_bindinfo.grfBindInfoF == 12, "cbSize = %u\n", in_bindinfo.grfBindInfoF); + ok(in_bindinfo.dwBindVerb == 13, "dwBindVerb = %u\n", in_bindinfo.dwBindVerb); + ok(!in_bindinfo.szCustomVerb, "szCustomVerb = %s\n", wine_dbgstr_w(in_bindinfo.szCustomVerb)); + ok(in_bindinfo.cbstgmedData == 19, "cbstgmedData = %u\n", in_bindinfo.cbstgmedData); + ok(!in_bindinfo.dwOptions, "dwOptions = %u\n", in_bindinfo.dwOptions); + ok(!in_bindinfo.dwOptionsFlags, "dwOptionsFlags = %u\n", in_bindinfo.dwOptionsFlags); + ok(!in_bindinfo.dwCodePage, "dwCodePage = %u\n", in_bindinfo.dwCodePage); + ok(!in_bindinfo.iid.Data1, "iid.Data1 = %u\n", in_bindinfo.iid.Data1); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(!in_bindinfo.dwReserved, "dwReserved = %u\n", in_bindinfo.dwReserved); + ok(!in_bindinfo.securityAttributes.nLength, "securityAttributes.nLength = %u\n", + in_bindinfo.securityAttributes.nLength); + ok(!in_bindinfo.securityAttributes.lpSecurityDescriptor, + "securityAttributes.lpSecurityDescriptor = %p\n", + in_bindinfo.securityAttributes.lpSecurityDescriptor); + ok(!in_bindinfo.securityAttributes.bInheritHandle, "securityAttributes.bInheritHandle = %u\n", + in_bindinfo.securityAttributes.bInheritHandle); + ok(!in_bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + in_bindinfo.stgmedData.pUnkForRelease); + + ok(bindinfo.cbSize == sizeof(rem_bindinfo), "cbSize = %u\n", rem_bindinfo.cbSize); + ok(!strcmp_wa(bindinfo.szExtraInfo, "extra info out"), + "szExtraInfo = %s\n", wine_dbgstr_w(bindinfo.szExtraInfo)); + ok(bindinfo.grfBindInfoF == 22, "grfBindInfoF = %u\n", rem_bindinfo.grfBindInfoF); + ok(bindinfo.dwBindVerb == 23, "dwBindVerb = %u\n", bindinfo.dwBindVerb); + ok(bindinfo.szCustomVerb != verb_out, "szCustomVerb == inbuf\n"); + ok(!strcmp_wa(bindinfo.szCustomVerb, "custom verb out"), "szCustomVerb = %s\n", + wine_dbgstr_w(bindinfo.szCustomVerb)); + ok(bindinfo.cbstgmedData == 29, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + ok(bindinfo.dwOptions == 24, "dwOptions = %u\n", bindinfo.dwOptions); + ok(bindinfo.dwOptionsFlags == 25, "dwOptionsFlags = %u\n", bindinfo.dwOptionsFlags); + ok(bindinfo.dwCodePage, "dwCodePage = %u\n", bindinfo.dwCodePage); + ok(!bindinfo.iid.Data1, "iid.Data1 = %u\n", bindinfo.iid.Data1); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.dwReserved == 18, "dwReserved = %u\n", bindinfo.dwReserved); + ok(bindinfo.securityAttributes.nLength == 30, "securityAttributes.nLength = %u\n", + bindinfo.securityAttributes.nLength); + ok(bindinfo.securityAttributes.lpSecurityDescriptor == (void*)0xdead0001, + "securityAttributes.lpSecurityDescriptor = %p\n", + bindinfo.securityAttributes.lpSecurityDescriptor); + ok(bindinfo.securityAttributes.bInheritHandle == 31, "securityAttributes.bInheritHandle = %u\n", + bindinfo.securityAttributes.bInheritHandle); + ok(bindinfo.stgmedData.pUnkForRelease == &unk_in.IUnknown_iface, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(unk_out.ref == 1, "unk_out.ref = %u\n", unk_out.ref); + + bindinfo.stgmedData.pUnkForRelease = NULL; + ReleaseBindInfo(&bindinfo); + + zero.QuadPart = 0; + hres = IStream_Seek(binding_stream, zero, STREAM_SEEK_SET, NULL); + ok(hres == S_OK, "Seek failed: 0x%08x\n", hres); + + /* Return IStream stgmed from GetBindInfo, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_ISTREAM; + rem_bindinfo.stgmedData.u.pstm = binding_stream; + rem_bindinfo.cbstgmedData = 3; + IStream_AddRef(binding_stream); + + hres = IBindStatusCallback_GetBindInfo(bsc, &bindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 3, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + /* Same, but with pUnkForRelease, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_ISTREAM; + rem_bindinfo.stgmedData.u.pstm = binding_stream; + rem_bindinfo.stgmedData.pUnkForRelease = &unk_out.IUnknown_iface; + unk_out.ref = 1; + rem_bindinfo.cbstgmedData = 3; + IStream_AddRef(binding_stream); + + hres = IBindStatusCallback_GetBindInfo(bsc, &bindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 3, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + /* Return HGLOBAL stgmed from GetBindInfo, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_HGLOBAL; + + buf = GlobalAlloc(0, sizeof(5)); + strcpy(buf, "test"); + rem_bindinfo.stgmedData.u.hGlobal = buf; + rem_bindinfo.cbstgmedData = 5; + + hres = IBindStatusCallback_GetBindInfo(bsc, &bindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 5, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + /* Same with GetBindInfoEx */ + hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackEx, (void**)&callbackex); + if(SUCCEEDED(hres)) { + DWORD bindf2, reserved; + + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = bindf2 = reserved = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + bindinfo.grfBindInfoF = 12; + bindinfo.dwBindVerb = 13; + bindinfo.cbstgmedData = 19; + bindinfo.dwOptions = 14; + bindinfo.dwOptionsFlags = 15; + bindinfo.dwCodePage = 16; + bindinfo.securityAttributes.nLength = 30; + bindinfo.securityAttributes.lpSecurityDescriptor = (void*)0xdead0001; + bindinfo.securityAttributes.bInheritHandle = 31; + bindinfo.iid.Data1 = 17; + bindinfo.pUnk = (IUnknown*)0xdeadbeef; + bindinfo.dwReserved = 18; + bindinfo.stgmedData.pUnkForRelease = &unk_in.IUnknown_iface; + unk_in.ref = 1; + + memset(&rem_bindinfo, 0, sizeof(bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + rem_bindinfo.szExtraInfo = extra_info_out = a2co("extra info out"); + rem_bindinfo.grfBindInfoF = 22; + rem_bindinfo.dwBindVerb = 23; + rem_bindinfo.szCustomVerb = verb_out = a2co("custom verb out"); + rem_bindinfo.cbstgmedData = 29; + rem_bindinfo.dwOptions = 24; + rem_bindinfo.dwOptionsFlags = 25; + rem_bindinfo.dwCodePage = 16; + rem_bindinfo.securityAttributes.nLength = 40; + rem_bindinfo.securityAttributes.lpSecurityDescriptor = (void*)0xdead0002; + rem_bindinfo.securityAttributes.bInheritHandle = 41; + rem_bindinfo.iid.Data1 = 27; + rem_bindinfo.pUnk = (IUnknown*)0xdeadbeef; + rem_bindinfo.dwReserved = 18; + rem_bindinfo.stgmedData.pUnkForRelease = &unk_out.IUnknown_iface; + unk_out.ref = 1; + + hres = IBindStatusCallbackEx_GetBindInfoEx(callbackex, &bindf, &bindinfo, &bindf2, &reserved); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + ok(bindf2 == 11, "bindf2 = %x\n", bindf); + ok(reserved == 12, "reserved = %x\n", reserved); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.szExtraInfo, "szExtraInfo = %s\n", wine_dbgstr_w(in_bindinfo.szExtraInfo)); + ok(in_bindinfo.grfBindInfoF == 12, "cbSize = %u\n", in_bindinfo.grfBindInfoF); + ok(in_bindinfo.dwBindVerb == 13, "dwBindVerb = %u\n", in_bindinfo.dwBindVerb); + ok(!in_bindinfo.szCustomVerb, "szCustomVerb = %s\n", wine_dbgstr_w(in_bindinfo.szCustomVerb)); + ok(in_bindinfo.cbstgmedData == 19, "cbstgmedData = %u\n", in_bindinfo.cbstgmedData); + ok(!in_bindinfo.dwOptions, "dwOptions = %u\n", in_bindinfo.dwOptions); + ok(!in_bindinfo.dwOptionsFlags, "dwOptionsFlags = %u\n", in_bindinfo.dwOptionsFlags); + ok(!in_bindinfo.dwCodePage, "dwCodePage = %u\n", in_bindinfo.dwCodePage); + ok(!in_bindinfo.iid.Data1, "iid.Data1 = %u\n", in_bindinfo.iid.Data1); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(!in_bindinfo.dwReserved, "dwReserved = %u\n", in_bindinfo.dwReserved); + ok(!in_bindinfo.securityAttributes.nLength, "securityAttributes.nLength = %u\n", + in_bindinfo.securityAttributes.nLength); + ok(!in_bindinfo.securityAttributes.lpSecurityDescriptor, + "securityAttributes.lpSecurityDescriptor = %p\n", + in_bindinfo.securityAttributes.lpSecurityDescriptor); + ok(!in_bindinfo.securityAttributes.bInheritHandle, "securityAttributes.bInheritHandle = %u\n", + in_bindinfo.securityAttributes.bInheritHandle); + ok(!in_bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + in_bindinfo.stgmedData.pUnkForRelease); + + ok(bindinfo.cbSize == sizeof(rem_bindinfo), "cbSize = %u\n", rem_bindinfo.cbSize); + ok(!strcmp_wa(bindinfo.szExtraInfo, "extra info out"), + "szExtraInfo = %s\n", wine_dbgstr_w(bindinfo.szExtraInfo)); + ok(bindinfo.grfBindInfoF == 22, "grfBindInfoF = %u\n", rem_bindinfo.grfBindInfoF); + ok(bindinfo.dwBindVerb == 23, "dwBindVerb = %u\n", bindinfo.dwBindVerb); + ok(bindinfo.szCustomVerb != verb_out, "szCustomVerb == inbuf\n"); + ok(!strcmp_wa(bindinfo.szCustomVerb, "custom verb out"), "szCustomVerb = %s\n", + wine_dbgstr_w(bindinfo.szCustomVerb)); + ok(bindinfo.cbstgmedData == 29, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + ok(bindinfo.dwOptions == 24, "dwOptions = %u\n", bindinfo.dwOptions); + ok(bindinfo.dwOptionsFlags == 25, "dwOptionsFlags = %u\n", bindinfo.dwOptionsFlags); + ok(bindinfo.dwCodePage, "dwCodePage = %u\n", bindinfo.dwCodePage); + ok(!bindinfo.iid.Data1, "iid.Data1 = %u\n", bindinfo.iid.Data1); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.dwReserved == 18, "dwReserved = %u\n", bindinfo.dwReserved); + ok(bindinfo.securityAttributes.nLength == 30, "securityAttributes.nLength = %u\n", + bindinfo.securityAttributes.nLength); + ok(bindinfo.securityAttributes.lpSecurityDescriptor == (void*)0xdead0001, + "securityAttributes.lpSecurityDescriptor = %p\n", + bindinfo.securityAttributes.lpSecurityDescriptor); + ok(bindinfo.securityAttributes.bInheritHandle == 31, "securityAttributes.bInheritHandle = %u\n", + bindinfo.securityAttributes.bInheritHandle); + ok(bindinfo.stgmedData.pUnkForRelease == &unk_in.IUnknown_iface, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(unk_out.ref == 1, "unk_out.ref = %u\n", unk_out.ref); + + bindinfo.stgmedData.pUnkForRelease = NULL; + ReleaseBindInfo(&bindinfo); + + zero.QuadPart = 0; + hres = IStream_Seek(binding_stream, zero, STREAM_SEEK_SET, NULL); + ok(hres == S_OK, "Seek failed: 0x%08x\n", hres); + + /* Return IStream stgmed from GetBindInfoEx, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = bindf2 = reserved = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_ISTREAM; + rem_bindinfo.stgmedData.u.pstm = binding_stream; + rem_bindinfo.cbstgmedData = 3; + IStream_AddRef(binding_stream); + + hres = IBindStatusCallbackEx_GetBindInfoEx(callbackex, &bindf, &bindinfo, &bindf2, &reserved); + ok(hres == S_OK, "GetBindInfoEx failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 3, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + /* Same, but with pUnkForRelease, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = bindf2 = reserved = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_ISTREAM; + rem_bindinfo.stgmedData.u.pstm = binding_stream; + rem_bindinfo.stgmedData.pUnkForRelease = &unk_out.IUnknown_iface; + unk_out.ref = 1; + rem_bindinfo.cbstgmedData = 3; + IStream_AddRef(binding_stream); + + hres = IBindStatusCallbackEx_GetBindInfoEx(callbackex, &bindf, &bindinfo, &bindf2, &reserved); + ok(hres == S_OK, "GetBindInfoEx failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 3, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + /* Return HGLOBAL stgmed from GetBindInfoEx, it's not marshaled back */ + rem_bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + bindf = bindf2 = reserved = 0xdeadbeef; + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + + memset(&rem_bindinfo, 0, sizeof(rem_bindinfo)); + rem_bindinfo.cbSize = sizeof(rem_bindinfo); + + rem_bindinfo.stgmedData.tymed = TYMED_HGLOBAL; + + buf = GlobalAlloc(0, sizeof(5)); + strcpy(buf, "test"); + rem_bindinfo.stgmedData.u.hGlobal = buf; + rem_bindinfo.cbstgmedData = 5; + + hres = IBindStatusCallbackEx_GetBindInfoEx(callbackex, &bindf, &bindinfo, &bindf2, &reserved); + ok(hres == S_OK, "GetBindInfoEx failed: %08x\n", hres); + ok(bindf == rem_bindf, "bindf = %x, expected %x\n", bindf, rem_bindf); + + ok(in_bindinfo.cbSize == sizeof(in_bindinfo), "cbSize = %u\n", in_bindinfo.cbSize); + ok(!in_bindinfo.pUnk, "pUnk = %p\n", in_bindinfo.pUnk); + ok(in_bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + in_bindinfo.stgmedData.tymed); + + ok(bindinfo.cbSize == sizeof(bindinfo), "cbSize = %u\n", bindinfo.cbSize); + ok(!bindinfo.pUnk, "pUnk = %p\n", bindinfo.pUnk); + ok(bindinfo.stgmedData.tymed == TYMED_NULL, "tymed = %u\n", + bindinfo.stgmedData.tymed); + ok(!bindinfo.stgmedData.u.pstm, "stm = %p\n", + bindinfo.stgmedData.u.pstm); + ok(!bindinfo.stgmedData.pUnkForRelease, "pUnkForRelease = %p\n", + bindinfo.stgmedData.pUnkForRelease); + ok(bindinfo.cbstgmedData == 5, "cbstgmedData = %u\n", bindinfo.cbstgmedData); + + ReleaseBindInfo(&bindinfo); + + IBindStatusCallbackEx_Release(callbackex); + }else { + win_skip("IBindStatusCallbackEx not supported\n"); + } + + /* Test marshaling stgmed from OnDataAvailable */ + memset(&in_stgmed, 0xcc, sizeof(in_stgmed)); + stgmed.tymed = TYMED_ISTREAM; + stgmed.u.pstm = binding_stream; + stgmed.pUnkForRelease = NULL; + + hres = IBindStatusCallback_OnDataAvailable(bsc, 1, 10, &formatetc, &stgmed); + ok(hres == S_OK, "OnDataAvailable failed: %08x\n", hres); + + ok(in_stgmed.tymed == TYMED_ISTREAM, "tymed = %u\n", in_stgmed.tymed); + ok(in_stgmed.u.pstm != NULL, "pstm = NULL\n"); + ok(!in_stgmed.pUnkForRelease, "pUnkForRelease = %p\n", in_stgmed.pUnkForRelease); + + /* OnDataAvailable with both IStream and pUnkForRelease */ + memset(&in_stgmed, 0xcc, sizeof(in_stgmed)); + stgmed.tymed = TYMED_ISTREAM; + stgmed.u.pstm = binding_stream; + stgmed.pUnkForRelease = &unk_in.IUnknown_iface; + unk_in.ref = 1; + + hres = IBindStatusCallback_OnDataAvailable(bsc, 1, 10, &formatetc, &stgmed); + ok(hres == S_OK, "OnDataAvailable failed: %08x\n", hres); + + ok(in_stgmed.tymed == TYMED_ISTREAM, "tymed = %u\n", in_stgmed.tymed); + ok(in_stgmed.u.pstm != NULL, "pstm = NULL\n"); + ok(in_stgmed.pUnkForRelease != NULL, "pUnkForRelease = %p\n", in_stgmed.pUnkForRelease); + ok(unk_in.ref > 1, "ref = %u\n", unk_in.ref); + + /* OnDataAvailable with TYMED_ISTREAM, but NULL stream */ + memset(&in_stgmed, 0xcc, sizeof(in_stgmed)); + stgmed.tymed = TYMED_ISTREAM; + stgmed.u.pstm = binding_stream; + stgmed.pUnkForRelease = NULL; + + hres = IBindStatusCallback_OnDataAvailable(bsc, 1, 10, &formatetc, &stgmed); + ok(hres == S_OK, "OnDataAvailable failed: %08x\n", hres); + + ok(in_stgmed.tymed == TYMED_ISTREAM, "tymed = %u\n", in_stgmed.tymed); + ok(in_stgmed.u.pstm != NULL, "pstm = NULL\n"); + ok(!in_stgmed.pUnkForRelease, "pUnkForRelease = %p\n", in_stgmed.pUnkForRelease); + + /* OnDataAvailable with TYMED_NULL and pUnkForRelease */ + memset(&in_stgmed, 0xcc, sizeof(in_stgmed)); + stgmed.tymed = TYMED_NULL; + stgmed.u.pstm = binding_stream; + stgmed.pUnkForRelease = &unk_in.IUnknown_iface; + unk_in.ref = 1; + + hres = IBindStatusCallback_OnDataAvailable(bsc, 1, 10, &formatetc, &stgmed); + ok(hres == S_OK, "OnDataAvailable failed: %08x\n", hres); + + ok(in_stgmed.tymed == TYMED_NULL, "tymed = %u\n", in_stgmed.tymed); + ok(!in_stgmed.u.pstm, "pstm != NULL\n"); + ok(in_stgmed.pUnkForRelease != NULL, "pUnkForRelease = %p\n", in_stgmed.pUnkForRelease); + ok(unk_in.ref == 1, "ref = %u\n", unk_in.ref); + + IStream_Release(binding_stream); + IBindStatusCallback_Release(bsc); + + TerminateThread(thread, 0); +} + START_TEST(misc) { HMODULE hurlmon; @@ -1975,6 +2697,7 @@ START_TEST(misc) test_user_agent(); test_MkParseDisplayNameEx(); test_IsValidURL(); + test_bsc_marshaling(); } test_internet_features(); -- 2.11.4.GIT