Commit a4cf16db authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

ole32: Allow unmarshalling objects into an implicit MTA.

parent 084559fe
...@@ -736,7 +736,7 @@ static APARTMENT *apartment_find_mta(void) ...@@ -736,7 +736,7 @@ static APARTMENT *apartment_find_mta(void)
/* Return the current apartment if it exists, or, failing that, the MTA. Caller /* Return the current apartment if it exists, or, failing that, the MTA. Caller
* must free the returned apartment in either case. */ * must free the returned apartment in either case. */
static APARTMENT *apartment_get_current_or_mta(void) APARTMENT *apartment_get_current_or_mta(void)
{ {
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
if (apt) if (apt)
......
...@@ -212,7 +212,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN; ...@@ -212,7 +212,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN;
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
const OXID_INFO *oxid_info, const OXID_INFO *oxid_info,
DWORD dest_context, void *dest_context_data, DWORD dest_context, void *dest_context_data,
IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; IRpcChannelBuffer **chan, APARTMENT *apt) DECLSPEC_HIDDEN;
HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN;
void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN; void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN;
HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN; HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN;
...@@ -248,6 +248,7 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; ...@@ -248,6 +248,7 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN;
HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN;
HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN;
void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN;
APARTMENT *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN;
/* DCOM messages used by the apartment window (not compatible with native) */ /* DCOM messages used by the apartment window (not compatible with native) */
#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */
......
...@@ -313,13 +313,15 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL ...@@ -313,13 +313,15 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL
* the interfaces were returned */ * the interfaces were returned */
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
APARTMENT *apt = apartment_get_current_or_mta();
/* try to unmarshal each object returned to us */ /* try to unmarshal each object returned to us */
for (i = 0; i < nonlocal_mqis; i++) for (i = 0; i < nonlocal_mqis; i++)
{ {
ULONG index = mapping[i]; ULONG index = mapping[i];
HRESULT hrobj = qiresults[i].hResult; HRESULT hrobj = qiresults[i].hResult;
if (hrobj == S_OK) if (hrobj == S_OK)
hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(), hrobj = unmarshal_object(&qiresults[i].std, apt,
This->dest_context, This->dest_context,
This->dest_context_data, This->dest_context_data,
pMQIs[index].pIID, &This->oxid_info, pMQIs[index].pIID, &This->oxid_info,
...@@ -331,6 +333,8 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL ...@@ -331,6 +333,8 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL
ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
pMQIs[index].hr = hrobj; pMQIs[index].hr = hrobj;
} }
apartment_release(apt);
} }
/* free the memory allocated by the proxy */ /* free the memory allocated by the proxy */
...@@ -1010,8 +1014,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk ...@@ -1010,8 +1014,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
if (This->sorflags & SORFP_NOLIFETIMEMGMT) if (This->sorflags & SORFP_NOLIFETIMEMGMT)
return S_FALSE; return S_FALSE;
apt = COM_CurrentApt(); if (!(apt = apartment_get_current_or_mta()))
if (!apt)
return CO_E_NOTINITIALIZED; return CO_E_NOTINITIALIZED;
called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid); called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
...@@ -1046,7 +1049,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk ...@@ -1046,7 +1049,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
stdobjref.ipid = This->oxid_info.ipidRemUnknown; stdobjref.ipid = This->oxid_info.ipidRemUnknown;
/* do the unmarshal */ /* do the unmarshal */
hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context, hr = unmarshal_object(&stdobjref, apt, This->dest_context,
This->dest_context_data, &IID_IRemUnknown, This->dest_context_data, &IID_IRemUnknown,
&This->oxid_info, (void**)remunk); &This->oxid_info, (void**)remunk);
if (hr == S_OK && called_in_original_apt) if (hr == S_OK && called_in_original_apt)
...@@ -1056,6 +1059,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk ...@@ -1056,6 +1059,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
} }
} }
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
apartment_release(apt);
TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr); TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
...@@ -1288,7 +1292,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, ...@@ -1288,7 +1292,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
&proxy_manager->oxid_info, &proxy_manager->oxid_info,
proxy_manager->dest_context, proxy_manager->dest_context,
proxy_manager->dest_context_data, proxy_manager->dest_context_data,
&chanbuf); &chanbuf, apt);
if (hr == S_OK) if (hr == S_OK)
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
riid, chanbuf, &ifproxy); riid, chanbuf, &ifproxy);
...@@ -1324,14 +1328,14 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v ...@@ -1324,14 +1328,14 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
STDOBJREF stdobjref; STDOBJREF stdobjref;
ULONG res; ULONG res;
HRESULT hres; HRESULT hres;
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt;
APARTMENT *stub_apt; APARTMENT *stub_apt;
OXID oxid; OXID oxid;
TRACE("(...,%s,....)\n", debugstr_guid(riid)); TRACE("(...,%s,....)\n", debugstr_guid(riid));
/* we need an apartment to unmarshal into */ /* we need an apartment to unmarshal into */
if (!apt) if (!(apt = apartment_get_current_or_mta()))
{ {
ERR("Apartment not initialized\n"); ERR("Apartment not initialized\n");
return CO_E_NOTINITIALIZED; return CO_E_NOTINITIALIZED;
...@@ -1339,10 +1343,18 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v ...@@ -1339,10 +1343,18 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
/* read STDOBJREF from wire */ /* read STDOBJREF from wire */
hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
if (hres != S_OK) return STG_E_READFAULT; if (hres != S_OK)
{
apartment_release(apt);
return STG_E_READFAULT;
}
hres = apartment_getoxid(apt, &oxid); hres = apartment_getoxid(apt, &oxid);
if (hres != S_OK) return hres; if (hres != S_OK)
{
apartment_release(apt);
return hres;
}
/* check if we're marshalling back to ourselves */ /* check if we're marshalling back to ourselves */
if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
...@@ -1357,6 +1369,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v ...@@ -1357,6 +1369,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE); stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE);
stub_manager_int_release(stubmgr); stub_manager_int_release(stubmgr);
apartment_release(apt);
return hres; return hres;
} }
...@@ -1395,6 +1408,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v ...@@ -1395,6 +1408,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres); if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
else TRACE("Successfully created proxy %p\n", *ppv); else TRACE("Successfully created proxy %p\n", *ppv);
apartment_release(apt);
return hres; return hres;
} }
......
...@@ -830,14 +830,16 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac ...@@ -830,14 +830,16 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
ORPC_EXTENT_ARRAY orpc_ext_array; ORPC_EXTENT_ARRAY orpc_ext_array;
WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL; WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
HRESULT hrFault = S_OK; HRESULT hrFault = S_OK;
APARTMENT *apt = apartment_get_current_or_mta();
TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod); TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt()); hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt);
if (hr != S_OK) if (hr != S_OK)
{ {
ERR("called from wrong apartment, should have been 0x%s\n", ERR("called from wrong apartment, should have been 0x%s\n",
wine_dbgstr_longlong(This->oxid)); wine_dbgstr_longlong(This->oxid));
if (apt) apartment_release(apt);
return RPC_E_WRONG_THREAD; return RPC_E_WRONG_THREAD;
} }
/* This situation should be impossible in multi-threaded apartments, /* This situation should be impossible in multi-threaded apartments,
...@@ -845,11 +847,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac ...@@ -845,11 +847,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
* Note: doing a COM call during the processing of a sent message is * Note: doing a COM call during the processing of a sent message is
* only disallowed if a client call is already being waited for * only disallowed if a client call is already being waited for
* completion */ * completion */
if (!COM_CurrentApt()->multi_threaded && if (!apt->multi_threaded &&
COM_CurrentInfo()->pending_call_count_client && COM_CurrentInfo()->pending_call_count_client &&
InSendMessage()) InSendMessage())
{ {
ERR("can't make an outgoing COM call in response to a sent message\n"); ERR("can't make an outgoing COM call in response to a sent message\n");
apartment_release(apt);
return RPC_E_CANTCALLOUT_ININPUTSYNCCALL; return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
} }
...@@ -967,6 +970,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac ...@@ -967,6 +970,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
TRACE("-- 0x%08x\n", hr); TRACE("-- 0x%08x\n", hr);
apartment_release(apt);
return hr; return hr;
} }
...@@ -1094,7 +1098,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = ...@@ -1094,7 +1098,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
const OXID_INFO *oxid_info, const OXID_INFO *oxid_info,
DWORD dest_context, void *dest_context_data, DWORD dest_context, void *dest_context_data,
IRpcChannelBuffer **chan) IRpcChannelBuffer **chan, APARTMENT *apt)
{ {
ClientRpcChannelBuffer *This; ClientRpcChannelBuffer *This;
WCHAR endpoint[200]; WCHAR endpoint[200];
...@@ -1148,7 +1152,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, ...@@ -1148,7 +1152,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
This->super.dest_context = dest_context; This->super.dest_context = dest_context;
This->super.dest_context_data = dest_context_data; This->super.dest_context_data = dest_context_data;
This->bind = bind; This->bind = bind;
apartment_getoxid(COM_CurrentApt(), &This->oxid); apartment_getoxid(apt, &This->oxid);
This->server_pid = oxid_info->dwPid; This->server_pid = oxid_info->dwPid;
This->event = NULL; This->event = NULL;
......
...@@ -3419,6 +3419,119 @@ static void test_manualresetevent(void) ...@@ -3419,6 +3419,119 @@ static void test_manualresetevent(void)
ok(!ref, "Got nonzero ref: %d\n", ref); ok(!ref, "Got nonzero ref: %d\n", ref);
} }
static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
{
IStream *stream = param;
IClassFactory *cf;
IUnknown *proxy;
HRESULT hr;
IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
ok_ole_success(hr, CoUnmarshalInterface);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
ok_ole_success(hr, IClassFactory_CreateInstance);
IUnknown_Release(proxy);
/* But if we initialize an STA in this apartment, it becomes the wrong one. */
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
CoUninitialize();
ok_more_than_one_lock();
ok_non_zero_external_conn();
IClassFactory_Release(cf);
ok_no_locks();
ok_zero_external_conn();
ok_last_release_closes(TRUE);
return 0;
}
static DWORD CALLBACK implicit_mta_use_proc(void *param)
{
IClassFactory *cf = param;
IUnknown *proxy;
HRESULT hr;
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
ok_ole_success(hr, IClassFactory_CreateInstance);
IUnknown_Release(proxy);
/* But if we initialize an STA in this apartment, it becomes the wrong one. */
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
CoUninitialize();
return 0;
}
static void test_implicit_mta(void)
{
HANDLE host_thread, thread;
IClassFactory *cf;
IStream *stream;
HRESULT hr;
DWORD tid;
cLocks = 0;
external_connections = 0;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
/* Firstly: we can unmarshal and use an object while in the implicit MTA. */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok_ole_success(hr, CreateStreamOnHGlobal);
tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
ok_more_than_one_lock();
ok_non_zero_external_conn();
thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
CloseHandle(thread);
IStream_Release(stream);
end_host_object(tid, host_thread);
/* Secondly: we can unmarshal an object into the real MTA and then use it
* from the implicit MTA. */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok_ole_success(hr, CreateStreamOnHGlobal);
tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
ok_more_than_one_lock();
ok_non_zero_external_conn();
IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
ok_ole_success(hr, CoUnmarshalInterface);
thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
CloseHandle(thread);
IClassFactory_Release(cf);
IStream_Release(stream);
ok_no_locks();
ok_non_zero_external_conn();
ok_last_release_closes(TRUE);
end_host_object(tid, host_thread);
CoUninitialize();
}
static const char *debugstr_iid(REFIID riid) static const char *debugstr_iid(REFIID riid)
{ {
static char name[256]; static char name[256];
...@@ -3765,6 +3878,7 @@ START_TEST(marshal) ...@@ -3765,6 +3878,7 @@ START_TEST(marshal)
register_test_window(); register_test_window();
test_cocreateinstance_proxy(); test_cocreateinstance_proxy();
test_implicit_mta();
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment