ole32: Determine the destination for the COM call and initialise the necessary parameters in ClientRpcChannelBuffer_GetBuffer instead of ClientRpcChannelBuffer_SendReceive.
The parameters are then freed in the matching ClientRpcChannelBuffer_FreeBuffer function.
This commit is contained in:
parent
13f9c71960
commit
d84f0abb70
125
dlls/ole32/rpc.c
125
dlls/ole32/rpc.c
|
@ -129,6 +129,8 @@ struct message_state
|
|||
SChannelHookCallInfo channel_hook_info;
|
||||
|
||||
/* client only */
|
||||
HWND target_hwnd;
|
||||
DWORD target_tid;
|
||||
struct dispatch_params params;
|
||||
};
|
||||
|
||||
|
@ -562,6 +564,24 @@ static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
|
|||
return HRESULT_FROM_WIN32(status);
|
||||
}
|
||||
|
||||
static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
|
||||
{
|
||||
HANDLE event = InterlockedExchangePointer(&This->event, NULL);
|
||||
|
||||
/* Note: must be auto-reset event so we can reuse it without a call
|
||||
* to ResetEvent */
|
||||
if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
|
||||
{
|
||||
if (InterlockedCompareExchangePointer(&This->event, event, NULL))
|
||||
/* already a handle cached in This */
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
|
||||
{
|
||||
ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
|
||||
|
@ -574,6 +594,9 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
|
|||
struct channel_hook_buffer_data *channel_hook_data;
|
||||
unsigned int channel_hook_count;
|
||||
ULONG extension_count;
|
||||
IPID ipid;
|
||||
HRESULT hr;
|
||||
APARTMENT *apt = NULL;
|
||||
|
||||
TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
|
||||
|
||||
|
@ -597,12 +620,17 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
|
|||
msg->Handle = This->bind;
|
||||
msg->RpcInterfaceInformation = cif;
|
||||
|
||||
message_state->prefix_data_len = 0;
|
||||
message_state->binding_handle = This->bind;
|
||||
|
||||
message_state->channel_hook_info.iid = *riid;
|
||||
message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
|
||||
message_state->channel_hook_info.uCausality = COM_CurrentCausalityId();
|
||||
message_state->channel_hook_info.dwServerPid = This->server_pid;
|
||||
message_state->channel_hook_info.iMethod = msg->ProcNum;
|
||||
message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
|
||||
message_state->target_hwnd = NULL;
|
||||
message_state->target_tid = 0;
|
||||
memset(&message_state->params, 0, sizeof(message_state->params));
|
||||
|
||||
extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
|
||||
|
@ -616,10 +644,40 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
|
|||
msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
|
||||
}
|
||||
|
||||
RpcBindingInqObject(message_state->binding_handle, &ipid);
|
||||
hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
|
||||
&message_state->params.chan,
|
||||
&message_state->params.iid,
|
||||
&message_state->params.iface);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
/* stub, chan, iface and iid are unneeded in multi-threaded case as we go
|
||||
* via the RPC runtime */
|
||||
if (apt->multi_threaded)
|
||||
{
|
||||
IRpcStubBuffer_Release(message_state->params.stub);
|
||||
message_state->params.stub = NULL;
|
||||
IRpcChannelBuffer_Release(message_state->params.chan);
|
||||
message_state->params.chan = NULL;
|
||||
message_state->params.iface = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
message_state->target_hwnd = apartment_getwindow(apt);
|
||||
message_state->target_tid = apt->tid;
|
||||
/* we assume later on that this being non-NULL is the indicator that
|
||||
* means call directly instead of going through RPC runtime */
|
||||
if (!message_state->target_hwnd)
|
||||
ERR("window for apartment %s is NULL\n", wine_dbgstr_longlong(apt->oxid));
|
||||
}
|
||||
}
|
||||
if (apt) apartment_release(apt);
|
||||
message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This);
|
||||
/* Note: message_state->params.msg is initialised in
|
||||
* ClientRpcChannelBuffer_SendReceive */
|
||||
|
||||
status = I_RpcGetBuffer(msg);
|
||||
|
||||
message_state->prefix_data_len = 0;
|
||||
message_state->binding_handle = This->bind;
|
||||
msg->Handle = message_state;
|
||||
|
||||
if (status == RPC_S_OK)
|
||||
|
@ -682,24 +740,6 @@ static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
|
||||
{
|
||||
HANDLE event = InterlockedExchangePointer(&This->event, NULL);
|
||||
|
||||
/* Note: must be auto-reset event so we can reuse it without a call
|
||||
* to ResetEvent */
|
||||
if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
|
||||
{
|
||||
if (InterlockedCompareExchangePointer(&This->event, event, NULL))
|
||||
/* already a handle cached in This */
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
/* this thread runs an outgoing RPC */
|
||||
static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
|
||||
{
|
||||
|
@ -735,8 +775,6 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
|
||||
RPC_STATUS status;
|
||||
DWORD index;
|
||||
APARTMENT *apt = NULL;
|
||||
IPID ipid;
|
||||
struct message_state *message_state;
|
||||
ORPCTHAT orpcthat;
|
||||
ORPC_EXTENT_ARRAY orpc_ext_array;
|
||||
|
@ -771,10 +809,6 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
|
||||
msg->BufferLength += message_state->prefix_data_len;
|
||||
|
||||
message_state->params.msg = olemsg;
|
||||
message_state->params.status = RPC_S_OK;
|
||||
message_state->params.hr = S_OK;
|
||||
|
||||
/* Note: this is an optimization in the Microsoft OLE runtime that we need
|
||||
* to copy, as shown by the test_no_couninitialize_client test. without
|
||||
* short-circuiting the RPC runtime in the case below, the test will
|
||||
|
@ -782,25 +816,16 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
* a thread to process the RPC when this function is called indirectly
|
||||
* from DllMain */
|
||||
|
||||
RpcBindingInqObject(message_state->binding_handle, &ipid);
|
||||
hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
|
||||
&message_state->params.chan,
|
||||
&message_state->params.iid,
|
||||
&message_state->params.iface);
|
||||
message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This);
|
||||
if ((hr == S_OK) && !apt->multi_threaded)
|
||||
message_state->params.msg = olemsg;
|
||||
if (message_state->target_hwnd)
|
||||
{
|
||||
TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
|
||||
TRACE("Calling apartment thread 0x%08x...\n", message_state->target_tid);
|
||||
|
||||
if (!PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0,
|
||||
if (!PostMessageW(message_state->target_hwnd, DM_EXECUTERPC, 0,
|
||||
(LPARAM)&message_state->params))
|
||||
{
|
||||
ERR("PostMessage failed with error %u\n", GetLastError());
|
||||
|
||||
IRpcStubBuffer_Release(message_state->params.stub);
|
||||
message_state->params.stub = NULL;
|
||||
IRpcChannelBuffer_Release(message_state->params.chan);
|
||||
message_state->params.chan = NULL;
|
||||
/* Note: message_state->params.iface doesn't have a reference and
|
||||
* so doesn't need to be released */
|
||||
|
||||
|
@ -809,16 +834,6 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
}
|
||||
else
|
||||
{
|
||||
if (hr == S_OK)
|
||||
{
|
||||
/* otherwise, we go via RPC runtime so the stub and channel aren't
|
||||
* needed here */
|
||||
IRpcStubBuffer_Release(message_state->params.stub);
|
||||
message_state->params.stub = NULL;
|
||||
IRpcChannelBuffer_Release(message_state->params.chan);
|
||||
message_state->params.chan = NULL;
|
||||
}
|
||||
|
||||
/* we use a separate thread here because we need to be able to
|
||||
* pump the message loop in the application thread: if we do not,
|
||||
* any windows created by this thread will hang and RPCs that try
|
||||
|
@ -833,7 +848,6 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
|
|||
else
|
||||
hr = S_OK;
|
||||
}
|
||||
if (apt) apartment_release(apt);
|
||||
|
||||
if (hr == S_OK)
|
||||
{
|
||||
|
@ -950,6 +964,11 @@ static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface
|
|||
|
||||
HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
|
||||
msg->RpcInterfaceInformation = NULL;
|
||||
|
||||
if (message_state->params.stub)
|
||||
IRpcStubBuffer_Release(message_state->params.stub);
|
||||
if (message_state->params.chan)
|
||||
IRpcChannelBuffer_Release(message_state->params.chan);
|
||||
HeapFree(GetProcessHeap(), 0, message_state);
|
||||
|
||||
TRACE("-- %ld\n", status);
|
||||
|
@ -1344,8 +1363,6 @@ exit_reset_state:
|
|||
|
||||
exit:
|
||||
HeapFree(GetProcessHeap(), 0, message_state);
|
||||
IRpcStubBuffer_Release(params->stub);
|
||||
IRpcChannelBuffer_Release(params->chan);
|
||||
if (params->handle) SetEvent(params->handle);
|
||||
}
|
||||
|
||||
|
@ -1418,6 +1435,10 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
|
|||
}
|
||||
|
||||
hr = params->hr;
|
||||
if (params->chan)
|
||||
IRpcChannelBuffer_Release(params->chan);
|
||||
if (params->stub)
|
||||
IRpcStubBuffer_Release(params->stub);
|
||||
HeapFree(GetProcessHeap(), 0, params);
|
||||
|
||||
apartment_release(apt);
|
||||
|
|
Loading…
Reference in New Issue