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:
parent
084559fe85
commit
a4cf16db08
|
@ -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)
|
||||
|
|
|
@ -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 *) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue