📄 rpc.c
字号:
InSendMessage())
{
ERR("can't make an outgoing COM call in response to a sent message\n");
return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
}
params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params));
if (!params) return E_OUTOFMEMORY;
message_state = (struct message_state *)msg->Handle;
/* restore the binding handle and the real start of data */
msg->Handle = message_state->binding_handle;
msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
msg->BufferLength += message_state->prefix_data_len;
params->msg = olemsg;
params->status = RPC_S_OK;
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
* deadlock on the loader lock due to the RPC runtime needing to create
* 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, ¶ms->stub, ¶ms->chan,
¶ms->iid, ¶ms->iface);
params->handle = ClientRpcChannelBuffer_GetEventHandle(This);
if ((hr == S_OK) && !apt->multi_threaded)
{
TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
if (!PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
{
ERR("PostMessage failed with error %u\n", GetLastError());
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
if (hr == S_OK)
{
/* otherwise, we go via RPC runtime so the stub and channel aren't
* needed here */
IRpcStubBuffer_Release(params->stub);
params->stub = NULL;
IRpcChannelBuffer_Release(params->chan);
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
* and re-enter this STA from an incoming server thread will
* deadlock. InstallShield is an example of that.
*/
if (!QueueUserWorkItem(rpc_sendreceive_thread, params, WT_EXECUTEDEFAULT))
{
ERR("QueueUserWorkItem failed with error %u\n", GetLastError());
hr = E_UNEXPECTED;
}
else
hr = S_OK;
}
if (apt) apartment_release(apt);
if (hr == S_OK)
{
if (WaitForSingleObject(params->handle, 0))
{
COM_CurrentInfo()->pending_call_count_client++;
hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index);
COM_CurrentInfo()->pending_call_count_client--;
}
}
ClientRpcChannelBuffer_ReleaseEventHandle(This, params->handle);
/* for WM shortcut, faults are returned in params->hr */
if (hr == S_OK)
hrFault = params->hr;
status = params->status;
HeapFree(GetProcessHeap(), 0, params);
params = NULL;
orpcthat.flags = ORPCF_NULL;
orpcthat.extensions = NULL;
/* for normal RPC calls, faults are returned in first 4 bytes of the
* buffer */
TRACE("RPC call status: 0x%lx\n", status);
if (status == RPC_S_CALL_FAILED)
hrFault = *(HRESULT *)olemsg->Buffer;
else if (status != RPC_S_OK)
hr = HRESULT_FROM_WIN32(status);
TRACE("hrFault = 0x%08x\n", hrFault);
/* FIXME: this condition should be
* "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)"
* but we don't currently reset the message length for PostMessage
* dispatched calls */
if (hr == S_OK && hrFault == S_OK)
{
HRESULT hr2;
char *original_buffer = msg->Buffer;
/* handle ORPCTHAT and client extensions */
hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent);
if (FAILED(hr2))
hr = hr2;
message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
msg->BufferLength -= message_state->prefix_data_len;
}
else
message_state->prefix_data_len = 0;
if (hr == S_OK)
{
ChannelHooks_ClientNotify(&message_state->channel_hook_info,
msg->DataRepresentation,
first_wire_orpc_extent,
orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0,
hrFault);
}
/* save away the message state again */
msg->Handle = message_state;
if (pstatus) *pstatus = status;
if (hr == S_OK)
hr = hrFault;
TRACE("-- 0x%08x\n", hr);
return hr;
}
static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
{
RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
RPC_STATUS status;
struct message_state *message_state;
TRACE("(%p)\n", msg);
message_state = (struct message_state *)msg->Handle;
/* restore the binding handle and the real start of data */
msg->Handle = message_state->binding_handle;
msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
msg->BufferLength += message_state->prefix_data_len;
message_state->prefix_data_len = 0;
status = I_RpcFreeBuffer(msg);
msg->Handle = message_state;
TRACE("-- %ld\n", status);
return HRESULT_FROM_WIN32(status);
}
static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
{
RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
RPC_STATUS status;
struct message_state *message_state;
TRACE("(%p)\n", msg);
message_state = (struct message_state *)msg->Handle;
/* restore the binding handle and the real start of data */
msg->Handle = message_state->binding_handle;
msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
msg->BufferLength += message_state->prefix_data_len;
status = I_RpcFreeBuffer(msg);
HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
msg->RpcInterfaceInformation = NULL;
HeapFree(GetProcessHeap(), 0, message_state);
TRACE("-- %ld\n", status);
return HRESULT_FROM_WIN32(status);
}
static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
{
ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
*pdwDestContext = This->dest_context;
*ppvDestContext = This->dest_context_data;
return S_OK;
}
static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
{
FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
return E_FAIL;
}
static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
{
TRACE("()\n");
/* native does nothing too */
return S_OK;
}
static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
{
RpcChannelBuffer_QueryInterface,
RpcChannelBuffer_AddRef,
ClientRpcChannelBuffer_Release,
ClientRpcChannelBuffer_GetBuffer,
ClientRpcChannelBuffer_SendReceive,
ClientRpcChannelBuffer_FreeBuffer,
ClientRpcChannelBuffer_GetDestCtx,
RpcChannelBuffer_IsConnected
};
static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
{
RpcChannelBuffer_QueryInterface,
RpcChannelBuffer_AddRef,
ServerRpcChannelBuffer_Release,
ServerRpcChannelBuffer_GetBuffer,
ServerRpcChannelBuffer_SendReceive,
ServerRpcChannelBuffer_FreeBuffer,
ServerRpcChannelBuffer_GetDestCtx,
RpcChannelBuffer_IsConnected
};
/* returns a channel buffer for proxies */
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
const OXID_INFO *oxid_info,
DWORD dest_context, void *dest_context_data,
IRpcChannelBuffer **chan)
{
ClientRpcChannelBuffer *This;
WCHAR endpoint[200];
RPC_BINDING_HANDLE bind;
RPC_STATUS status;
LPWSTR string_binding;
/* FIXME: get the endpoint from oxid_info->psa instead */
get_rpc_endpoint(endpoint, oxid);
TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
status = RpcStringBindingComposeW(
NULL,
wszRpcTransport,
NULL,
endpoint,
NULL,
&string_binding);
if (status == RPC_S_OK)
{
status = RpcBindingFromStringBindingW(string_binding, &bind);
if (status == RPC_S_OK)
{
IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
status = RpcBindingSetObject(bind, &ipid2);
if (status != RPC_S_OK)
RpcBindingFree(&bind);
}
RpcStringFreeW(&string_binding);
}
if (status != RPC_S_OK)
{
ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status);
return HRESULT_FROM_WIN32(status);
}
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if (!This)
{
RpcBindingFree(&bind);
return E_OUTOFMEMORY;
}
This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
This->super.refs = 1;
This->bind = bind;
apartment_getoxid(COM_CurrentApt(), &This->oxid);
This->server_pid = oxid_info->dwPid;
This->dest_context = dest_context;
This->dest_context_data = dest_context_data;
This->event = NULL;
*chan = (IRpcChannelBuffer*)This;
return S_OK;
}
HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
{
RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if (!This)
return E_OUTOFMEMORY;
This->lpVtbl = &ServerRpcChannelBufferVtbl;
This->refs = 1;
*chan = (IRpcChannelBuffer*)This;
return S_OK;
}
/* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate
* any memory */
static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end,
ORPC_EXTENT_ARRAY *extensions,
WIRE_ORPC_EXTENT **first_wire_orpc_extent)
{
DWORD pointer_id;
DWORD i;
memcpy(extensions, msg->Buffer, FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent));
msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
return RPC_E_INVALID_HEADER;
pointer_id = *(DWORD *)msg->Buffer;
msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
extensions->extent = NULL;
if (pointer_id)
{
WIRE_ORPC_EXTENT *wire_orpc_extent;
/* conformance */
if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1))
return RPC_S_INVALID_BOUND;
msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
/* arbritary limit for security (don't know what native does) */
if (extensions->size > 256)
{
ERR("too many extensions: %ld\n", extensions->size);
return RPC_S_INVALID_BOUND;
}
*first_wire_orpc_extent = wire_orpc_extent = (WIRE_ORPC_EXTENT *)msg->Buffer;
for (i = 0; i < ((extensions->size+1)&~1); i++)
{
if ((const char *)&wire_orpc_extent->data[0] > end)
return RPC_S_INVALID_BOUND;
if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
return RPC_S_INVALID_BOUND;
if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
return RPC_S_INVALID_BOUND;
TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
}
msg->Buffer = wire_orpc_extent;
}
return S_OK;
}
/* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -