ole32: Allow unmarshalling objects into an implicit MTA.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-04-09 21:15:51 -05:00 committed by Alexandre Julliard
parent 084559fe85
commit a4cf16db08
5 changed files with 148 additions and 15 deletions

View File

@ -736,7 +736,7 @@ static APARTMENT *apartment_find_mta(void)
/* Return the current apartment if it exists, or, failing that, the MTA. Caller
* 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();
if (apt)

View File

@ -212,7 +212,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN;
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
const OXID_INFO *oxid_info,
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;
void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN;
HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN;
@ -248,6 +248,7 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN;
HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN;
HRESULT enter_apartment(struct oletls *info, DWORD model) 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) */
#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */

View File

@ -313,13 +313,15 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL
* the interfaces were returned */
if (SUCCEEDED(hr))
{
APARTMENT *apt = apartment_get_current_or_mta();
/* try to unmarshal each object returned to us */
for (i = 0; i < nonlocal_mqis; i++)
{
ULONG index = mapping[i];
HRESULT hrobj = qiresults[i].hResult;
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_data,
pMQIs[index].pIID, &This->oxid_info,
@ -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));
pMQIs[index].hr = hrobj;
}
apartment_release(apt);
}
/* free the memory allocated by the proxy */
@ -1010,8 +1014,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
return S_FALSE;
apt = COM_CurrentApt();
if (!apt)
if (!(apt = apartment_get_current_or_mta()))
return CO_E_NOTINITIALIZED;
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
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
/* 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->oxid_info, (void**)remunk);
if (hr == S_OK && called_in_original_apt)
@ -1056,6 +1059,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
}
}
LeaveCriticalSection(&This->cs);
apartment_release(apt);
TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
@ -1288,7 +1292,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
&proxy_manager->oxid_info,
proxy_manager->dest_context,
proxy_manager->dest_context_data,
&chanbuf);
&chanbuf, apt);
if (hr == S_OK)
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
riid, chanbuf, &ifproxy);
@ -1324,14 +1328,14 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
STDOBJREF stdobjref;
ULONG res;
HRESULT hres;
APARTMENT *apt = COM_CurrentApt();
APARTMENT *apt;
APARTMENT *stub_apt;
OXID oxid;
TRACE("(...,%s,....)\n", debugstr_guid(riid));
/* we need an apartment to unmarshal into */
if (!apt)
if (!(apt = apartment_get_current_or_mta()))
{
ERR("Apartment not initialized\n");
return CO_E_NOTINITIALIZED;
@ -1339,10 +1343,18 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
/* read STDOBJREF from wire */
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);
if (hres != S_OK) return hres;
if (hres != S_OK)
{
apartment_release(apt);
return hres;
}
/* check if we're marshalling back to ourselves */
if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
@ -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_int_release(stubmgr);
apartment_release(apt);
return hres;
}
@ -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);
else TRACE("Successfully created proxy %p\n", *ppv);
apartment_release(apt);
return hres;
}

View File

@ -830,14 +830,16 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
ORPC_EXTENT_ARRAY orpc_ext_array;
WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
HRESULT hrFault = S_OK;
APARTMENT *apt = apartment_get_current_or_mta();
TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt);
if (hr != S_OK)
{
ERR("called from wrong apartment, should have been 0x%s\n",
wine_dbgstr_longlong(This->oxid));
if (apt) apartment_release(apt);
return RPC_E_WRONG_THREAD;
}
/* This situation should be impossible in multi-threaded apartments,
@ -845,11 +847,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
* Note: doing a COM call during the processing of a sent message is
* only disallowed if a client call is already being waited for
* completion */
if (!COM_CurrentApt()->multi_threaded &&
if (!apt->multi_threaded &&
COM_CurrentInfo()->pending_call_count_client &&
InSendMessage())
{
ERR("can't make an outgoing COM call in response to a sent message\n");
apartment_release(apt);
return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
}
@ -967,6 +970,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
TRACE("-- 0x%08x\n", hr);
apartment_release(apt);
return hr;
}
@ -1094,7 +1098,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
const OXID_INFO *oxid_info,
DWORD dest_context, void *dest_context_data,
IRpcChannelBuffer **chan)
IRpcChannelBuffer **chan, APARTMENT *apt)
{
ClientRpcChannelBuffer *This;
WCHAR endpoint[200];
@ -1148,7 +1152,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
This->super.dest_context = dest_context;
This->super.dest_context_data = dest_context_data;
This->bind = bind;
apartment_getoxid(COM_CurrentApt(), &This->oxid);
apartment_getoxid(apt, &This->oxid);
This->server_pid = oxid_info->dwPid;
This->event = NULL;

View File

@ -3419,6 +3419,119 @@ static void test_manualresetevent(void)
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 char name[256];
@ -3765,6 +3878,7 @@ START_TEST(marshal)
register_test_window();
test_cocreateinstance_proxy();
test_implicit_mta();
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);