From fc6e4ed57615eead1c9dc6941ca90396749a6b66 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sun, 10 Nov 2019 14:11:19 +0100 Subject: [PATCH] [OLE32_WINETEST] Sync with Wine Staging 4.18. CORE-16441 --- modules/rostests/winetests/ole32/clipboard.c | 2 +- modules/rostests/winetests/ole32/compobj.c | 210 ++++++++++++------ modules/rostests/winetests/ole32/marshal.c | 14 +- modules/rostests/winetests/ole32/ole_server.c | 2 +- .../rostests/winetests/ole32/propvariant.c | 124 +++++++++-- 5 files changed, 264 insertions(+), 88 deletions(-) diff --git a/modules/rostests/winetests/ole32/clipboard.c b/modules/rostests/winetests/ole32/clipboard.c index d7f18ef2458..e3e1b27fb5e 100644 --- a/modules/rostests/winetests/ole32/clipboard.c +++ b/modules/rostests/winetests/ole32/clipboard.c @@ -46,7 +46,7 @@ static inline char *dump_fmtetc(FORMATETC *fmt) { static char buf[100]; - snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x", + sprintf(buf, "cf %04x ptd %p aspect %x lindex %d tymed %x", fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); return buf; } diff --git a/modules/rostests/winetests/ole32/compobj.c b/modules/rostests/winetests/ole32/compobj.c index 33a75853653..49faabdece3 100644 --- a/modules/rostests/winetests/ole32/compobj.c +++ b/modules/rostests/winetests/ole32/compobj.c @@ -39,7 +39,7 @@ #include "initguid.h" #define DEFINE_EXPECT(func) \ - static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + static BOOL expect_ ## func = FALSE; static unsigned int called_ ## func = 0 #define SET_EXPECT(func) \ expect_ ## func = TRUE @@ -47,7 +47,7 @@ #define CHECK_EXPECT2(func) \ do { \ ok(expect_ ##func, "unexpected call " #func "\n"); \ - called_ ## func = TRUE; \ + called_ ## func++; \ }while(0) #define CHECK_EXPECT(func) \ @@ -56,13 +56,18 @@ expect_ ## func = FALSE; \ }while(0) -#define CHECK_CALLED(func) \ +#define CHECK_CALLED(func, n) \ do { \ - ok(called_ ## func, "expected " #func "\n"); \ - expect_ ## func = called_ ## func = FALSE; \ + ok(called_ ## func == n, "expected " #func " called %u times, got %u\n", n, called_ ## func); \ + expect_ ## func = FALSE; \ + called_ ## func = 0; \ }while(0) DEFINE_EXPECT(CreateStub); +DEFINE_EXPECT(PreInitialize); +DEFINE_EXPECT(PostInitialize); +DEFINE_EXPECT(PreUninitialize); +DEFINE_EXPECT(PostUninitialize); /* functions that are not present on all versions of Windows */ static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); @@ -788,7 +793,7 @@ static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID if (ppvObj == NULL) return E_POINTER; if (IsEqualGUID(riid, &IID_IUnknown) || - IsEqualGUID(riid, &IID_IClassFactory)) + IsEqualGUID(riid, &IID_IMessageFilter)) { *ppvObj = iface; IMessageFilter_AddRef(iface); @@ -1031,7 +1036,7 @@ static HRESULT WINAPI PSFactoryBuffer_CreateStub( { CHECK_EXPECT(CreateStub); - ok(pUnkServer == (IUnknown*)&Test_Unknown, "unexpected pUnkServer %p\n", pUnkServer); + ok(pUnkServer == &Test_Unknown, "unexpected pUnkServer %p\n", pUnkServer); if(!ps_factory_buffer) return E_NOTIMPL; @@ -1120,7 +1125,7 @@ static void test_CoRegisterPSClsid(void) 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); + CHECK_CALLED(CreateStub, 1); hr = CoGetPSClsid(&IID_IEnumOLEVERB, &clsid); ok_ole_success(hr, "CoGetPSClsid"); @@ -1134,7 +1139,7 @@ static void test_CoRegisterPSClsid(void) SET_EXPECT(CreateStub); hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, (IUnknown*)&EnumOLEVERB, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr); - CHECK_CALLED(CreateStub); + CHECK_CALLED(CreateStub, 1); hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr); @@ -3306,27 +3311,47 @@ static ULONG WINAPI testinitialize_Release(IInitializeSpy *iface) return 1; } +static DWORD expected_coinit_flags; +static ULARGE_INTEGER init_cookies[3]; +static BOOL revoke_spies_on_uninit; + static HRESULT WINAPI testinitialize_PreInitialize(IInitializeSpy *iface, DWORD coinit, DWORD aptrefs) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT2(PreInitialize); + ok(coinit == expected_coinit_flags, "Unexpected init flags %#x, expected %#x.\n", coinit, expected_coinit_flags); + return S_OK; } static HRESULT WINAPI testinitialize_PostInitialize(IInitializeSpy *iface, HRESULT hr, DWORD coinit, DWORD aptrefs) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT2(PostInitialize); + ok(coinit == expected_coinit_flags, "Unexpected init flags %#x, expected %#x.\n", coinit, expected_coinit_flags); + return hr; } static HRESULT WINAPI testinitialize_PreUninitialize(IInitializeSpy *iface, DWORD aptrefs) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + HRESULT hr; + CHECK_EXPECT2(PreUninitialize); + if (revoke_spies_on_uninit) + { + hr = CoRevokeInitializeSpy(init_cookies[0]); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = CoRevokeInitializeSpy(init_cookies[1]); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = CoRevokeInitializeSpy(init_cookies[2]); + ok(hr == S_OK, "got 0x%08x\n", hr); + + revoke_spies_on_uninit = FALSE; + } + return S_OK; } static HRESULT WINAPI testinitialize_PostUninitialize(IInitializeSpy *iface, DWORD aptrefs) { - ok(0, "unexpected call\n"); + CHECK_EXPECT2(PostUninitialize); return E_NOTIMPL; } @@ -3343,76 +3368,134 @@ static const IInitializeSpyVtbl testinitializevtbl = static IInitializeSpy testinitialize = { &testinitializevtbl }; -static void test_IInitializeSpy(void) +static DWORD WINAPI test_init_spies_proc(void *arg) { - ULARGE_INTEGER cookie, cookie1, cookie2; HRESULT hr; + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr); + + hr = CoRevokeInitializeSpy(init_cookies[2]); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + + CoUninitialize(); + return 0; +} + +static void test_IInitializeSpy(BOOL mt) +{ + HRESULT hr; + + if (mt) + { + hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED); + ok(hr == S_OK, "CoInitializeEx failed: %#x\n", hr); + } + hr = CoRegisterInitializeSpy(NULL, NULL); ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); - cookie.QuadPart = 1; - hr = CoRegisterInitializeSpy(NULL, &cookie); + init_cookies[0].QuadPart = 1; + hr = CoRegisterInitializeSpy(NULL, &init_cookies[0]); ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); - ok(cookie.QuadPart == 1, "got wrong cookie\n"); + ok(init_cookies[0].QuadPart == 1, "got wrong cookie\n"); hr = CoRegisterInitializeSpy(&testinitialize, NULL); ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); - cookie.HighPart = 0; - cookie.LowPart = 1; - hr = CoRegisterInitializeSpy(&testinitialize, &cookie); + init_cookies[0].HighPart = 0; + init_cookies[0].LowPart = 1; + hr = CoRegisterInitializeSpy(&testinitialize, &init_cookies[0]); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { - ok(cookie.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie.HighPart, + ok(init_cookies[0].HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", init_cookies[0].HighPart, GetCurrentThreadId()); - ok(cookie.LowPart == 0, "got wrong low part 0x%x\n", cookie.LowPart); -} + if (!mt) ok(init_cookies[0].LowPart == 0, "got wrong low part 0x%x\n", init_cookies[0].LowPart); + /* register same instance one more time */ - cookie1.HighPart = 0; - cookie1.LowPart = 0; - hr = CoRegisterInitializeSpy(&testinitialize, &cookie1); -todo_wine { + init_cookies[1].HighPart = 0; + init_cookies[1].LowPart = 0; + hr = CoRegisterInitializeSpy(&testinitialize, &init_cookies[1]); ok(hr == S_OK, "got 0x%08x\n", hr); - ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart, + ok(init_cookies[1].HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", init_cookies[1].HighPart, GetCurrentThreadId()); - ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart); -} - cookie2.HighPart = 0; - cookie2.LowPart = 0; - hr = CoRegisterInitializeSpy(&testinitialize, &cookie2); -todo_wine { + if (!mt) ok(init_cookies[1].LowPart == 1, "got wrong low part 0x%x\n", init_cookies[1].LowPart); + + init_cookies[2].HighPart = 0; + init_cookies[2].LowPart = 0; + hr = CoRegisterInitializeSpy(&testinitialize, &init_cookies[2]); ok(hr == S_OK, "got 0x%08x\n", hr); - ok(cookie2.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie2.HighPart, + ok(init_cookies[2].HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", init_cookies[2].HighPart, GetCurrentThreadId()); - ok(cookie2.LowPart == 2, "got wrong low part 0x%x\n", cookie2.LowPart); -} - hr = CoRevokeInitializeSpy(cookie1); -todo_wine + if (!mt) ok(init_cookies[2].LowPart == 2, "got wrong low part 0x%x\n", init_cookies[2].LowPart); + + hr = CoRevokeInitializeSpy(init_cookies[1]); ok(hr == S_OK, "got 0x%08x\n", hr); - hr = CoRevokeInitializeSpy(cookie1); + hr = CoRevokeInitializeSpy(init_cookies[1]); ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); - cookie1.HighPart = 0; - cookie1.LowPart = 0; - hr = CoRegisterInitializeSpy(&testinitialize, &cookie1); -todo_wine { + init_cookies[1].HighPart = 0; + init_cookies[1].LowPart = 0; + hr = CoRegisterInitializeSpy(&testinitialize, &init_cookies[1]); ok(hr == S_OK, "got 0x%08x\n", hr); - ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart, + ok(init_cookies[1].HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", init_cookies[1].HighPart, GetCurrentThreadId()); - ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart); -} - hr = CoRevokeInitializeSpy(cookie); - ok(hr == S_OK, "got 0x%08x\n", hr); + if (!mt) ok(init_cookies[1].LowPart == 1, "got wrong low part 0x%x\n", init_cookies[1].LowPart); - hr = CoRevokeInitializeSpy(cookie1); -todo_wine - ok(hr == S_OK, "got 0x%08x\n", hr); + SET_EXPECT(PreInitialize); + SET_EXPECT(PostInitialize); + hr = CoInitializeEx(NULL, expected_coinit_flags = ((mt ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED) | COINIT_DISABLE_OLE1DDE)); + ok(hr == (mt ? S_FALSE : S_OK), "Failed to initialize COM, hr %#x.\n", hr); + CHECK_CALLED(PreInitialize, 3); + CHECK_CALLED(PostInitialize, 3); - hr = CoRevokeInitializeSpy(cookie2); -todo_wine - ok(hr == S_OK, "got 0x%08x\n", hr); + if (mt) + { + HANDLE thread; + thread = CreateThread(NULL, 0, test_init_spies_proc, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed: %u\n", GetLastError()); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + } + + SET_EXPECT(PreInitialize); + SET_EXPECT(PostInitialize); + hr = CoInitializeEx(NULL, expected_coinit_flags = ((mt ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED) | COINIT_DISABLE_OLE1DDE)); + ok(hr == S_FALSE, "Failed to initialize COM, hr %#x.\n", hr); + CHECK_CALLED(PreInitialize, 3); + CHECK_CALLED(PostInitialize, 3); + + SET_EXPECT(PreUninitialize); + SET_EXPECT(PostUninitialize); + CoUninitialize(); + CHECK_CALLED(PreUninitialize, 3); + CHECK_CALLED(PostUninitialize, 3); + + SET_EXPECT(PreUninitialize); + SET_EXPECT(PostUninitialize); + CoUninitialize(); + CHECK_CALLED(PreUninitialize, 3); + CHECK_CALLED(PostUninitialize, 3); + + if (mt) + { + SET_EXPECT(PreUninitialize); + SET_EXPECT(PostUninitialize); + CoUninitialize(); + CHECK_CALLED(PreUninitialize, 3); + CHECK_CALLED(PostUninitialize, 3); + } + + SET_EXPECT(PreInitialize); + SET_EXPECT(PostInitialize); + hr = CoInitializeEx(NULL, expected_coinit_flags = ((mt ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED) | COINIT_DISABLE_OLE1DDE)); + ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr); + CHECK_CALLED(PreInitialize, 3); + CHECK_CALLED(PostInitialize, 3); + + SET_EXPECT(PreUninitialize); + revoke_spies_on_uninit = TRUE; + CoUninitialize(); + CHECK_CALLED(PreUninitialize, 1); } static HRESULT g_persistfile_qi_ret; @@ -3755,10 +3838,10 @@ static DWORD CALLBACK implicit_mta_proc(void *param) hr = CoRegisterMessageFilter(NULL, NULL); ok(hr == CO_E_NOT_SUPPORTED, "got %#x\n", hr); - hr = CoLockObjectExternal((IUnknown *)&Test_Unknown, TRUE, TRUE); + hr = CoLockObjectExternal(&Test_Unknown, TRUE, TRUE); ok_ole_success(hr, "CoLockObjectExternal"); - hr = CoDisconnectObject((IUnknown *)&Test_Unknown, 0); + hr = CoDisconnectObject(&Test_Unknown, 0); ok_ole_success(hr, "CoDisconnectObject"); return 0; @@ -3824,7 +3907,8 @@ START_TEST(compobj) test_CoGetApartmentType(); test_IMallocSpy(); test_CoGetCurrentLogicalThreadId(); - test_IInitializeSpy(); + test_IInitializeSpy(FALSE); + test_IInitializeSpy(TRUE); test_CoGetInstanceFromFile(); test_GlobalOptions(); test_implicit_mta(); diff --git a/modules/rostests/winetests/ole32/marshal.c b/modules/rostests/winetests/ole32/marshal.c index 22a67960120..881eddde70c 100644 --- a/modules/rostests/winetests/ole32/marshal.c +++ b/modules/rostests/winetests/ole32/marshal.c @@ -329,7 +329,7 @@ static HRESULT WINAPI Test_IClassFactory_CreateInstance( LPVOID *ppvObj) { if (pUnkOuter) return CLASS_E_NOAGGREGATION; - return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj); + return IUnknown_QueryInterface(&Test_Unknown, riid, ppvObj); } static HRESULT WINAPI Test_IClassFactory_LockServer( @@ -1205,7 +1205,9 @@ static void test_marshal_proxy_apartment_shutdown(void) { HRESULT hr; IStream *pStream = NULL; - IUnknown *pProxy = NULL; + IClassFactory *proxy; + IUnknown *unk; + ULONG ref; DWORD tid; HANDLE thread; @@ -1220,7 +1222,7 @@ static void test_marshal_proxy_apartment_shutdown(void) ok_non_zero_external_conn(); IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy); + hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy); ok_ole_success(hr, CoUnmarshalInterface); IStream_Release(pStream); @@ -1233,7 +1235,11 @@ static void test_marshal_proxy_apartment_shutdown(void) ok_zero_external_conn(); ok_last_release_closes(TRUE); - IUnknown_Release(pProxy); + hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&unk); + ok(hr == CO_E_OBJNOTCONNECTED, "got %#x\n", hr); + + ref = IClassFactory_Release(proxy); + ok(!ref, "got %d refs\n", ref); ok_no_locks(); diff --git a/modules/rostests/winetests/ole32/ole_server.c b/modules/rostests/winetests/ole32/ole_server.c index 2f5a3ca5ea7..83f7c660dbb 100644 --- a/modules/rostests/winetests/ole32/ole_server.c +++ b/modules/rostests/winetests/ole32/ole_server.c @@ -244,7 +244,7 @@ static void ole_server(void) if (hr == S_OK) { trace("server: registering class object\n"); - hr = CoRegisterClassObject(&CLSID_WineTestObject, (IUnknown *)&factory, + hr = CoRegisterClassObject(&CLSID_WineTestObject, (IUnknown *)&factory.IClassFactory_iface, CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &key); if (hr == S_OK) { diff --git a/modules/rostests/winetests/ole32/propvariant.c b/modules/rostests/winetests/ole32/propvariant.c index 97c4eec4cac..b1ec76dfc91 100644 --- a/modules/rostests/winetests/ole32/propvariant.c +++ b/modules/rostests/winetests/ole32/propvariant.c @@ -18,6 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS +#ifdef __REACTOS__ +#define CONST_VTABLE +#endif + #include "windows.h" #include "wtypes.h" #include "ddeml.h" @@ -44,28 +49,28 @@ static const struct valid_mapping { { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_EMPTY */ { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_NULL */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I2 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I4 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R4 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R8 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_CY */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_DATE */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BSTR */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DISPATCH */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_ERROR */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BOOL */ - { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_VARIANT */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UNKNOWN */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DECIMAL */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I2 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I4 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R4 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R8 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_CY */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_DATE */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BSTR */ + { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DISPATCH */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_ERROR */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BOOL */ + { PROP_V1 | PROP_TODO , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_VARIANT */ + { PROP_V1 , PROP_V1, PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UNKNOWN */ + { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DECIMAL */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 15 */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_V1 , PROP_V1 | PROP_TODO }, /* VT_I1 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI1 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI2 */ - { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI4 */ + { PROP_V1 , PROP_V1 , PROP_V1 , PROP_V1 | PROP_TODO }, /* VT_I1 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI1 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI2 */ + { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI4 */ { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_I8 */ { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_UI8 */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_INT */ - { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UINT */ + { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_INT */ + { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UINT */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_VOID */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_HRESULT */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_PTR */ @@ -298,12 +303,60 @@ static void test_validtypes(void) } } +struct unk_impl +{ + IUnknown IUnknown_iface; + LONG ref; +}; + +static inline struct unk_impl *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct unk_impl, IUnknown_iface); +} + +static HRESULT WINAPI unk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + struct unk_impl *This = impl_from_IUnknown(iface); + if(winetest_debug > 1) + trace("Call to unk_QueryInterface()\n"); + *ppv = &This->IUnknown_iface; + IUnknown_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI unk_AddRef(IUnknown *iface) +{ + struct unk_impl *This = impl_from_IUnknown(iface); + if(winetest_debug > 1) + trace("Call to unk_AddRef()\n"); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI unk_Release(IUnknown *iface) +{ + struct unk_impl *This = impl_from_IUnknown(iface); + if(winetest_debug > 1) + trace("Call to unk_Release()\n"); + return InterlockedDecrement(&This->ref); +} + +static const IUnknownVtbl unk_vtbl = +{ + unk_QueryInterface, + unk_AddRef, + unk_Release +}; + static void test_copy(void) { static char szTestString[] = "Test String"; static WCHAR wszTestString[] = {'T','e','s','t',' ','S','t','r','i','n','g',0}; + struct unk_impl unk_obj = {{&unk_vtbl}, 1}; PROPVARIANT propvarSrc; PROPVARIANT propvarDst; + SAFEARRAY *sa; + SAFEARRAYBOUND sabound; + LONG saindex; HRESULT hr; propvarSrc.vt = VT_BSTR; @@ -334,6 +387,39 @@ static void test_copy(void) hr = PropVariantClear(&propvarDst); ok(hr == S_OK, "PropVariantClear(...VT_LPSTR...) failed\n"); memset(&propvarSrc, 0, sizeof(propvarSrc)); + + propvarSrc.vt = VT_UNKNOWN; + U(propvarSrc).punkVal = &unk_obj.IUnknown_iface; + hr = PropVariantCopy(&propvarDst, &propvarSrc); + ok(hr == S_OK, "PropVariantCopy(...VT_UNKNOWN...) failed: 0x%08x.\n", hr); + ok(U(propvarDst).punkVal == &unk_obj.IUnknown_iface, "Got wrong IUnknown pointer\n"); + ok(unk_obj.ref == 2, "got wrong refcount: %d.\n", unk_obj.ref); + hr = PropVariantClear(&propvarDst); + ok(hr == S_OK, "PropVariantClear(...VT_UNKNOWN...) failed: 0x%08x.\n", hr); + ok(unk_obj.ref == 1, "got wrong refcount: %d.\n", unk_obj.ref); + memset(&propvarSrc, 0, sizeof(propvarSrc)); + + sabound.lLbound = 0; + sabound.cElements = 2; + sa = SafeArrayCreate(VT_UNKNOWN, 1, &sabound); + saindex = 0; + SafeArrayPutElement(sa, &saindex, &unk_obj.IUnknown_iface); + saindex = 1; + SafeArrayPutElement(sa, &saindex, &unk_obj.IUnknown_iface); + ok(unk_obj.ref == 3, "got wrong refcount: %d.\n", unk_obj.ref); + + propvarSrc.vt = VT_ARRAY | VT_UNKNOWN; + U(propvarSrc).parray = sa; + hr = PropVariantCopy(&propvarDst, &propvarSrc); + ok(hr == S_OK, "PropVariantCopy(...VT_ARRAY|VT_UNKNOWN...) failed: 0x%08x.\n", hr); + ok(unk_obj.ref == 5, "got wrong refcount: %d.\n", unk_obj.ref); + hr = PropVariantClear(&propvarDst); + ok(hr == S_OK, "PropVariantClear(...VT_ARRAY|VT_UNKNOWN...) failed: 0x%08x.\n", hr); + ok(unk_obj.ref == 3, "got wrong refcount: %d.\n", unk_obj.ref); + hr = PropVariantClear(&propvarSrc); + ok(hr == S_OK, "PropVariantClear(...VT_ARRAY|VT_UNKNOWN...) failed: 0x%08x.\n", hr); + ok(unk_obj.ref == 1, "got wrong refcount: %d.\n", unk_obj.ref); + memset(&propvarSrc, 0, sizeof(propvarSrc)); } struct _PMemoryAllocator_vtable {