From dd8a736c3fc8ebcbbce1d4c548ac0e57d5c3feff Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Mon, 21 May 2007 16:45:17 +0100 Subject: [PATCH] ole32: The identity functions can be used from apartments other than the one the proxy was unmarshaled into. In this case, don't use the cached This->remunk and don't cache the unmarshaled object in This->remunk. --- dlls/ole32/marshal.c | 19 +++++++++++++++---- dlls/ole32/tests/marshal.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 9c7d53c6cb4..d9183473be3 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -298,7 +298,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL ULONG index = mapping[i]; HRESULT hrobj = qiresults[i].hResult; if (hrobj == S_OK) - hrobj = unmarshal_object(&qiresults[i].std, This->parent, + hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(), This->dest_context, This->dest_context_data, pMQIs[index].pIID, &This->oxid_info, @@ -964,14 +964,25 @@ static void proxy_manager_disconnect(struct proxy_manager * This) static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk) { HRESULT hr = S_OK; + struct apartment *apt; + BOOL called_in_original_apt; /* we don't want to try and unmarshal or use IRemUnknown if we don't want * lifetime management */ if (This->sorflags & SORFP_NOLIFETIMEMGMT) return S_FALSE; + apt = COM_CurrentApt(); + if (!apt) + return CO_E_NOTINITIALIZED; + + called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid); + EnterCriticalSection(&This->cs); - if (This->remunk) + /* only return the cached object if called from the original apartment. + * in future, we might want to make the IRemUnknown proxy callable from any + * apartment to avoid these checks */ + if (This->remunk && called_in_original_apt) { /* already created - return existing object */ *remunk = This->remunk; @@ -994,10 +1005,10 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk stdobjref.ipid = This->oxid_info.ipidRemUnknown; /* do the unmarshal */ - hr = unmarshal_object(&stdobjref, This->parent, This->dest_context, + hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context, This->dest_context_data, &IID_IRemUnknown, &This->oxid_info, (void**)remunk); - if (hr == S_OK) + if (hr == S_OK && called_in_original_apt) { This->remunk = *remunk; IRemUnknown_AddRef(This->remunk); diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 843b2204fdf..e64b9f5bfb4 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -1283,6 +1283,24 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p) HRESULT hr; IUnknown * proxy = NULL; + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); + todo_wine + ok(hr == CO_E_NOTINITIALIZED, + "COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n", + hr); + + hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy); + /* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */ + trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr); + if (SUCCEEDED(hr)) + IUnknown_Release(proxy); + + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */ + trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr); + if (SUCCEEDED(hr)) + IUnknown_Release(proxy); + pCoInitializeEx(NULL, COINIT_MULTITHREADED); hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy); @@ -1291,6 +1309,19 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p) "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n", hr); + hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy); + /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */ + trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr); + + /* this statement causes Win9x DCOM to crash during CoUninitialize of + * other apartment, so don't test this on Win9x (signified by NT-only + * export of CoRegisterSurrogateEx) */ + if (GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx")) + /* now be really bad and release the proxy from the wrong apartment */ + IUnknown_Release(cf); + else + skip("skipping test for releasing proxy from wrong apartment that will succeed, but cause a crash during CoUninitialize\n"); + CoUninitialize(); return 0; @@ -1321,13 +1352,18 @@ static void test_proxy_used_in_wrong_thread(void) ok_more_than_one_lock(); + /* do a call that will fail, but result in IRemUnknown being used by the proxy */ + IClassFactory_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream); + /* create a thread that we can misbehave in */ thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); - IUnknown_Release(pProxy); + /* do release statement on Win9x that we should have done above */ + if (!GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx")) + IUnknown_Release(pProxy); ok_no_locks();