Author: akhaldi Date: Tue Nov 17 10:31:59 2015 New Revision: 69909
URL: http://svn.reactos.org/svn/reactos?rev=69909&view=rev Log: [OLE32_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
Modified: trunk/rostests/winetests/ole32/compobj.c trunk/rostests/winetests/ole32/marshal.c trunk/rostests/winetests/ole32/moniker.c trunk/rostests/winetests/ole32/ole2.c trunk/rostests/winetests/ole32/propvariant.c trunk/rostests/winetests/ole32/storage32.c trunk/rostests/winetests/ole32/usrmarshal.c
Modified: trunk/rostests/winetests/ole32/compobj.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/compobj.c?... ============================================================================== --- trunk/rostests/winetests/ole32/compobj.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/compobj.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -46,6 +46,32 @@
extern const IID GUID_NULL;
+#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_EXPECT(CreateStub); + /* functions that are not present on all versions of Windows */ static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv); @@ -135,6 +161,7 @@ return 1; /* non-heap-based object */ }
+static IID create_instance_iid; static HRESULT WINAPI Test_IClassFactory_CreateInstance( LPCLASSFACTORY iface, IUnknown *pUnkOuter, @@ -142,6 +169,7 @@ LPVOID *ppvObj) { *ppvObj = NULL; + create_instance_iid = *riid; if (pUnkOuter) return CLASS_E_NOAGGREGATION; return E_NOINTERFACE; } @@ -772,6 +800,30 @@ CoUninitialize(); }
+static void test_CoCreateInstanceEx(void) +{ + MULTI_QI qi_res = { &IID_IMoniker }; + DWORD cookie; + HRESULT hr; + + CoInitialize(NULL); + + hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie); + ok_ole_success(hr, "CoRegisterClassObject"); + + create_instance_iid = IID_NULL; + hr = CoCreateInstanceEx(&CLSID_WineOOPTest, NULL, CLSCTX_INPROC_SERVER, NULL, 1, &qi_res); + ok(hr == E_NOINTERFACE, "CoCreateInstanceEx failed: %08x\n", hr); + ok(IsEqualGUID(&create_instance_iid, qi_res.pIID), "Unexpected CreateInstance iid %s\n", + wine_dbgstr_guid(&create_instance_iid)); + + hr = CoRevokeClassObject(cookie); + ok_ole_success(hr, "CoRevokeClassObject"); + + CoUninitialize(); +} + static ATOM register_dummy_class(void) { WNDCLASSA wc = @@ -912,6 +964,59 @@ CoUninitialize(); }
+static IUnknown Test_Unknown; + +static HRESULT WINAPI EnumOLEVERB_QueryInterface(IEnumOLEVERB *iface, REFIID riid, void **ppv) +{ + return IUnknown_QueryInterface(&Test_Unknown, riid, ppv); +} + +static ULONG WINAPI EnumOLEVERB_AddRef(IEnumOLEVERB *iface) +{ + return 2; +} + +static ULONG WINAPI EnumOLEVERB_Release(IEnumOLEVERB *iface) +{ + return 1; +} + +static HRESULT WINAPI EnumOLEVERB_Next(IEnumOLEVERB *iface, ULONG celt, OLEVERB *rgelt, ULONG *fetched) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumOLEVERB_Skip(IEnumOLEVERB *iface, ULONG celt) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumOLEVERB_Reset(IEnumOLEVERB *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumOLEVERB_Clone(IEnumOLEVERB *iface, IEnumOLEVERB **ppenum) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IEnumOLEVERBVtbl EnumOLEVERBVtbl = { + EnumOLEVERB_QueryInterface, + EnumOLEVERB_AddRef, + EnumOLEVERB_Release, + EnumOLEVERB_Next, + EnumOLEVERB_Skip, + EnumOLEVERB_Reset, + EnumOLEVERB_Clone +}; + +static IEnumOLEVERB EnumOLEVERB = { &EnumOLEVERBVtbl }; + static HRESULT WINAPI Test_IUnknown_QueryInterface( IUnknown *iface, REFIID riid, @@ -919,16 +1024,17 @@ { if (ppvObj == NULL) return E_POINTER;
- if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IWineTest)) - { + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IWineTest)) { *ppvObj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - *ppvObj = NULL; - return E_NOINTERFACE; + }else if(IsEqualIID(riid, &IID_IEnumOLEVERB)) { + *ppvObj = &EnumOLEVERB; + }else { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppvObj); + return S_OK; }
static ULONG WINAPI Test_IUnknown_AddRef(IUnknown *iface) @@ -949,6 +1055,8 @@ };
static IUnknown Test_Unknown = { &TestUnknown_Vtbl }; + +static IPSFactoryBuffer *ps_factory_buffer;
static HRESULT WINAPI PSFactoryBuffer_QueryInterface( IPSFactoryBuffer * This, @@ -993,7 +1101,13 @@ /* [unique][in] */ IUnknown *pUnkServer, /* [out] */ IRpcStubBuffer **ppStub) { - return E_NOTIMPL; + CHECK_EXPECT(CreateStub); + + ok(pUnkServer == (IUnknown*)&Test_Unknown, "unexpected pUnkServer %p\n", pUnkServer); + if(!ps_factory_buffer) + return E_NOTIMPL; + + return IPSFactoryBuffer_CreateStub(ps_factory_buffer, &IID_IEnumOLEVERB, pUnkServer, ppStub); }
static IPSFactoryBufferVtbl PSFactoryBufferVtbl = @@ -1037,9 +1151,31 @@ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); ok_ole_success(hr, "CreateStreamOnHGlobal");
+ SET_EXPECT(CreateStub); hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr); + CHECK_CALLED(CreateStub); + + hr = CoGetPSClsid(&IID_IEnumOLEVERB, &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 = CoRegisterPSClsid(&IID_IEnumOLEVERB, &CLSID_WineTestPSFactoryBuffer); + ok_ole_success(hr, "CoRegisterPSClsid"); + + SET_EXPECT(CreateStub); + hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, (IUnknown*)&EnumOLEVERB, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok(hr == S_OK, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr); + CHECK_CALLED(CreateStub); + + hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok(hr == S_OK, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr); + IStream_Release(stream); + IPSFactoryBuffer_Release(ps_factory_buffer); + ps_factory_buffer = NULL;
hr = CoRevokeClassObject(dwRegistrationKey); ok_ole_success(hr, "CoRevokeClassObject"); @@ -2135,9 +2271,45 @@ return 0; }
+static const char cls_name[] = "cowait_test_class"; +static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg) +{ + HANDLE *handles = arg; + BOOL success; + DWORD index; + HRESULT hr; + HWND hWnd; + MSG msg; + + hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr); + + hWnd = CreateWindowExA(0, cls_name, "Test (thread)", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); + ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError()); + + index = 0xdeadbeef; + PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); + hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index); + ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr); + ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index); + success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); + ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n"); + + index = 0xdeadbeef; + PostMessageA(hWnd, WM_USER, 0, 0); + hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index); + ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr); + ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index); + success = PeekMessageA(&msg, hWnd, WM_USER, WM_USER, PM_REMOVE); + ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n"); + + DestroyWindow(hWnd); + CoUninitialize(); + return 0; +} + static void test_CoWaitForMultipleHandles(void) { - static const char cls_name[] = "cowait_test_class"; HANDLE handles[2], thread; DWORD index, tid; WNDCLASSEXA wc; @@ -2440,6 +2612,12 @@ CloseHandle(thread); }
+ /* test message pumping when CoWaitForMultipleHandles is called from non main apartment thread */ + thread = CreateThread(NULL, 0, test_CoWaitForMultipleHandles_thread, handles, 0, &tid); + index = WaitForSingleObject(thread, 500); + ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(thread); + CloseHandle(handles[0]); CloseHandle(handles[1]); DestroyWindow(hWnd); @@ -2493,6 +2671,7 @@ test_CoCreateInstance(); test_ole_menu(); test_CoGetClassObject(); + test_CoCreateInstanceEx(); test_CoRegisterMessageFilter(); test_CoRegisterPSClsid(); test_CoGetPSClsid();
Modified: trunk/rostests/winetests/ole32/marshal.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/marshal.c?... ============================================================================== --- trunk/rostests/winetests/ole32/marshal.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/marshal.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -122,7 +122,7 @@
static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv) { - ok(0, "unxpected call\n"); + ok(0, "unexpected call\n"); *ppv = NULL; return E_NOINTERFACE; } @@ -202,6 +202,24 @@
static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
+static ULONG WINAPI TestCrash_IUnknown_Release(LPUNKNOWN iface) +{ + UnlockModule(); + if(!cLocks) { + trace("crashing...\n"); + *(int**)0xc = 0; + } + return 1; /* non-heap-based object */ +} + +static const IUnknownVtbl TestCrashUnknown_Vtbl = +{ + Test_IUnknown_QueryInterface, + Test_IUnknown_AddRef, + TestCrash_IUnknown_Release, +}; + +static IUnknown TestCrash_Unknown = { &TestCrashUnknown_Vtbl };
static HRESULT WINAPI Test_IClassFactory_QueryInterface( LPCLASSFACTORY iface, @@ -1087,6 +1105,63 @@ ok_last_release_closes(TRUE);
end_host_object(host_tid, host_thread); +} + +static BOOL crash_thread_success; + +static DWORD CALLBACK crash_couninitialize_proc(void *p) +{ + IStream *stream; + HRESULT hr; + + cLocks = 0; + + CoInitialize(NULL); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + + IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + + hr = CoReleaseMarshalData(stream); + ok_ole_success(hr, CoReleaseMarshalData); + + ok_no_locks(); + + hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + + ok_more_than_one_lock(); + + trace("CoUninitialize >>>\n"); + CoUninitialize(); + trace("CoUninitialize <<<\n"); + + ok_no_locks(); + + IStream_Release(stream); + crash_thread_success = TRUE; + return 0; +} + +static void test_crash_couninitialize(void) +{ + HANDLE thread; + DWORD tid; + + if(!GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateActCtxW")) { + win_skip("Skipping crash tests on win2k.\n"); + return; + } + + crash_thread_success = FALSE; + thread = CreateThread(NULL, 0, crash_couninitialize_proc, NULL, 0, &tid); + ok(!WaitForSingleObject(thread, 10000), "wait timed out\n"); + CloseHandle(thread); + ok(crash_thread_success, "Crash thread failed\n"); }
/* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */ @@ -2859,6 +2934,63 @@
static HWND hwnd_app;
+struct local_server +{ + IPersist IPersist_iface; /* a nice short interface */ +}; + +static HRESULT WINAPI local_server_QueryInterface(IPersist *iface, REFIID iid, void **obj) +{ + *obj = NULL; + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IPersist)) + *obj = iface; + + if (*obj) + { + IPersist_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI local_server_AddRef(IPersist *iface) +{ + return 2; +} + +static ULONG WINAPI local_server_Release(IPersist *iface) +{ + return 1; +} + +static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid) +{ + HRESULT hr; + + *clsid = IID_IUnknown; + + /* Test calling CoDisconnectObject within a COM call */ + hr = CoDisconnectObject((IUnknown *)iface, 0); + ok(hr == S_OK, "got %08x\n", hr); + + return S_OK; +} + +static const IPersistVtbl local_server_persist_vtbl = +{ + local_server_QueryInterface, + local_server_AddRef, + local_server_Release, + local_server_GetClassID +}; + +struct local_server local_server_class = +{ + {&local_server_persist_vtbl} +}; + static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface( LPCLASSFACTORY iface, REFIID riid, @@ -2893,12 +3025,12 @@ REFIID riid, LPVOID *ppvObj) { - if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) - { - *ppvObj = iface; - return S_OK; - } - return CLASS_E_CLASSNOTAVAILABLE; + IPersist *persist = &local_server_class.IPersist_iface; + HRESULT hr; + IPersist_AddRef( persist ); + hr = IPersist_QueryInterface( persist, riid, ppvObj ); + IPersist_Release( persist ); + return hr; }
static HRESULT WINAPI TestOOP_IClassFactory_LockServer( @@ -2928,24 +3060,25 @@ DWORD cookie; HRESULT hr; HANDLE ready_event; - HANDLE quit_event; DWORD wait; + HANDLE handles[2];
heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL); - + ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event"); + handles[0] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event"); + handles[1] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event"); + +again: hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory, CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie); ok_ole_success(hr, CoRegisterClassObject);
- ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event"); SetEvent(ready_event);
- quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event"); - do { - wait = MsgWaitForMultipleObjects(1, &quit_event, FALSE, 30000, QS_ALLINPUT); - if (wait == WAIT_OBJECT_0+1) + wait = MsgWaitForMultipleObjects(2, handles, FALSE, 30000, QS_ALLINPUT); + if (wait == WAIT_OBJECT_0+2) { MSG msg;
@@ -2956,12 +3089,20 @@ DispatchMessageA(&msg); } } - } - while (wait == WAIT_OBJECT_0+1); + else if (wait == WAIT_OBJECT_0+1) + { + hr = CoRevokeClassObject(cookie); + ok_ole_success(hr, CoRevokeClassObject); + goto again; + } + } + while (wait == WAIT_OBJECT_0+2);
ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" ); hr = CoRevokeClassObject(cookie); ok_ole_success(hr, CoRevokeClassObject); + CloseHandle(handles[0]); + CloseHandle(handles[1]); }
static HANDLE create_target_process(const char *arg) @@ -2976,7 +3117,7 @@ pi.hThread = NULL; pi.hProcess = NULL; winetest_get_mainargs( &argv ); - sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); + sprintf(cmdline, ""%s" %s %s", argv[0], argv[1], arg); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed with error: %u\n", GetLastError()); if (pi.hThread) CloseHandle(pi.hThread); @@ -2989,10 +3130,13 @@ DWORD cookie; HRESULT hr; IClassFactory * cf; + IPersist *persist; DWORD ret; HANDLE process; HANDLE quit_event; HANDLE ready_event; + HANDLE repeat_event; + CLSID clsid;
heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
@@ -3059,15 +3203,29 @@
ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event"); ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" ); + + hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist); + ok_ole_success(hr, CoCreateInstance); + + IPersist_Release(persist); + + hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist); + ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n"); + + /* Re-register the class and try calling CoDisconnectObject from within a call to that object */ + repeat_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event"); + SetEvent(repeat_event); + CloseHandle(repeat_event); + + ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" ); CloseHandle(ready_event);
- hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IClassFactory, (void **)&cf); + hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist); ok_ole_success(hr, CoCreateInstance);
- IClassFactory_Release(cf); - - hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IClassFactory, (void **)&cf); - ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n"); + /* GetClassID will call CoDisconnectObject */ + IPersist_GetClassID(persist, &clsid); + IPersist_Release(persist);
quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event"); SetEvent(quit_event); @@ -3556,6 +3714,7 @@
test_globalinterfacetable(); test_manualresetevent(); + test_crash_couninitialize();
/* must be last test as channel hooks can't be unregistered */ test_channel_hook();
Modified: trunk/rostests/winetests/ole32/moniker.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/moniker.c?... ============================================================================== --- trunk/rostests/winetests/ole32/moniker.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/moniker.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -99,7 +99,7 @@
static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv) { - ok(0, "unxpected call\n"); + ok(0, "unexpected call\n"); *ppv = NULL; return E_NOINTERFACE; }
Modified: trunk/rostests/winetests/ole32/ole2.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/ole2.c?rev... ============================================================================== --- trunk/rostests/winetests/ole32/ole2.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/ole2.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -117,6 +117,32 @@ static HRESULT g_QIFailsWith;
static UINT cf_test_1, cf_test_2, cf_test_3; + +/**************************************************************************** + * PresentationDataHeader + * + * This structure represents the header of the \002OlePresXXX stream in + * the OLE object storage. + */ +typedef struct PresentationDataHeader +{ + /* clipformat: + * - standard clipformat: + * DWORD length = 0xffffffff; + * DWORD cfFormat; + * - or custom clipformat: + * DWORD length; + * CHAR format_name[length]; (null-terminated) + */ + DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ + DVASPECT dvAspect; + DWORD lindex; + DWORD tymed; + DWORD unknown7; /* 0 */ + DWORD dwObjectExtentX; + DWORD dwObjectExtentY; + DWORD dwSize; +} PresentationDataHeader;
#define CHECK_EXPECTED_METHOD(method_name) \ do { \ @@ -1045,6 +1071,7 @@ { HRESULT hr; IOleObject *pObject; + DWORD fmt;
static const struct expected_method methods_oleload[] = { @@ -1101,6 +1128,105 @@
IOleObject_Release(pObject); CHECK_NO_EXTRA_METHODS(); + } + + for (fmt = CF_TEXT; fmt < CF_MAX; fmt++) + { + static const WCHAR olrepres[] = { 2,'O','l','e','P','r','e','s','0','0','0',0 }; + IStorage *stg; + IStream *stream; + IUnknown *obj; + DWORD data, i, tymed, data_size; + PresentationDataHeader header; + HDC hdc; + HGDIOBJ hobj; + RECT rc; + char buf[256]; + + for (i = 0; i < 7; i++) + { + hr = StgCreateDocfile(NULL, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &stg); + ok(hr == S_OK, "StgCreateDocfile error %#x\n", hr); + + hr = IStorage_SetClass(stg, &CLSID_WineTest); + ok(hr == S_OK, "SetClass error %#x\n", hr); + + hr = IStorage_CreateStream(stg, olrepres, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, 0, &stream); + ok(hr == S_OK, "CreateStream error %#x\n", hr); + + data = ~0; + hr = IStream_Write(stream, &data, sizeof(data), NULL); + ok(hr == S_OK, "Write error %#x\n", hr); + + data = fmt; + hr = IStream_Write(stream, &data, sizeof(data), NULL); + ok(hr == S_OK, "Write error %#x\n", hr); + + switch (fmt) + { + case CF_BITMAP: + /* FIXME: figure out stream format */ + hobj = CreateBitmap(1, 1, 1, 1, NULL); + data_size = GetBitmapBits(hobj, sizeof(buf), buf); + DeleteObject(hobj); + break; + + case CF_METAFILEPICT: + case CF_ENHMETAFILE: + hdc = CreateMetaFileA(NULL); + hobj = CloseMetaFile(hdc); + data_size = GetMetaFileBitsEx(hobj, sizeof(buf), buf); + DeleteMetaFile(hobj); + break; + + default: + data_size = sizeof(buf); + memset(buf, 'A', sizeof(buf)); + break; + } + + tymed = 1 << i; + + header.unknown3 = 4; + header.dvAspect = DVASPECT_CONTENT; + header.lindex = -1; + header.tymed = tymed; + header.unknown7 = 0; + header.dwObjectExtentX = 1; + header.dwObjectExtentY = 1; + header.dwSize = data_size; + hr = IStream_Write(stream, &header, sizeof(header), NULL); + ok(hr == S_OK, "Write error %#x\n", hr); + + hr = IStream_Write(stream, buf, data_size, NULL); + ok(hr == S_OK, "Write error %#x\n", hr); + + IStream_Release(stream); + + hr = OleLoad(stg, &IID_IUnknown, NULL, (void **)&obj); + /* FIXME: figure out stream format */ + if (fmt == CF_BITMAP && hr != S_OK) + { + IStorage_Release(stg); + continue; + } + ok(hr == S_OK, "OleLoad error %#x: cfFormat = %u, tymed = %u\n", hr, fmt, tymed); + + hdc = CreateCompatibleDC(0); + SetRect(&rc, 0, 0, 100, 100); + hr = OleDraw(obj, DVASPECT_CONTENT, hdc, &rc); + DeleteDC(hdc); + if (fmt == CF_METAFILEPICT) + ok(hr == S_OK, "OleDraw error %#x: cfFormat = %u, tymed = %u\n", hr, fmt, tymed); + else if (fmt == CF_ENHMETAFILE) +todo_wine + ok(hr == S_OK, "OleDraw error %#x: cfFormat = %u, tymed = %u\n", hr, fmt, tymed); + else + ok(hr == OLE_E_BLANK || hr == OLE_E_NOTRUNNING || hr == E_FAIL, "OleDraw should fail: %#x, cfFormat = %u, tymed = %u\n", hr, fmt, header.tymed); + + IUnknown_Release(obj); + IStorage_Release(stg); + } } }
@@ -1936,7 +2062,6 @@ fmtetc.lindex = -1; fmtetc.tymed = TYMED_ENHMF; hr = IDataObject_QueryGetData(pDataObject, &fmtetc); - todo_wine ok(hr == OLE_E_NOTRUNNING, "IDataObject_QueryGetData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr);
fmtetc.cfFormat = CF_TEXT; @@ -1945,7 +2070,6 @@ fmtetc.lindex = -1; fmtetc.tymed = TYMED_NULL; hr = IDataObject_QueryGetData(pDataObject, &fmtetc); - todo_wine ok(hr == OLE_E_NOTRUNNING, "IDataObject_QueryGetData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr);
hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnableObject); @@ -2107,7 +2231,7 @@
static HRESULT WINAPI OleRun_GetRunningClass(IRunnableObject *iface, CLSID *clsid) { - ok(0, "unxpected\n"); + ok(0, "unexpected\n"); return E_NOTIMPL; }
@@ -2119,20 +2243,20 @@
static BOOL WINAPI OleRun_IsRunning(IRunnableObject *iface) { - ok(0, "unxpected\n"); + ok(0, "unexpected\n"); return FALSE; }
static HRESULT WINAPI OleRun_LockRunning(IRunnableObject *iface, BOOL lock, BOOL last_unlock_closes) { - ok(0, "unxpected\n"); + ok(0, "unexpected\n"); return E_NOTIMPL; }
static HRESULT WINAPI OleRun_SetContainedObject(IRunnableObject *iface, BOOL contained) { - ok(0, "unxpected\n"); + ok(0, "unexpected\n"); return E_NOTIMPL; }
Modified: trunk/rostests/winetests/ole32/propvariant.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/propvarian... ============================================================================== --- trunk/rostests/winetests/ole32/propvariant.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/propvariant.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -140,7 +140,7 @@ };
-static void expect(HRESULT hr, VARTYPE vt, BOOL copy) +static void expect(HRESULT hr, VARTYPE vt, BOOL copy, int line) { int idx = vt & VT_TYPEMASK; BYTE flags; @@ -168,7 +168,12 @@ }
if(flags == PROP_INV) - ok(hr == copy ? DISP_E_BADVARTYPE : STG_E_INVALIDPARAMETER, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); + { + if (copy && (vt & VT_VECTOR)) + ok(hr == DISP_E_BADVARTYPE || hr == STG_E_INVALIDPARAMETER, "%s (%s): got %08x (line %d)\n", wine_vtypes[idx], modifier, hr, line); + else + ok(hr == (copy ? DISP_E_BADVARTYPE : STG_E_INVALIDPARAMETER), "%s (%s): got %08x (line %d)\n", wine_vtypes[idx], modifier, hr, line); + } else if(flags == PROP_V0) ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); else if(flags & PROP_TODO) @@ -220,7 +225,7 @@ vt = propvar.vt = i; memset(©, 0x77, sizeof(copy)); hr = PropVariantCopy(©, &propvar); - expect(hr, vt, TRUE); + expect(hr, vt, TRUE, __LINE__); if (hr == S_OK) { ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt); @@ -234,7 +239,7 @@ ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i); } hr = PropVariantClear(&propvar); - expect(hr, vt, FALSE); + expect(hr, vt, FALSE, __LINE__); ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt); ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n", i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart); @@ -244,7 +249,7 @@ vt = propvar.vt = i | VT_ARRAY; memset(©, 0x77, sizeof(copy)); hr = PropVariantCopy(©, &propvar); - expect(hr, vt, TRUE); + expect(hr, vt, TRUE, __LINE__); if (hr == S_OK) { ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt); @@ -257,7 +262,7 @@ ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i); } hr = PropVariantClear(&propvar); - expect(hr, vt, FALSE); + expect(hr, vt, FALSE, __LINE__); ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt); ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n", i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart); @@ -268,7 +273,7 @@ vt = propvar.vt = i | VT_VECTOR; memset(©, 0x77, sizeof(copy)); hr = PropVariantCopy(©, &propvar); - expect(hr, vt, TRUE); + expect(hr, vt, TRUE, __LINE__); if (hr == S_OK) { ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt); @@ -281,7 +286,7 @@ ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i); } hr = PropVariantClear(&propvar); - expect(hr, vt, FALSE); + expect(hr, vt, FALSE, __LINE__); ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt); ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n", i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart); @@ -291,7 +296,7 @@ vt = propvar.vt = i | VT_BYREF; memset(©, 0x77, sizeof(copy)); hr = PropVariantCopy(©, &propvar); - expect(hr, vt, TRUE); + expect(hr, vt, TRUE, __LINE__); if (hr == S_OK) { ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt); @@ -305,7 +310,7 @@ ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i); } hr = PropVariantClear(&propvar); - expect(hr, vt, FALSE); + expect(hr, vt, FALSE, __LINE__); ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt); ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n", i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
Modified: trunk/rostests/winetests/ole32/storage32.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/storage32.... ============================================================================== --- trunk/rostests/winetests/ole32/storage32.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/storage32.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -224,7 +224,7 @@ return S_OK; }
-static ILockBytesVtbl TestLockBytes_Vtbl = { +static /* const */ ILockBytesVtbl TestLockBytes_Vtbl = { TestLockBytes_QueryInterface, TestLockBytes_AddRef, TestLockBytes_Release, @@ -517,6 +517,7 @@ ULARGE_INTEGER p; unsigned char buffer[0x100]; IUnknown *unk; + BOOL ret;
DeleteFileA(filenameA);
@@ -695,8 +696,8 @@ IStorage_Release(stg); }
- r = DeleteFileA(filenameA); - ok(r, "file should exist\n"); + ret = DeleteFileA(filenameA); + ok(ret, "file should exist\n"); }
static BOOL touch_file(LPCSTR filename) @@ -743,6 +744,7 @@ IStorage *stg = NULL, *stg2 = NULL; HRESULT r; DWORD stgm; + BOOL ret;
/* try opening a zero length file - it should stay zero length */ DeleteFileA(filenameA); @@ -902,8 +904,8 @@ r = StgOpenStorage( filename, NULL, STGM_NOSNAPSHOT | STGM_PRIORITY, NULL, 0, &stg); ok(r == STG_E_INVALIDFLAG, "should fail\n");
- r = DeleteFileA(filenameA); - ok(r, "file didn't exist\n"); + ret = DeleteFileA(filenameA); + ok(ret, "file didn't exist\n"); }
static void test_storage_suminfo(void) @@ -1226,6 +1228,7 @@ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; static const WCHAR stmname2[] = { 'A','B','C','D','E','F','G','H','I',0 }; static const WCHAR stmname3[] = { 'A','B','C','D','E','F','G','H','I','J',0 }; + static const STATSTG stat_null; STATSTG stat; IEnumSTATSTG *ee = NULL; ULONG count; @@ -1271,10 +1274,12 @@ r = IStorage_DestroyElement(stg, stmname); ok(r==S_OK, "IStorage->DestroyElement failed\n");
+ memset(&stat, 0xad, sizeof(stat)); count = 0xf00; r = IEnumSTATSTG_Next(ee, 1, &stat, &count); ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n"); ok(count == 0, "count wrong\n"); + ok(memcmp(&stat, &stat_null, sizeof(stat)) == 0, "stat is not zeroed\n");
/* reset and try again */ r = IEnumSTATSTG_Reset(ee); @@ -1401,6 +1406,7 @@ static const WCHAR stmname2[] = { 'F','O','O',0 }; static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -1521,8 +1527,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_substorage_share(void) @@ -1533,6 +1539,7 @@ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; static const WCHAR othername[] = { 'N','E','W','N','A','M','E',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -1612,8 +1619,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_revert(void) @@ -1626,6 +1633,7 @@ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 }; STATSTG statstg; + BOOL ret;
DeleteFileA(filenameA);
@@ -1743,8 +1751,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n");
/* Revert only invalidates objects in transacted mode */ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | @@ -1763,8 +1771,8 @@ IStream_Release(stm); IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_parent_free(void) @@ -1776,6 +1784,7 @@ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; ULONG ref; STATSTG statstg; + BOOL ret;
DeleteFileA(filenameA);
@@ -1825,8 +1834,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_nonroot_transacted(void) @@ -1837,6 +1846,7 @@ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; static const WCHAR stmname2[] = { 'F','O','O',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -1945,8 +1955,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_ReadClassStm(void) @@ -2415,6 +2425,7 @@ static const WCHAR fileW[] = {'f','m','t','t','e','s','t',0}; static WCHAR userTypeW[] = {'S','t','g','U','s','r','T','y','p','e',0}; static const WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0}; + static const STATSTG statstg_null;
hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg); ok(hr == S_OK, "should succeed, res=%x\n", hr); @@ -2433,6 +2444,7 @@ BOOL found = FALSE; STATSTG statstg; DWORD got; + memset(&statstg, 0xad, sizeof(statstg)); while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1) { if (strcmp_ww(statstg.pwcsName, strmNameW) == 0) @@ -2441,6 +2453,7 @@ ok(0, "found unexpected stream or storage\n"); CoTaskMemFree(statstg.pwcsName); } + ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n"); ok(found == TRUE, "expected storage to contain stream \0001CompObj\n"); IEnumSTATSTG_Release(stat); } @@ -2457,6 +2470,7 @@ BOOL found = FALSE; STATSTG statstg; DWORD got; + memset(&statstg, 0xad, sizeof(statstg)); while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1) { if (strcmp_ww(statstg.pwcsName, strmNameW) == 0) @@ -2465,6 +2479,7 @@ ok(0, "found unexpected stream or storage\n"); CoTaskMemFree(statstg.pwcsName); } + ok(memcmp(&statstg, &statstg_null, sizeof(statstg)) == 0, "statstg is not zeroed\n"); ok(found == TRUE, "expected storage to contain stream \0001CompObj\n"); IEnumSTATSTG_Release(stat); } @@ -2929,6 +2944,7 @@ static const WCHAR stgname2[] = { 'S','T','G',0 }; static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; static const WCHAR stmname2[] = { 'E','N','T','S',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -2985,8 +3001,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_toplevel_stat(void) @@ -3072,6 +3088,7 @@ HRESULT r; ULONG ref; static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -3107,8 +3124,8 @@
IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_copyto_locking(void) @@ -3119,6 +3136,7 @@ static const WCHAR stgname[] = { 'S','T','G','1',0 }; static const WCHAR stgname2[] = { 'S','T','G','2',0 }; static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -3158,8 +3176,8 @@ IStorage_Release(stg2); IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_copyto_recursive(void) @@ -3168,6 +3186,7 @@ HRESULT r; static const WCHAR stgname[] = { 'S','T','G','1',0 }; static const WCHAR stgname2[] = { 'S','T','G','2',0 }; + BOOL ret;
DeleteFileA(filenameA);
@@ -3209,8 +3228,8 @@ IStorage_Release(stg2); IStorage_Release(stg);
- r = DeleteFileA(filenameA); - ok( r == TRUE, "deleted file\n"); + ret = DeleteFileA(filenameA); + ok(ret, "deleted file\n"); }
static void test_hglobal_storage_creation(void)
Modified: trunk/rostests/winetests/ole32/usrmarshal.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/usrmarshal... ============================================================================== --- trunk/rostests/winetests/ole32/usrmarshal.c [iso-8859-1] (original) +++ trunk/rostests/winetests/ole32/usrmarshal.c [iso-8859-1] Tue Nov 17 10:31:59 2015 @@ -89,6 +89,91 @@ umcb->pStubMsg = stub_msg; umcb->Signature = USER_MARSHAL_CB_SIGNATURE; umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE; +} + +#define RELEASEMARSHALDATA WM_USER + +struct host_object_data +{ + IStream *stream; + IID iid; + IUnknown *object; + MSHLFLAGS marshal_flags; + HANDLE marshal_event; + IMessageFilter *filter; +}; + +static DWORD CALLBACK host_object_proc(LPVOID p) +{ + struct host_object_data *data = p; + HRESULT hr; + MSG msg; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + if (data->filter) + { + IMessageFilter * prev_filter = NULL; + hr = CoRegisterMessageFilter(data->filter, &prev_filter); + if (prev_filter) IMessageFilter_Release(prev_filter); + ok(hr == S_OK, "got %08x\n", hr); + } + + hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags); + ok(hr == S_OK, "got %08x\n", hr); + + /* force the message queue to be created before signaling parent thread */ + PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + SetEvent(data->marshal_event); + + while (GetMessageA(&msg, NULL, 0, 0)) + { + if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA) + { + CoReleaseMarshalData(data->stream); + SetEvent((HANDLE)msg.lParam); + } + else + DispatchMessageA(&msg); + } + + HeapFree(GetProcessHeap(), 0, data); + + CoUninitialize(); + + return hr; +} + +static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, 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; + + *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); + + return tid; +} + +static void end_host_object(DWORD tid, HANDLE thread) +{ + BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0); + ok(ret, "PostThreadMessage failed with error %d\n", GetLastError()); + /* be careful of races - don't return until hosting thread has terminated */ + ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" ); + CloseHandle(thread); }
static const char cf_marshaled[] = @@ -533,6 +618,17 @@ Test_IUnknown_Release, };
+struct test_stream +{ + IStream IStream_iface; + LONG refs; +}; + +static inline struct test_stream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream, IStream_iface); +} + static HRESULT WINAPI Test_IStream_QueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) { @@ -552,12 +648,14 @@
static ULONG WINAPI Test_IStream_AddRef(IStream *iface) { - return 2; /* non-heap-based object */ + struct test_stream *This = impl_from_IStream(iface); + return InterlockedIncrement(&This->refs); }
static ULONG WINAPI Test_IStream_Release(IStream *iface) { - return 1; /* non-heap-based object */ + struct test_stream *This = impl_from_IStream(iface); + return InterlockedDecrement(&This->refs); }
static const IStreamVtbl TestStream_Vtbl = @@ -569,13 +667,15 @@ };
static TestUnknown Test_Unknown = { {&TestUnknown_Vtbl}, 1 }; -static IStream Test_Stream = { &TestStream_Vtbl }; +static TestUnknown Test_Unknown2 = { {&TestUnknown_Vtbl}, 1 }; +static struct test_stream Test_Stream = { {&TestStream_Vtbl}, 1 }; +static struct test_stream Test_Stream2 = { {&TestStream_Vtbl}, 1 };
ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID); unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG *, ULONG, unsigned char *, IUnknown *, REFIID); unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG *, unsigned char *, IUnknown **, REFIID);
-static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx) +static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx, BOOL client, BOOL in, BOOL out) { USER_MARSHAL_CB umcb; MIDL_STUB_MESSAGE stub_msg; @@ -644,11 +744,17 @@ CoReleaseMarshalData(stm); IStream_Release(stm);
- unk2 = NULL; + Test_Unknown2.refs = 1; + unk2 = &Test_Unknown2.IUnknown_iface; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx); + umcb.pStubMsg->IsClient = client; + umcb.pStubMsg->fIsIn = in; + umcb.pStubMsg->fIsOut = out; + WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown); ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n"); ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs); + ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs); HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); IUnknown_Release(unk2); @@ -663,17 +769,26 @@ */
/* All three are marshalled as inproc */ - marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_INPROC); - marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_INPROC); - marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_INPROC, 0xffff)); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_INPROC, 0,0,0); + marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_INPROC,0,0,0); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_INPROC, 0xffff),0,0,0);
/* All three are marshalled as remote */ - marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE); - marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_DIFFERENTMACHINE); - marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_DIFFERENTMACHINE, 0xffff)); -} - -static void test_marshal_STGMEDIUM(void) + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,0,0); + marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_DIFFERENTMACHINE,0,0,0); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_DIFFERENTMACHINE, 0xffff),0,0,0); + + /* Test different combinations of client, in and out */ + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,0,1); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,1,0); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,1,1); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,0,0); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,0,1); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,1,0); + marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,1,1); +} + +static void marshal_STGMEDIUM(BOOL client, BOOL in, BOOL out) { USER_MARSHAL_CB umcb; MIDL_STUB_MESSAGE stub_msg; @@ -682,13 +797,17 @@ ULONG size, expect_size; STGMEDIUM med, med2; IUnknown *unk = &Test_Unknown.IUnknown_iface; - IStream *stm = &Test_Stream; + IStream *stm = &Test_Stream.IStream_iface;
/* TYMED_NULL with pUnkForRelease */ + + Test_Unknown.refs = 1;
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 2 * sizeof(DWORD), unk, &IID_IUnknown); expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size); + *(DWORD*)expect_buffer = TYMED_NULL; + *((DWORD*)expect_buffer + 1) = 0xdeadbeef; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE); expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 2 * sizeof(DWORD), unk, &IID_IUnknown);
@@ -709,25 +828,41 @@ ok(!memcmp(buffer+8, expect_buffer + 8, expect_buffer_end - expect_buffer - 8), "buffer mismatch\n");
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - - /* native crashes if this is uninitialised, presumably because it - tries to release it */ + umcb.pStubMsg->IsClient = client; + umcb.pStubMsg->fIsIn = in; + umcb.pStubMsg->fIsOut = out; + + Test_Unknown2.refs = 1; + med2.tymed = TYMED_NULL; + U(med2).pstm = NULL; + med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface; + + STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2); + + ok(med2.tymed == TYMED_NULL, "got tymed %x\n", med2.tymed); + ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n"); + ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs); + + HeapFree(GetProcessHeap(), 0, buffer); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + STGMEDIUM_UserFree(&umcb.Flags, &med2); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE); med2.tymed = TYMED_NULL; U(med2).pstm = NULL; med2.pUnkForRelease = NULL; - - STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2); - - ok(med2.tymed == TYMED_NULL, "got tymed %x\n", med2.tymed); - ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n"); - - HeapFree(GetProcessHeap(), 0, buffer); + STGMEDIUM_UserUnmarshal(&umcb.Flags, expect_buffer, &med2); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); STGMEDIUM_UserFree(&umcb.Flags, &med2);
+ ok(Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs); + HeapFree(GetProcessHeap(), 0, expect_buffer);
/* TYMED_ISTREAM with pUnkForRelease */ + + Test_Unknown.refs = 1; + Test_Stream.refs = 1;
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream); @@ -736,6 +871,9 @@ expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size); /* There may be a hole between the two interfaces so init the buffer to something */ memset(expect_buffer, 0xcc, expect_size); + *(DWORD*)expect_buffer = TYMED_ISTREAM; + *((DWORD*)expect_buffer + 1) = 0xdeadbeef; + *((DWORD*)expect_buffer + 2) = 0xcafe; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE); expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream); expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer_end, unk, &IID_IUnknown); @@ -759,24 +897,98 @@ ok(!memcmp(buffer + 12, expect_buffer + 12, (buffer_end - buffer) - 12), "buffer mismatch\n");
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - - /* native crashes if this is uninitialised, presumably because it - tries to release it */ + umcb.pStubMsg->IsClient = client; + umcb.pStubMsg->fIsIn = in; + umcb.pStubMsg->fIsOut = out; + + Test_Stream2.refs = 1; + Test_Unknown2.refs = 1; + med2.tymed = TYMED_ISTREAM; + U(med2).pstm = &Test_Stream2.IStream_iface; + med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface; + + STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2); + + ok(med2.tymed == TYMED_ISTREAM, "got tymed %x\n", med2.tymed); + ok(U(med2).pstm != NULL, "Incorrectly unmarshalled\n"); + ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n"); + ok(Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs); + ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs); + + HeapFree(GetProcessHeap(), 0, buffer); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + STGMEDIUM_UserFree(&umcb.Flags, &med2); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE); med2.tymed = TYMED_NULL; U(med2).pstm = NULL; med2.pUnkForRelease = NULL; + STGMEDIUM_UserUnmarshal(&umcb.Flags, expect_buffer, &med2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + STGMEDIUM_UserFree(&umcb.Flags, &med2); + + ok(Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs); + ok(Test_Stream.refs == 1, "got %d\n", Test_Stream.refs); + + HeapFree(GetProcessHeap(), 0, expect_buffer); + + /* TYMED_ISTREAM = NULL with pUnkForRelease = NULL */ + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + expect_size = 3 * sizeof(DWORD); + + med.tymed = TYMED_ISTREAM; + U(med).pstm = NULL; + med.pUnkForRelease = NULL; + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med); + ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size); + + buffer = HeapAlloc(GetProcessHeap(), 0, size); + memset(buffer, 0xcc, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med); + ok(buffer_end - buffer == expect_size, "buffer size mismatch\n"); + ok(*(DWORD*)buffer == TYMED_ISTREAM, "got %08x\n", *(DWORD*)buffer); + ok(*((DWORD*)buffer+1) == 0, "got %08x\n", *((DWORD*)buffer+1)); + ok(*((DWORD*)buffer+2) == 0, "got %08x\n", *((DWORD*)buffer+2)); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + umcb.pStubMsg->IsClient = client; + umcb.pStubMsg->fIsIn = in; + umcb.pStubMsg->fIsOut = out; + + Test_Stream2.refs = 1; + Test_Unknown2.refs = 1; + med2.tymed = TYMED_ISTREAM; + U(med2).pstm = &Test_Stream2.IStream_iface; + med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface;
STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
ok(med2.tymed == TYMED_ISTREAM, "got tymed %x\n", med2.tymed); - ok(U(med2).pstm != NULL, "Incorrectly unmarshalled\n"); - ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n"); + ok(U(med2).pstm == NULL, "Incorrectly unmarshalled\n"); + ok(med2.pUnkForRelease == &Test_Unknown2.IUnknown_iface, "Incorrectly unmarshalled\n"); + ok(Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs); + ok(Test_Unknown2.refs == 1, "got %d\n", Test_Unknown2.refs);
HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); STGMEDIUM_UserFree(&umcb.Flags, &med2); - - HeapFree(GetProcessHeap(), 0, expect_buffer); +} + +static void test_marshal_STGMEDIUM(void) +{ + marshal_STGMEDIUM(0, 0, 0); + marshal_STGMEDIUM(0, 0, 1); + marshal_STGMEDIUM(0, 1, 0); + marshal_STGMEDIUM(0, 1, 1); + /* For Windows versions post 2003, client side, non-[in,out] STGMEDIUMs get zero-initialised. + However since inline stubs don't set fIsIn or fIsOut this behaviour would break + ref counting in GetDataHere_Proxy for example, as we'd end up not releasing the original + interface. For simplicity we don't test or implement this. */ + marshal_STGMEDIUM(1, 1, 1); }
static void test_marshal_SNB(void) @@ -984,9 +1196,156 @@ DeleteObject(hBrush); }
+struct obj +{ + IDataObject IDataObject_iface; +}; + +static HRESULT WINAPI obj_QueryInterface(IDataObject *iface, REFIID iid, void **obj) +{ + *obj = NULL; + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IDataObject)) + *obj = iface; + + if (*obj) + { + IDataObject_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI obj_AddRef(IDataObject *iface) +{ + return 2; +} + +static ULONG WINAPI obj_Release(IDataObject *iface) +{ + return 1; +} + +static HRESULT WINAPI obj_DO_GetDataHere(IDataObject *iface, FORMATETC *fmt, + STGMEDIUM *med) +{ + ok( med->pUnkForRelease == NULL, "got %p\n", med->pUnkForRelease ); + + if (fmt->cfFormat == 2) + { + IStream_Release(U(med)->pstm); + U(med)->pstm = &Test_Stream2.IStream_iface; + } + + return S_OK; +} + +static const IDataObjectVtbl obj_data_object_vtbl = +{ + obj_QueryInterface, + obj_AddRef, + obj_Release, + NULL, /* GetData */ + obj_DO_GetDataHere, + NULL, /* QueryGetData */ + NULL, /* GetCanonicalFormatEtc */ + NULL, /* SetData */ + NULL, /* EnumFormatEtc */ + NULL, /* DAdvise */ + NULL, /* DUnadvise */ + NULL /* EnumDAdvise */ +}; + +static struct obj obj = +{ + {&obj_data_object_vtbl} +}; + +static void test_GetDataHere_Proxy(void) +{ + HRESULT hr; + IStream *stm; + HANDLE thread; + DWORD tid; + static const LARGE_INTEGER zero; + IDataObject *data; + FORMATETC fmt; + STGMEDIUM med; + + hr = CreateStreamOnHGlobal( NULL, TRUE, &stm ); + ok( hr == S_OK, "got %08x\n", hr ); + tid = start_host_object2( stm, &IID_IDataObject, (IUnknown *)&obj.IDataObject_iface, MSHLFLAGS_NORMAL, NULL, &thread ); + + IStream_Seek( stm, zero, STREAM_SEEK_SET, NULL ); + hr = CoUnmarshalInterface( stm, &IID_IDataObject, (void **)&data ); + ok( hr == S_OK, "got %08x\n", hr ); + IStream_Release( stm ); + + Test_Stream.refs = 1; + Test_Stream2.refs = 1; + Test_Unknown.refs = 1; + + fmt.cfFormat = 1; + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + U(med).pstm = NULL; + med.pUnkForRelease = &Test_Unknown.IUnknown_iface; + + fmt.tymed = med.tymed = TYMED_NULL; + hr = IDataObject_GetDataHere( data, &fmt, &med ); + ok( hr == DV_E_TYMED, "got %08x\n", hr ); + + for (fmt.tymed = TYMED_HGLOBAL; fmt.tymed <= TYMED_ENHMF; fmt.tymed <<= 1) + { + med.tymed = fmt.tymed; + hr = IDataObject_GetDataHere( data, &fmt, &med ); + ok( hr == (fmt.tymed <= TYMED_ISTORAGE ? S_OK : DV_E_TYMED), "got %08x for tymed %d\n", hr, fmt.tymed ); + ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs ); + } + + fmt.tymed = TYMED_ISTREAM; + med.tymed = TYMED_ISTORAGE; + hr = IDataObject_GetDataHere( data, &fmt, &med ); + ok( hr == DV_E_TYMED, "got %08x\n", hr ); + + fmt.tymed = med.tymed = TYMED_ISTREAM; + U(med).pstm = &Test_Stream.IStream_iface; + med.pUnkForRelease = &Test_Unknown.IUnknown_iface; + + hr = IDataObject_GetDataHere( data, &fmt, &med ); + ok( hr == S_OK, "got %08x\n", hr ); + + ok( U(med).pstm == &Test_Stream.IStream_iface, "stm changed\n" ); + ok( med.pUnkForRelease == &Test_Unknown.IUnknown_iface, "punk changed\n" ); + + ok( Test_Stream.refs == 1, "got %d\n", Test_Stream.refs ); + ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs ); + + fmt.cfFormat = 2; + fmt.tymed = med.tymed = TYMED_ISTREAM; + U(med).pstm = &Test_Stream.IStream_iface; + med.pUnkForRelease = &Test_Unknown.IUnknown_iface; + + hr = IDataObject_GetDataHere( data, &fmt, &med ); + ok( hr == S_OK, "got %08x\n", hr ); + + ok( U(med).pstm == &Test_Stream.IStream_iface, "stm changed\n" ); + ok( med.pUnkForRelease == &Test_Unknown.IUnknown_iface, "punk changed\n" ); + + ok( Test_Stream.refs == 1, "got %d\n", Test_Stream.refs ); + ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs ); + ok( Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs ); + + IDataObject_Release( data ); + end_host_object( tid, thread ); +} + START_TEST(usrmarshal) { - CoInitialize(NULL); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
test_marshal_CLIPFORMAT(); test_marshal_HWND(); @@ -1001,5 +1360,7 @@ test_marshal_HICON(); test_marshal_HBRUSH();
+ test_GetDataHere_Proxy(); + CoUninitialize(); }