Rob Shearman : ole32:
The identity functions can be used from apartments other than the one
the proxy was unmarshaled into .
Alexandre Julliard
julliard at wine.codeweavers.com
Tue May 22 07:00:12 CDT 2007
Module: wine
Branch: master
Commit: dd8a736c3fc8ebcbbce1d4c548ac0e57d5c3feff
URL: http://source.winehq.org/git/wine.git/?a=commit;h=dd8a736c3fc8ebcbbce1d4c548ac0e57d5c3feff
Author: Rob Shearman <rob at codeweavers.com>
Date: Mon May 21 16:45:17 2007 +0100
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 9c7d53c..d918347 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 843b220..e64b9f5 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();
More information about the wine-cvs
mailing list