📄 rpc.c
字号:
{
const char *end = (char *)msg->Buffer + msg->BufferLength;
*first_wire_orpc_extent = NULL;
if (msg->BufferLength < FIELD_OFFSET(ORPCTHIS, extensions) + 4)
{
ERR("invalid buffer length\n");
return RPC_E_INVALID_HEADER;
}
memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(ORPCTHIS, extensions));
msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);
if ((const char *)msg->Buffer + sizeof(DWORD) > end)
return RPC_E_INVALID_HEADER;
if (*(DWORD *)msg->Buffer)
orpcthis->extensions = orpc_ext_array;
else
orpcthis->extensions = NULL;
msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
if (orpcthis->extensions)
{
HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
first_wire_orpc_extent);
if (FAILED(hr))
return hr;
}
if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
(orpcthis->version.MinorVersion > COM_MINOR_VERSION))
{
ERR("COM version {%d, %d} not supported\n",
orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
return RPC_E_VERSION_MISMATCH;
}
if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
{
ERR("invalid flags 0x%lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
return RPC_E_INVALID_HEADER;
}
return S_OK;
}
static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
{
const char *end = (char *)msg->Buffer + msg->BufferLength;
*first_wire_orpc_extent = NULL;
if (msg->BufferLength < FIELD_OFFSET(ORPCTHAT, extensions) + 4)
{
ERR("invalid buffer length\n");
return RPC_E_INVALID_HEADER;
}
memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(ORPCTHAT, extensions));
msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHAT, extensions);
if ((const char *)msg->Buffer + sizeof(DWORD) > end)
return RPC_E_INVALID_HEADER;
if (*(DWORD *)msg->Buffer)
orpcthat->extensions = orpc_ext_array;
else
orpcthat->extensions = NULL;
msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
if (orpcthat->extensions)
{
HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
first_wire_orpc_extent);
if (FAILED(hr))
return hr;
}
if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
{
ERR("invalid flags 0x%lx\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
return RPC_E_INVALID_HEADER;
}
return S_OK;
}
void RPC_ExecuteCall(struct dispatch_params *params)
{
struct message_state *message_state = NULL;
RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
char *original_buffer = msg->Buffer;
ORPCTHIS orpcthis;
ORPC_EXTENT_ARRAY orpc_ext_array;
WIRE_ORPC_EXTENT *first_wire_orpc_extent;
GUID old_causality_id;
/* handle ORPCTHIS and server extensions */
params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
if (params->hr != S_OK)
{
msg->Buffer = original_buffer;
goto exit;
}
message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
if (!message_state)
{
params->hr = E_OUTOFMEMORY;
msg->Buffer = original_buffer;
goto exit;
}
message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
message_state->binding_handle = msg->Handle;
message_state->channel_hook_info.iid = params->iid;
message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
message_state->channel_hook_info.uCausality = orpcthis.cid;
message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
message_state->channel_hook_info.iMethod = msg->ProcNum;
message_state->channel_hook_info.pObject = params->iface;
if (orpcthis.extensions && first_wire_orpc_extent &&
orpcthis.extensions->size)
ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
msg->Handle = message_state;
msg->BufferLength -= message_state->prefix_data_len;
/* call message filter */
if (COM_CurrentApt()->filter)
{
DWORD handlecall;
INTERFACEINFO interface_info;
CALLTYPE calltype;
interface_info.pUnk = params->iface;
interface_info.iid = params->iid;
interface_info.wMethod = msg->ProcNum;
if (IsEqualGUID(&orpcthis.cid, &COM_CurrentInfo()->causality_id))
calltype = CALLTYPE_NESTED;
else if (COM_CurrentInfo()->pending_call_count_server == 0)
calltype = CALLTYPE_TOPLEVEL;
else
calltype = CALLTYPE_TOPLEVEL_CALLPENDING;
handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter,
calltype,
(HTASK)GetCurrentProcessId(),
0 /* FIXME */,
&interface_info);
TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall);
switch (handlecall)
{
case SERVERCALL_REJECTED:
params->hr = RPC_E_CALL_REJECTED;
goto exit_reset_state;
case SERVERCALL_RETRYLATER:
#if 0 /* FIXME: handle retries on the client side before enabling this code */
params->hr = RPC_E_RETRY;
goto exit_reset_state;
#else
FIXME("retry call later not implemented\n");
break;
#endif
case SERVERCALL_ISHANDLED:
default:
break;
}
}
/* invoke the method */
/* save the old causality ID - note: any calls executed while processing
* messages received during the SendReceive will appear to originate from
* this call - this should be checked with what Windows does */
old_causality_id = COM_CurrentInfo()->causality_id;
COM_CurrentInfo()->causality_id = orpcthis.cid;
COM_CurrentInfo()->pending_call_count_server++;
params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
COM_CurrentInfo()->pending_call_count_server--;
COM_CurrentInfo()->causality_id = old_causality_id;
exit_reset_state:
message_state = (struct message_state *)msg->Handle;
msg->Handle = message_state->binding_handle;
msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
msg->BufferLength += message_state->prefix_data_len;
exit:
HeapFree(GetProcessHeap(), 0, message_state);
IRpcStubBuffer_Release(params->stub);
IRpcChannelBuffer_Release(params->chan);
if (params->handle) SetEvent(params->handle);
}
static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
{
struct dispatch_params *params;
APARTMENT *apt;
IPID ipid;
HRESULT hr;
RpcBindingInqObject(msg->Handle, &ipid);
TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
if (!params)
{
RpcRaiseException(E_OUTOFMEMORY);
return;
}
hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan,
¶ms->iid, ¶ms->iface);
if (hr != S_OK)
{
ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
HeapFree(GetProcessHeap(), 0, params);
RpcRaiseException(hr);
return;
}
params->msg = (RPCOLEMESSAGE *)msg;
params->status = RPC_S_OK;
params->hr = S_OK;
params->handle = NULL;
/* Note: this is the important difference between STAs and MTAs - we
* always execute RPCs to STAs in the thread that originally created the
* apartment (i.e. the one that pumps messages to the window) */
if (!apt->multi_threaded)
{
params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
WaitForSingleObject(params->handle, INFINITE);
else
{
ERR("PostMessage failed with error %u\n", GetLastError());
IRpcChannelBuffer_Release(params->chan);
IRpcStubBuffer_Release(params->stub);
}
CloseHandle(params->handle);
}
else
{
BOOL joined = FALSE;
if (!COM_CurrentInfo()->apt)
{
apartment_joinmta();
joined = TRUE;
}
RPC_ExecuteCall(params);
if (joined)
{
apartment_release(COM_CurrentInfo()->apt);
COM_CurrentInfo()->apt = NULL;
}
}
hr = params->hr;
HeapFree(GetProcessHeap(), 0, params);
apartment_release(apt);
/* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
* the RPC runtime that the call failed */
if (hr) RpcRaiseException(hr);
}
/* stub registration */
HRESULT RPC_RegisterInterface(REFIID riid)
{
struct registered_if *rif;
BOOL found = FALSE;
HRESULT hr = S_OK;
TRACE("(%s)\n", debugstr_guid(riid));
EnterCriticalSection(&csRegIf);
LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry)
{
if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
{
rif->refs++;
found = TRUE;
break;
}
}
if (!found)
{
TRACE("Creating new interface\n");
rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
if (rif)
{
RPC_STATUS status;
rif->refs = 1;
rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
/* RPC interface ID = COM interface ID */
rif->If.InterfaceId.SyntaxGUID = *riid;
rif->If.DispatchTable = &rpc_dispatch;
/* all other fields are 0, including the version asCOM objects
* always have a version of 0.0 */
status = RpcServerRegisterIfEx(
(RPC_IF_HANDLE)&rif->If,
NULL, NULL,
RPC_IF_OLE | RPC_IF_AUTOLISTEN,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
NULL);
if (status == RPC_S_OK)
list_add_tail(®istered_interfaces, &rif->entry);
else
{
ERR("RpcServerRegisterIfEx failed with error %ld\n", status);
HeapFree(GetProcessHeap(), 0, rif);
hr = HRESULT_FROM_WIN32(status);
}
}
else
hr = E_OUTOFMEMORY;
}
LeaveCriticalSection(&csRegIf);
return hr;
}
/* stub unregistration */
void RPC_UnregisterInterface(REFIID riid)
{
struct registered_if *rif;
EnterCriticalSection(&csRegIf);
LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry)
{
if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
{
if (!--rif->refs)
{
RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
list_remove(&rif->entry);
HeapFree(GetProcessHeap(), 0, rif);
}
break;
}
}
LeaveCriticalSection(&csRegIf);
}
/* get the info for an OXID, including the IPID for the rem unknown interface
* and the string binding */
HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info)
{
TRACE("%s\n", wine_dbgstr_longlong(oxid));
oxid_info->dwTid = 0;
oxid_info->dwPid = 0;
oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
/* FIXME: this is a hack around not having an OXID resolver yet -
* this function should contact the machine's OXID resolver and then it
* should give us the IPID of the IRemUnknown interface */
oxid_info->ipidRemUnknown.Data1 = 0xffffffff;
oxid_info->ipidRemUnknown.Data2 = 0xffff;
oxid_info->ipidRemUnknown.Data3 = 0xffff;
memcpy(&oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID));
oxid_info->psa = NULL /* FIXME */;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -