https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a6cdf4ff0885008788ea2…
commit a6cdf4ff0885008788ea2ea876a14edad7fd512e
Author: Amine Khaldi <amine.khaldi(a)reactos.org>
AuthorDate: Mon Jun 4 03:46:11 2018 +0100
Commit: Amine Khaldi <amine.khaldi(a)reactos.org>
CommitDate: Mon Jun 4 03:46:11 2018 +0100
[OLE32_WINETEST] Sync with Wine Staging 3.9. CORE-14656
---
modules/rostests/winetests/ole32/compobj.c | 293 +++++----------
modules/rostests/winetests/ole32/marshal.c | 573 +++++++++++++++++++++++++++--
modules/rostests/winetests/ole32/ole2.c | 116 +++++-
3 files changed, 759 insertions(+), 223 deletions(-)
diff --git a/modules/rostests/winetests/ole32/compobj.c
b/modules/rostests/winetests/ole32/compobj.c
index 06d1914240..aedbc08f07 100644
--- a/modules/rostests/winetests/ole32/compobj.c
+++ b/modules/rostests/winetests/ole32/compobj.c
@@ -608,28 +608,8 @@ static void test_StringFromGUID2(void)
ok(len == 0, "len: %d (expected 0)\n", len);
}
-struct info
-{
- HANDLE wait, stop;
-};
-
-static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
-{
- HRESULT hr;
- struct info *info = pv;
-
- hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
-
- SetEvent(info->wait);
- WaitForSingleObject(info->stop, 10000);
-
- CoUninitialize();
- return hr;
-}
-
-#define test_apt_type(t, q, t_t, t_q) _test_apt_type(t, q, t_t, t_q, __LINE__)
-static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier,
BOOL todo_type,
- BOOL todo_qualifier, int line)
+#define test_apt_type(t, q) _test_apt_type(t, q, __LINE__)
+static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier,
int line)
{
APTTYPEQUALIFIER qualifier = ~0u;
APTTYPE type = ~0u;
@@ -640,9 +620,7 @@ static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER
expected_qual
hr = pCoGetApartmentType(&type, &qualifier);
ok_(__FILE__, line)(hr == S_OK || hr == CO_E_NOTINITIALIZED, "Unexpected return
code: 0x%08x\n", hr);
-todo_wine_if(todo_type)
ok_(__FILE__, line)(type == expected_type, "Wrong apartment type %d, expected
%d\n", type, expected_type);
-todo_wine_if(todo_qualifier)
ok_(__FILE__, line)(qualifier == expected_qualifier, "Wrong apartment qualifier
%d, expected %d\n", qualifier,
expected_qualifier);
}
@@ -650,10 +628,7 @@ todo_wine_if(todo_qualifier)
static void test_CoCreateInstance(void)
{
HRESULT hr;
- HANDLE thread;
- DWORD tid, exitcode;
IUnknown *pUnk;
- struct info info;
REFCLSID rclsid = &CLSID_InternetZoneManager;
pUnk = (IUnknown *)0xdeadbeef;
@@ -688,51 +663,15 @@ static void test_CoCreateInstance(void)
hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void
**)&pUnk);
ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned
CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
- /* show that COM doesn't have to be initialized for multi-threaded apartments if
another
- thread has already done so */
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.wait != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.stop != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
- ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
-
- ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
-
- test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
-
- pUnk = (IUnknown *)0xdeadbeef;
- hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void
**)&pUnk);
- ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of
0x%08x\n", hr);
- if (pUnk) IUnknown_Release(pUnk);
-
- SetEvent(info.stop);
- ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
-
- GetExitCodeThread(thread, &exitcode);
- hr = exitcode;
- ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n",
hr);
-
- CloseHandle(thread);
- CloseHandle(info.wait);
- CloseHandle(info.stop);
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
+ test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
}
static void test_CoGetClassObject(void)
{
HRESULT hr;
- HANDLE thread, handle;
- DWORD tid, exitcode;
+ HANDLE handle;
ULONG_PTR cookie;
IUnknown *pUnk;
- struct info info;
REFCLSID rclsid = &CLSID_InternetZoneManager;
HKEY hkey;
LONG res;
@@ -746,46 +685,7 @@ static void test_CoGetClassObject(void)
broken(hr == CO_E_NOTINITIALIZED), /* win9x */
"CoGetClassObject should have returned E_INVALIDARG instead of
0x%08x\n", hr);
- /* show that COM doesn't have to be initialized for multi-threaded apartments if
another
- thread has already done so */
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.wait != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.stop != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
- ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
-
- ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
-
- test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
-
- pUnk = (IUnknown *)0xdeadbeef;
- hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void
**)&pUnk);
- if(hr == REGDB_E_CLASSNOTREG)
- skip("IE not installed so can't test CoGetClassObject\n");
- else
- {
- ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of
0x%08x\n", hr);
- if (pUnk) IUnknown_Release(pUnk);
- }
-
- SetEvent(info.stop);
- ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
-
- GetExitCodeThread(thread, &exitcode);
- hr = exitcode;
- ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n",
hr);
-
- CloseHandle(thread);
- CloseHandle(info.wait);
- CloseHandle(info.stop);
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
+ test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
if (!pRegOverridePredefKey)
{
@@ -1886,9 +1786,6 @@ static void test_CoGetObjectContext(void)
IObjContext *pObjContext;
APTTYPE apttype;
THDTYPE thdtype;
- struct info info;
- HANDLE thread;
- DWORD tid, exitcode;
GUID id, id2;
if (!pCoGetObjectContext)
@@ -1901,27 +1798,12 @@ static void test_CoGetObjectContext(void)
ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned
CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to
NULL\n");
- /* show that COM doesn't have to be initialized for multi-threaded apartments if
another
- thread has already done so */
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.wait != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.stop != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
- ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
-
- ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
+ pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
+ test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
- pComThreadingInfo = NULL;
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void
**)&pComThreadingInfo);
- ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
+ ok_ole_success(hr, "CoGetObjectContext");
threadinginfo2 = NULL;
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&threadinginfo2);
@@ -1939,28 +1821,6 @@ static void test_CoGetObjectContext(void)
hr = CoGetCurrentLogicalThreadId(&id2);
ok(IsEqualGUID(&id, &id2), "got %s, expected %s\n",
wine_dbgstr_guid(&id), wine_dbgstr_guid(&id2));
- IComThreadingInfo_Release(pComThreadingInfo);
-
- SetEvent(info.stop);
- ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
-
- GetExitCodeThread(thread, &exitcode);
- hr = exitcode;
- ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n",
hr);
-
- CloseHandle(thread);
- CloseHandle(info.wait);
- CloseHandle(info.stop);
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-
- test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void
**)&pComThreadingInfo);
- ok_ole_success(hr, "CoGetObjectContext");
-
hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead
of %d\n", apttype);
@@ -2124,9 +1984,6 @@ static void test_CoGetContextToken(void)
ULONG refs;
ULONG_PTR token, token2;
IObjContext *ctx;
- struct info info;
- HANDLE thread;
- DWORD tid, exitcode;
if (!pCoGetContextToken)
{
@@ -2139,49 +1996,11 @@ static void test_CoGetContextToken(void)
ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n",
hr);
ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
- /* show that COM doesn't have to be initialized for multi-threaded apartments if
another
- thread has already done so */
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
-
- info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.wait != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
- ok(info.stop != NULL, "CreateEvent failed with error %d\n",
GetLastError());
-
- thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
- ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
-
- ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
-
- test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
-
- token = 0;
- hr = pCoGetContextToken(&token);
- ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
-
- token2 = 0;
- hr = pCoGetContextToken(&token2);
- ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
- ok(token == token2, "got different token\n");
-
- SetEvent(info.stop);
- ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
-
- GetExitCodeThread(thread, &exitcode);
- hr = exitcode;
- ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n",
hr);
-
- CloseHandle(thread);
- CloseHandle(info.wait);
- CloseHandle(info.stop);
-
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
+ test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
CoInitialize(NULL);
- test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
+ test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
hr = pCoGetContextToken(NULL);
ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
@@ -3185,14 +3004,36 @@ static void test_CoWaitForMultipleHandles(void)
ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
CloseHandle(thread);
+ CoUninitialize();
+
+ /* If COM was not initialized, messages are neither pumped nor peeked at */
+ PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
+ hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
+ ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr);
+ success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE,
MWMO_ALERTABLE);
+ ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success);
+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
+ ok(success, "PeekMessage failed: %u\n", GetLastError());
+
+ /* same in an MTA */
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
+ hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
+ ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr);
+ success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE,
MWMO_ALERTABLE);
+ ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success);
+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
+ ok(success, "PeekMessage failed: %u\n", GetLastError());
+
+ CoUninitialize();
+
CloseHandle(handles[0]);
CloseHandle(handles[1]);
DestroyWindow(hWnd);
success = UnregisterClassA(cls_name, GetModuleHandleA(0));
ok(success, "UnregisterClass failed %u\n", GetLastError());
-
- CoUninitialize();
}
static void test_CoGetMalloc(void)
@@ -3880,6 +3721,71 @@ static void init_funcs(void)
pReleaseActCtx = (void*)GetProcAddress(hkernel32, "ReleaseActCtx");
}
+static DWORD CALLBACK implicit_mta_proc(void *param)
+{
+ IComThreadingInfo *threading_info;
+ ULONG_PTR token;
+ IUnknown *unk;
+ DWORD cookie;
+ CLSID clsid;
+ HRESULT hr;
+
+ test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA);
+
+ hr = CoCreateInstance(&CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER,
&IID_IUnknown, (void **)&unk);
+ ok_ole_success(hr, "CoCreateInstance");
+ IUnknown_Release(unk);
+
+ hr = CoGetClassObject(&CLSID_InternetZoneManager, CLSCTX_INPROC_SERVER, NULL,
&IID_IUnknown, (void **)&unk);
+ ok_ole_success(hr, "CoGetClassObject");
+ IUnknown_Release(unk);
+
+ hr = CoGetObjectContext(&IID_IComThreadingInfo, (void **)&threading_info);
+ ok_ole_success(hr, "CoGetObjectContext");
+ IComThreadingInfo_Release(threading_info);
+
+ hr = CoGetContextToken(&token);
+ ok_ole_success(hr, "CoGetContextToken");
+
+ hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
+ ok_ole_success(hr, "CoRegisterPSClsid");
+
+ hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
+ ok_ole_success(hr, "CoGetPSClsid");
+
+ hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown
*)&Test_ClassFactory,
+ CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
+ ok_ole_success(hr, "CoRegisterClassObject");
+
+ hr = CoRevokeClassObject(cookie);
+ ok_ole_success(hr, "CoRevokeClassObject");
+
+ hr = CoRegisterMessageFilter(NULL, NULL);
+ ok(hr == CO_E_NOT_SUPPORTED, "got %#x\n", hr);
+
+ hr = CoLockObjectExternal((IUnknown *)&Test_Unknown, TRUE, TRUE);
+ ok_ole_success(hr, "CoLockObjectExternal");
+
+ hr = CoDisconnectObject((IUnknown *)&Test_Unknown, 0);
+ ok_ole_success(hr, "CoDisconnectObject");
+
+ return 0;
+}
+
+/* Some COM functions (perhaps even all of them?) can make use of an
"implicit"
+ * multi-threaded apartment created by another thread in the same process. */
+static void test_implicit_mta(void)
+{
+ HANDLE thread;
+
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ thread = CreateThread(NULL, 0, implicit_mta_proc, NULL, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
+
+ CoUninitialize();
+}
+
START_TEST(compobj)
{
init_funcs();
@@ -3929,4 +3835,5 @@ START_TEST(compobj)
test_IInitializeSpy();
test_CoGetInstanceFromFile();
test_GlobalOptions();
+ test_implicit_mta();
}
diff --git a/modules/rostests/winetests/ole32/marshal.c
b/modules/rostests/winetests/ole32/marshal.c
index 12c46e92df..1fcf9a392a 100644
--- a/modules/rostests/winetests/ole32/marshal.c
+++ b/modules/rostests/winetests/ole32/marshal.c
@@ -34,10 +34,37 @@
#include "initguid.h"
#include "wine/test.h"
+#include "wine/heap.h"
+
+#define DEFINE_EXPECT(func) \
+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+ expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ called_ ## func = TRUE; \
+ }while(0)
+
+#define CHECK_EXPECT(func) \
+ do { \
+ CHECK_EXPECT2(func); \
+ expect_ ## func = FALSE; \
+ }while(0)
+
+#define CHECK_CALLED(func) \
+ do { \
+ ok(called_ ## func, "expected " #func "\n"); \
+ expect_ ## func = called_ ## func = FALSE; \
+ }while(0)
DEFINE_GUID(CLSID_StdGlobalInterfaceTable,0x00000323,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
DEFINE_GUID(CLSID_ManualResetEvent,
0x0000032c,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12,
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
+
/* functions that are not present on all versions of Windows */
static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
@@ -281,6 +308,253 @@ static const IClassFactoryVtbl TestClassFactory_Vtbl =
static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
+DEFINE_EXPECT(Invoke);
+DEFINE_EXPECT(CreateStub);
+DEFINE_EXPECT(CreateProxy);
+DEFINE_EXPECT(GetWindow);
+DEFINE_EXPECT(Disconnect);
+
+static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void
**ppv)
+{
+ ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
+{
+ CHECK_EXPECT(GetWindow);
+ *hwnd = (HWND)0xdeadbeef;
+ return S_OK;
+}
+
+static const IOleWindowVtbl OleWindowVtbl = {
+ OleWindow_QueryInterface,
+ OleWindow_AddRef,
+ OleWindow_Release,
+ OleWindow_GetWindow,
+ /* not needed */
+};
+
+static IOleWindow Test_OleWindow = { &OleWindowVtbl };
+
+static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid,
void **ppv)
+{
+ if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid,
&IID_IOleClientSite))
+ *ppv = iface;
+ else if (IsEqualGUID(riid, &IID_IOleWindow))
+ *ppv = &Test_OleWindow;
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
+{
+ return 1;
+}
+
+static const IOleClientSiteVtbl OleClientSiteVtbl = {
+ OleClientSite_QueryInterface,
+ OleClientSite_AddRef,
+ OleClientSite_Release,
+ /* we don't need the rest, we never call it */
+};
+
+static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl };
+
+typedef struct {
+ IRpcStubBuffer IRpcStubBuffer_iface;
+ LONG ref;
+ IRpcStubBuffer *buffer;
+} StubBufferWrapper;
+
+static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
+{
+ return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
+}
+
+static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid,
void **ppv)
+{
+ StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
+
+ if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer,
riid)) {
+ *ppv = &This->IRpcStubBuffer_iface;
+ }else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
+{
+ StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface)
+{
+ StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+ if(!ref) {
+ IRpcStubBuffer_Release(This->buffer);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
+{
+ CHECK_EXPECT(Disconnect);
+}
+
+static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE
*_prpcmsg,
+ IRpcChannelBuffer *_pRpcChannelBuffer)
+{
+ StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
+ void *dest_context_data;
+ DWORD dest_context;
+ HRESULT hr;
+
+ CHECK_EXPECT(Invoke);
+
+ hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context,
&dest_context_data);
+ ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr);
+ ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context);
+ ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data);
+
+ return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer);
+}
+
+static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID
riid)
+{
+ ok(0, "unexpected call\n");
+ return NULL;
+}
+
+static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void
**ppv)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv)
+{
+ ok(0, "unexpected call\n");
+}
+
+static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
+ RpcStubBuffer_QueryInterface,
+ RpcStubBuffer_AddRef,
+ RpcStubBuffer_Release,
+ RpcStubBuffer_Connect,
+ RpcStubBuffer_Disconnect,
+ RpcStubBuffer_Invoke,
+ RpcStubBuffer_IsIIDSupported,
+ RpcStubBuffer_CountRefs,
+ RpcStubBuffer_DebugServerQueryInterface,
+ RpcStubBuffer_DebugServerRelease
+};
+
+static IPSFactoryBuffer *ps_factory_buffer;
+
+static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID
riid, void **ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid,
&IID_IPSFactoryBuffer))
+ *ppv = iface;
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown
*outer,
+ REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
+{
+ CHECK_EXPECT(CreateProxy);
+ return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv);
+}
+
+static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid,
+ IUnknown *server, IRpcStubBuffer **ppStub)
+{
+ StubBufferWrapper *stub;
+ HRESULT hr;
+
+ CHECK_EXPECT(CreateStub);
+
+ ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n",
server);
+
+ stub = heap_alloc(sizeof(*stub));
+ stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl;
+ stub->ref = 1;
+
+ hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server,
&stub->buffer);
+ ok(hr == S_OK, "CreateStub failed: %08x\n", hr);
+
+ *ppStub = &stub->IRpcStubBuffer_iface;
+ return S_OK;
+}
+
+static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
+{
+ PSFactoryBuffer_QueryInterface,
+ PSFactoryBuffer_AddRef,
+ PSFactoryBuffer_Release,
+ PSFactoryBuffer_CreateProxy,
+ PSFactoryBuffer_CreateStub
+};
+
+static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
+
#define RELEASEMARSHALDATA WM_USER
struct host_object_data
@@ -289,18 +563,31 @@ struct host_object_data
IID iid;
IUnknown *object;
MSHLFLAGS marshal_flags;
- HANDLE marshal_event;
IMessageFilter *filter;
+ IUnknown *register_object;
+ CLSID register_clsid;
+ HANDLE marshal_event;
};
+#ifndef __REACTOS__ /* FIXME: Inspect */
+static IPSFactoryBuffer PSFactoryBuffer;
+#endif
+
static DWORD CALLBACK host_object_proc(LPVOID p)
{
struct host_object_data *data = p;
+ DWORD registration_key;
HRESULT hr;
MSG msg;
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ if(data->register_object) {
+ hr = CoRegisterClassObject(&data->register_clsid,
data->register_object,
+ CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
+ ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
+ }
+
if (data->filter)
{
IMessageFilter * prev_filter = NULL;
@@ -335,31 +622,27 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
return hr;
}
-static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS
marshal_flags, IMessageFilter *filter, HANDLE *thread)
+static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread)
{
DWORD tid = 0;
- HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
- struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
-
- data->stream = stream;
- data->iid = *riid;
- data->object = object;
- data->marshal_flags = marshal_flags;
- data->marshal_event = marshal_event;
- data->filter = filter;
+ struct host_object_data *data;
+ data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
+ *data = *object_data;
+ data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
*thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
/* wait for marshaling to complete before returning */
- ok( !WaitForSingleObject(marshal_event, 10000), "wait timed out\n" );
- CloseHandle(marshal_event);
+ ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n"
);
+ CloseHandle(data->marshal_event);
return tid;
}
static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS
marshal_flags, HANDLE *thread)
{
- return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
+ struct host_object_data object_data = { stream, *riid, object, marshal_flags };
+ return start_host_object2(&object_data, thread);
}
/* asks thread to release the marshal data because it has to be done by the
@@ -962,6 +1245,75 @@ static void test_marshal_proxy_mta_apartment_shutdown(void)
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
}
+static void test_marshal_channel_buffer(void)
+{
+ DWORD registration_key;
+ IUnknown *proxy = NULL;
+ IOleWindow *ole_window;
+ HWND hwnd;
+ CLSID clsid;
+ DWORD tid;
+ HANDLE thread;
+ HRESULT hr;
+
+ struct host_object_data object_data = { NULL, IID_IOleClientSite,
(IUnknown*)&Test_OleClientSite,
+ MSHLFLAGS_NORMAL, NULL,
(IUnknown*)&PSFactoryBuffer,
+ CLSID_WineTestPSFactoryBuffer };
+
+ cLocks = 0;
+ external_connections = 0;
+
+ hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
+ ok_ole_success(hr, "CoGetPSClsid");
+
+ hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
&IID_IPSFactoryBuffer,
+ (void **)&ps_factory_buffer);
+ ok_ole_success(hr, "CoGetClassObject");
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
+ ok_ole_success(hr, CreateStreamOnHGlobal);
+ tid = start_host_object2(&object_data, &thread);
+
+ IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void
**)&proxy);
+ ok_ole_success(hr, CoUnmarshalInterface);
+ IStream_Release(object_data.stream);
+
+ hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown
*)&PSFactoryBuffer,
+ CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
+ ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
+
+ hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
+ ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
+
+ SET_EXPECT(CreateStub);
+ SET_EXPECT(CreateProxy);
+ hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
+ ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
+ CHECK_CALLED(CreateStub);
+ CHECK_CALLED(CreateProxy);
+
+ SET_EXPECT(Invoke);
+ SET_EXPECT(GetWindow);
+ hr = IOleWindow_GetWindow(ole_window, &hwnd);
+ ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
+ ok(hwnd == (HWND)0xdeadbeef, "hwnd = %p\n", hwnd);
+ CHECK_CALLED(Invoke);
+ CHECK_CALLED(GetWindow);
+
+ IOleWindow_Release(ole_window);
+
+ SET_EXPECT(Disconnect);
+ IUnknown_Release(proxy);
+todo_wine
+ CHECK_CALLED(Disconnect);
+
+ hr = CoRevokeClassObject(registration_key);
+ ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
+
+ end_host_object(tid, thread);
+}
+
struct ncu_params
{
LPSTREAM stream;
@@ -1965,25 +2317,27 @@ static IMessageFilter MessageFilter = { &MessageFilter_Vtbl
};
static void test_message_filter(void)
{
HRESULT hr;
- IStream *pStream = NULL;
IClassFactory *cf = NULL;
DWORD tid;
IUnknown *proxy = NULL;
IMessageFilter *prev_filter = NULL;
HANDLE thread;
+ struct host_object_data object_data = { NULL, IID_IClassFactory,
(IUnknown*)&Test_ClassFactory,
+ MSHLFLAGS_NORMAL, &MessageFilter };
+
cLocks = 0;
- hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
ok_ole_success(hr, CreateStreamOnHGlobal);
- tid = start_host_object2(pStream, &IID_IClassFactory,
(IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
+ tid = start_host_object2(&object_data, &thread);
ok_more_than_one_lock();
- IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
- hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
+ IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void
**)&cf);
ok_ole_success(hr, CoUnmarshalInterface);
- IStream_Release(pStream);
+ IStream_Release(object_data.stream);
ok_more_than_one_lock();
@@ -3419,6 +3773,169 @@ static void test_manualresetevent(void)
ok(!ref, "Got nonzero ref: %d\n", ref);
}
+static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
+{
+ IStream *stream = param;
+ IClassFactory *cf;
+ IUnknown *proxy;
+ HRESULT hr;
+
+ IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
+ ok_ole_success(hr, CoUnmarshalInterface);
+
+ hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
+ ok_ole_success(hr, IClassFactory_CreateInstance);
+
+ IUnknown_Release(proxy);
+
+ /* But if we initialize an STA in this apartment, it becomes the wrong one. */
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
+ ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
+
+ CoUninitialize();
+
+ ok_more_than_one_lock();
+ ok_non_zero_external_conn();
+
+ IClassFactory_Release(cf);
+
+ ok_no_locks();
+ ok_zero_external_conn();
+ ok_last_release_closes(TRUE);
+ return 0;
+}
+
+static DWORD CALLBACK implicit_mta_use_proc(void *param)
+{
+ IClassFactory *cf = param;
+ IUnknown *proxy;
+ HRESULT hr;
+
+ hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
+ ok_ole_success(hr, IClassFactory_CreateInstance);
+
+ IUnknown_Release(proxy);
+
+ /* But if we initialize an STA in this apartment, it becomes the wrong one. */
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
+ ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
+
+ CoUninitialize();
+ return 0;
+}
+
+struct implicit_mta_marshal_data
+{
+ IStream *stream;
+ HANDLE start;
+ HANDLE stop;
+};
+
+static DWORD CALLBACK implicit_mta_marshal_proc(void *param)
+{
+ struct implicit_mta_marshal_data *data = param;
+ HRESULT hr;
+
+ hr = CoMarshalInterface(data->stream, &IID_IClassFactory,
+ (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
+ ok_ole_success(hr, CoMarshalInterface);
+
+ SetEvent(data->start);
+
+ ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n");
+ return 0;
+}
+
+static void test_implicit_mta(void)
+{
+ struct implicit_mta_marshal_data data;
+ HANDLE host_thread, thread;
+ IClassFactory *cf;
+ IUnknown *proxy;
+ IStream *stream;
+ HRESULT hr;
+ DWORD tid;
+
+ cLocks = 0;
+ external_connections = 0;
+
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ /* Firstly: we can unmarshal and use an object while in the implicit MTA. */
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ ok_ole_success(hr, CreateStreamOnHGlobal);
+ tid = start_host_object(stream, &IID_IClassFactory, (IUnknown
*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
+
+ ok_more_than_one_lock();
+ ok_non_zero_external_conn();
+
+ thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
+ CloseHandle(thread);
+
+ IStream_Release(stream);
+ end_host_object(tid, host_thread);
+
+ /* Secondly: we can unmarshal an object into the real MTA and then use it
+ * from the implicit MTA. */
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ ok_ole_success(hr, CreateStreamOnHGlobal);
+ tid = start_host_object(stream, &IID_IClassFactory, (IUnknown
*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
+
+ ok_more_than_one_lock();
+ ok_non_zero_external_conn();
+
+ IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
+ ok_ole_success(hr, CoUnmarshalInterface);
+
+ thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
+ CloseHandle(thread);
+
+ IClassFactory_Release(cf);
+ IStream_Release(stream);
+
+ ok_no_locks();
+ ok_non_zero_external_conn();
+ ok_last_release_closes(TRUE);
+
+ end_host_object(tid, host_thread);
+
+ /* Thirdly: we can marshal an object from the implicit MTA and then
+ * unmarshal it into the real one. */
+ data.start = CreateEventA(NULL, FALSE, FALSE, NULL);
+ data.stop = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream);
+ ok_ole_success(hr, CreateStreamOnHGlobal);
+
+ thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL);
+ ok(!WaitForSingleObject(data.start, 1000), "wait failed\n");
+
+ IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf);
+ ok_ole_success(hr, CoUnmarshalInterface);
+
+ hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
+ ok_ole_success(hr, IClassFactory_CreateInstance);
+
+ IUnknown_Release(proxy);
+
+ SetEvent(data.stop);
+ ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
+ CloseHandle(thread);
+
+ IStream_Release(data.stream);
+
+ CoUninitialize();
+}
+
static const char *debugstr_iid(REFIID riid)
{
static char name[256];
@@ -3692,13 +4209,15 @@ static IChannelHook TestChannelHook = { &TestChannelHookVtbl
};
static void test_channel_hook(void)
{
- IStream *pStream = NULL;
IClassFactory *cf = NULL;
DWORD tid;
IUnknown *proxy = NULL;
HANDLE thread;
HRESULT hr;
+ struct host_object_data object_data = { NULL, IID_IClassFactory,
(IUnknown*)&Test_ClassFactory,
+ MSHLFLAGS_NORMAL, &MessageFilter };
+
hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
ok_ole_success(hr, CoRegisterChannelHook);
@@ -3707,17 +4226,17 @@ static void test_channel_hook(void)
cLocks = 0;
- hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
ok_ole_success(hr, CreateStreamOnHGlobal);
- tid = start_host_object2(pStream, &IID_IClassFactory,
(IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
+ tid = start_host_object2(&object_data, &thread);
server_tid = tid;
ok_more_than_one_lock();
- IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
- hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
+ IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void
**)&cf);
ok_ole_success(hr, CoUnmarshalInterface);
- IStream_Release(pStream);
+ IStream_Release(object_data.stream);
ok_more_than_one_lock();
@@ -3765,6 +4284,7 @@ START_TEST(marshal)
register_test_window();
test_cocreateinstance_proxy();
+ test_implicit_mta();
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
@@ -3802,6 +4322,7 @@ START_TEST(marshal)
with_external_conn = !with_external_conn;
} while (with_external_conn);
+ test_marshal_channel_buffer();
test_hresult_marshaling();
test_proxy_used_in_wrong_thread();
test_message_filter();
diff --git a/modules/rostests/winetests/ole32/ole2.c
b/modules/rostests/winetests/ole32/ole2.c
index 231f9d2531..dd9257dff8 100644
--- a/modules/rostests/winetests/ole32/ole2.c
+++ b/modules/rostests/winetests/ole32/ole2.c
@@ -4082,6 +4082,83 @@ static void check_storage_contents(IStorage *stg, const struct
storage_def *stg_
}
}
+static HRESULT stgmedium_cmp(const STGMEDIUM *med1, STGMEDIUM *med2)
+{
+ BYTE *data1, *data2;
+ ULONG datasize1, datasize2;
+
+ if (med1->tymed != med2->tymed)
+ return E_FAIL;
+
+ if (med1->tymed == TYMED_MFPICT)
+ {
+ METAFILEPICT *mfpict1 = GlobalLock(U(med1)->hMetaFilePict);
+ METAFILEPICT *mfpict2 = GlobalLock(U(med2)->hMetaFilePict);
+
+ datasize1 = GetMetaFileBitsEx(mfpict1->hMF, 0, NULL);
+ datasize2 = GetMetaFileBitsEx(mfpict2->hMF, 0, NULL);
+ if (datasize1 == datasize2)
+ {
+ data1 = HeapAlloc(GetProcessHeap(), 0, datasize1);
+ data2 = HeapAlloc(GetProcessHeap(), 0, datasize2);
+ GetMetaFileBitsEx(mfpict1->hMF, datasize1, data1);
+ GetMetaFileBitsEx(mfpict2->hMF, datasize2, data2);
+ }
+ else return E_FAIL;
+ }
+ else if (med1->tymed == TYMED_ENHMF)
+ {
+ datasize1 = GetEnhMetaFileBits(med1->hEnhMetaFile, 0, NULL);
+ datasize2 = GetEnhMetaFileBits(med2->hEnhMetaFile, 0, NULL);
+ if (datasize1 == datasize2)
+ {
+ data1 = HeapAlloc(GetProcessHeap(), 0, datasize1);
+ data2 = HeapAlloc(GetProcessHeap(), 0, datasize2);
+ GetEnhMetaFileBits(med1->hEnhMetaFile, datasize1, data1);
+ GetEnhMetaFileBits(med2->hEnhMetaFile, datasize2, data2);
+ }
+ else return E_FAIL;
+ }
+ else if (med1->tymed == TYMED_HGLOBAL)
+ {
+ datasize1 = GlobalSize(med1->hGlobal);
+ datasize2 = GlobalSize(med2->hGlobal);
+
+ if (datasize1 == datasize2)
+ {
+ data1 = GlobalLock(med1->hGlobal);
+ data2 = GlobalLock(med2->hGlobal);
+ }
+ else
+ return E_FAIL;
+ }
+ else
+ return E_NOTIMPL;
+
+ if (memcmp(data1, data2, datasize1) != 0)
+ return E_FAIL;
+
+ if (med1->tymed == TYMED_HGLOBAL)
+ {
+ GlobalUnlock(U(med1)->hGlobal);
+ GlobalUnlock(U(med2)->hGlobal);
+ }
+ else if (med1->tymed == TYMED_MFPICT)
+ {
+ HeapFree(GetProcessHeap(), 0, data1);
+ HeapFree(GetProcessHeap(), 0, data2);
+ GlobalUnlock(U(med1)->hMetaFilePict);
+ GlobalUnlock(U(med2)->hMetaFilePict);
+ }
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, data1);
+ HeapFree(GetProcessHeap(), 0, data2);
+ }
+
+ return S_OK;
+}
+
static IStorage *create_storage_from_def(const struct storage_def *stg_def)
{
HRESULT hr;
@@ -4254,8 +4331,10 @@ static void test_data_cache_save_data(void)
IStorage *doc;
IOleCache2 *cache;
IPersistStorage *persist;
+ IDataObject *odata;
int enumerated_streams, matched_streams, i;
DWORD dummy;
+ STGMEDIUM stgmeds[MAX_FMTS];
struct tests_data_cache
{
FORMATETC fmts[MAX_FMTS];
@@ -4370,9 +4449,9 @@ static void test_data_cache_save_data(void)
ok(SUCCEEDED(hr), "unexpected %#x\n", hr);
if (i < pdata->num_set)
{
- get_stgmedium(pdata->fmts[i].cfFormat, &stgmed);
- get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat,
&stgmed, i);
- hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmed,
TRUE);
+ get_stgmedium(pdata->fmts[i].cfFormat, &stgmeds[i]);
+ get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat,
&stgmeds[i], i);
+ hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmeds[i],
FALSE);
ok(hr == S_OK, "unexpected %#x\n", hr);
}
}
@@ -4403,12 +4482,41 @@ static void test_data_cache_save_data(void)
ok(enumerated_streams == pdata->stg_def.stream_count, "created %d != def
streams %d\n",
enumerated_streams, pdata->stg_def.stream_count);
+ IPersistStorage_Release(persist);
+ IOleCache2_Release(cache);
+
+ /* now test _Load/_GetData using the storage we used for _Save */
+ hr = CreateDataCache(NULL, pdata->clsid, &IID_IOleCache2, (void
**)&cache);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+ hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void
**)&persist);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+
+ hr = IStorage_SetClass(doc, pdata->clsid);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+ trace("IPersistStorage_Load\n");
+ hr = IPersistStorage_Load(persist, doc);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+
+ hr = IOleCache2_QueryInterface(cache, &IID_IDataObject, (void
**)&odata);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
for (i = 0; i < pdata->num_set; i++)
- HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data);
+ {
+ hr = IDataObject_GetData(odata, &pdata->fmts[i], &stgmed);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+ hr = stgmedium_cmp(&stgmeds[i], &stgmed);
+ ok(hr == S_OK, "unexpected %#x\n", hr);
+ ReleaseStgMedium(&stgmed);
+ ReleaseStgMedium(&stgmeds[i]);
+ }
+
+ IDataObject_Release(odata);
IPersistStorage_Release(persist);
IStorage_Release(doc);
IOleCache2_Release(cache);
+ for (i = 0; i < pdata->num_set; i++)
+ HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data);
+
}
}