-- v2: ole32/tests: Check calling a proxy after re-creating the STA. ole32/tests: Add more tests with RPC from the wrong thread. ole32/tests: Add an test with implicit MTA creation.
From: Rémi Bernon rbernon@codeweavers.com
This checks what b4da14035741f287130002b512c7d0e9117da80a is fixing: The MTA is created from the thread which is already in an STA, apartment_findfromtid would return the MTA without that patch and RPC would fail. --- dlls/ole32/tests/marshal.c | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 8f7d0b47684..c1ff205f48c 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -64,6 +64,8 @@ static const GUID CLSID_ft_unmarshaler_1809 = {0x00000359, 0x0000, 0x0000, {0xc0
/* functions that are not present on all versions of Windows */ static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID); +static HRESULT (WINAPI *pCoIncrementMTAUsage)(CO_MTA_USAGE_COOKIE *cookie); +static HRESULT (WINAPI *pCoDecrementMTAUsage)(CO_MTA_USAGE_COOKIE cookie);
/* helper macros to make tests a bit leaner */ #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %ld\n", cLocks) @@ -1370,6 +1372,95 @@ static void test_marshal_proxy_mta_apartment_shutdown(void) CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); }
+static HRESULT WINAPI TestMTA_IClassFactory_CreateInstance( + LPCLASSFACTORY iface, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID *ppvObj) +{ + static CO_MTA_USAGE_COOKIE cookie; + HRESULT hr; + + if (!cookie) + { + hr = pCoIncrementMTAUsage(&cookie); + ok_ole_success(hr, CoIncrementMTAUsage); + } + else + { + hr = pCoDecrementMTAUsage(cookie); + ok_ole_success(hr, CoDecrementMTAUsage); + cookie = NULL; + } + + return Test_IClassFactory_CreateInstance(iface, pUnkOuter, riid, ppvObj); +} + +static const IClassFactoryVtbl TestMTAClassFactory_Vtbl = +{ + Test_IClassFactory_QueryInterface, + Test_IClassFactory_AddRef, + Test_IClassFactory_Release, + TestMTA_IClassFactory_CreateInstance, + Test_IClassFactory_LockServer +}; + +static IClassFactory Test_MTAClassFactory = { &TestMTAClassFactory_Vtbl }; + +/* tests that proxies are working when the host joins mta apartment */ +static void test_marshal_proxy_join_mta_apartment(void) +{ + HRESULT hr; + IStream *pStream = NULL; + IClassFactory *pProxy = NULL; + IUnknown *tmp; + HANDLE thread; + DWORD tid; + + if (!pCoIncrementMTAUsage) + { + win_skip("CoIncrementMTAUsage() is not available.\n"); + return; + } + + cLocks = 0; + external_connections = 0; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_MTAClassFactory, MSHLFLAGS_NORMAL, &thread); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy); + ok_ole_success(hr, CoUnmarshalInterface); + IStream_Release(pStream); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + /* do a call that will fail, but result in IRemUnknown being used by the proxy */ + IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream); + + hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, (void **)&tmp); + ok_ole_success(hr, IClassFactory_CreateInstance); + IUnknown_Release(tmp); + + hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, (void **)&tmp); + ok_ole_success(hr, IClassFactory_CreateInstance); + IUnknown_Release(tmp); + + IUnknown_Release(pProxy); + + ok_no_locks(); + ok_zero_external_conn(); + ok_last_release_closes(TRUE); + + end_host_object(tid, thread); +} + static void test_marshal_channel_buffer(void) { DWORD registration_key; @@ -4644,6 +4735,8 @@ START_TEST(marshal) char **argv;
pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject"); + pCoIncrementMTAUsage = (void*)GetProcAddress(hOle32, "CoIncrementMTAUsage"); + pCoDecrementMTAUsage = (void*)GetProcAddress(hOle32, "CoDecrementMTAUsage");
argc = winetest_get_mainargs( &argv ); if (argc > 2 && (!strcmp(argv[2], "-Embedding"))) @@ -4681,6 +4774,7 @@ START_TEST(marshal) test_marshal_stub_apartment_shutdown(); test_marshal_proxy_apartment_shutdown(); test_marshal_proxy_mta_apartment_shutdown(); + test_marshal_proxy_join_mta_apartment(); test_no_couninitialize_server(); test_no_couninitialize_client(); test_tableweak_marshal_and_unmarshal_twice();
From: Rémi Bernon rbernon@codeweavers.com
This checks that calling a method from a different STA than the iface has been marshalling from should fail with RPC_E_WRONG_THREAD. --- dlls/ole32/tests/marshal.c | 132 +++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+)
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index c1ff205f48c..4b5fff657bb 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -66,6 +66,7 @@ static const GUID CLSID_ft_unmarshaler_1809 = {0x00000359, 0x0000, 0x0000, {0xc0 static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID); static HRESULT (WINAPI *pCoIncrementMTAUsage)(CO_MTA_USAGE_COOKIE *cookie); static HRESULT (WINAPI *pCoDecrementMTAUsage)(CO_MTA_USAGE_COOKIE cookie); +static HRESULT (WINAPI *pCoGetApartmentType)(APTTYPE *type, APTTYPEQUALIFIER *qualifier);
/* helper macros to make tests a bit leaner */ #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %ld\n", cLocks) @@ -2649,10 +2650,20 @@ static void test_hresult_marshaling(void) /* helper for test_proxy_used_in_wrong_thread */ static DWORD CALLBACK bad_thread_proc(LPVOID p) { + APTTYPE type; + APTTYPEQUALIFIER qual; IClassFactory * cf = p; HRESULT hr; IUnknown * proxy = NULL;
+ if (pCoGetApartmentType) + { + hr = pCoGetApartmentType(&type, &qual); + ok(hr == CO_E_NOTINITIALIZED, "Got hr %#lx.\n", hr); + ok(type == APTTYPE_CURRENT, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + } + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); todo_wine ok(hr == CO_E_NOTINITIALIZED, "Got hr %#lx.\n", hr);
@@ -2666,8 +2677,63 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p) if (SUCCEEDED(hr)) IUnknown_Release(proxy);
+ if (pCoIncrementMTAUsage) + { + CO_MTA_USAGE_COOKIE cookie; + + hr = pCoIncrementMTAUsage(&cookie); + ok_ole_success(hr, CoIncrementMTAUsage); + + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_MTA, "got %d\n", type); + ok(qual == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d\n", qual); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); + if (proxy) IUnknown_Release(proxy); + ok(hr == RPC_E_WRONG_THREAD, + "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n", + hr); + + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + todo_wine ok(hr == RPC_E_WRONG_THREAD, "Got hr %#lx.\n", hr); + + hr = pCoDecrementMTAUsage(cookie); + ok_ole_success(hr, CoDecrementMTAUsage); + } + CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ if (pCoGetApartmentType) + { + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_MTA, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + } + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); + if (proxy) IUnknown_Release(proxy); + ok(hr == RPC_E_WRONG_THREAD, + "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n", + hr); + + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + todo_wine ok(hr == RPC_E_WRONG_THREAD, "Got hr %#lx.\n", hr); + + CoUninitialize(); + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok_ole_success(hr, CoInitializeEx); + + if (pCoGetApartmentType) + { + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_STA, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + } + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); if (proxy) IUnknown_Release(proxy); ok(hr == RPC_E_WRONG_THREAD, @@ -2685,6 +2751,65 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p) return 0; }
+/* helper for test_proxy_used_in_wrong_thread */ +static DWORD CALLBACK bad_thread_proc_sta(LPVOID p) +{ + APTTYPE type; + APTTYPEQUALIFIER qual; + IClassFactory * cf = p; + HRESULT hr; + IUnknown * proxy = NULL; + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok_ole_success(hr, CoInitializeEx); + + if (pCoGetApartmentType) + { + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_STA, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + } + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); + if (proxy) IUnknown_Release(proxy); + ok(hr == RPC_E_WRONG_THREAD, + "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n", + hr); + + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + todo_wine ok(hr == RPC_E_WRONG_THREAD, "Got hr %#lx.\n", hr); + + if (pCoIncrementMTAUsage) + { + CO_MTA_USAGE_COOKIE cookie; + + hr = pCoIncrementMTAUsage(&cookie); + ok_ole_success(hr, CoIncrementMTAUsage); + + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_STA, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); + if (proxy) IUnknown_Release(proxy); + ok(hr == RPC_E_WRONG_THREAD, + "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n", + hr); + + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + todo_wine ok(hr == RPC_E_WRONG_THREAD, "Got hr %#lx.\n", hr); + + hr = pCoDecrementMTAUsage(cookie); + ok_ole_success(hr, CoDecrementMTAUsage); + } + + CoUninitialize(); + + return 0; +} + /* tests failure case of a using a proxy in the wrong apartment */ static void test_proxy_used_in_wrong_thread(void) { @@ -2713,6 +2838,12 @@ static void test_proxy_used_in_wrong_thread(void) /* do a call that will fail, but result in IRemUnknown being used by the proxy */ IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
+ /* create a thread that we can misbehave in */ + thread = CreateThread(NULL, 0, bad_thread_proc_sta, pProxy, 0, &tid2); + + ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" ); + CloseHandle(thread); + /* create a thread that we can misbehave in */ thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2);
@@ -4737,6 +4868,7 @@ START_TEST(marshal) pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject"); pCoIncrementMTAUsage = (void*)GetProcAddress(hOle32, "CoIncrementMTAUsage"); pCoDecrementMTAUsage = (void*)GetProcAddress(hOle32, "CoDecrementMTAUsage"); + pCoGetApartmentType = (void*)GetProcAddress(hOle32, "CoGetApartmentType");
argc = winetest_get_mainargs( &argv ); if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ole32/tests/marshal.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 4b5fff657bb..5848e9a519a 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -1453,6 +1453,35 @@ static void test_marshal_proxy_join_mta_apartment(void) ok_ole_success(hr, IClassFactory_CreateInstance); IUnknown_Release(tmp);
+ if (pCoIncrementMTAUsage) + { + CO_MTA_USAGE_COOKIE cookie; + APTTYPEQUALIFIER qual; + APTTYPE type; + + pCoIncrementMTAUsage(&cookie); + + CoUninitialize(); + + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_MTA, "got %d\n", type); + ok(qual == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d\n", qual); + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok_ole_success(hr, CoInitializeEx); + + hr = pCoGetApartmentType(&type, &qual); + ok_ole_success(hr, CoGetApartmentType); + ok(type == APTTYPE_MAINSTA, "got %d\n", type); + ok(qual == 0, "got %d\n", qual); + + hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, (void **)&tmp); + ok(hr == CO_E_OBJNOTCONNECTED, "got %#lx\n", hr); + + pCoDecrementMTAUsage(cookie); + } + IUnknown_Release(pProxy);
ok_no_locks();