diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 9fbff88ea76..fdb49cbbe96 100644 --- a/dlls/ole32/rpc.c +++ b/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);