⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpc.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        WIRE_ORPC_EXTENT *wire_orpc_extent;
        for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
             i < extension_count;
             i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
        {
            if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
                break;
        }
        if (i == extension_count) wire_orpc_extent = NULL;

        IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid,
                                  wire_orpc_extent ? wire_orpc_extent->size : 0,
                                  wire_orpc_extent ? wire_orpc_extent->data : NULL,
                                  lDataRep, hrFault);
    }

    LeaveCriticalSection(&csChannelHook);
}

HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook)
{
    struct channel_hook_entry *entry;

    TRACE("(%s, %p)\n", debugstr_guid(rguid), hook);

    entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
    if (!entry)
        return E_OUTOFMEMORY;

    memcpy(&entry->id, rguid, sizeof(entry->id));
    entry->hook = hook;
    IChannelHook_AddRef(hook);

    EnterCriticalSection(&csChannelHook);
    list_add_tail(&channel_hooks, &entry->entry);
    LeaveCriticalSection(&csChannelHook);

    return S_OK;
}

void RPC_UnregisterAllChannelHooks(void)
{
    struct channel_hook_entry *cursor;
    struct channel_hook_entry *cursor2;

    EnterCriticalSection(&csChannelHook);
    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
        HeapFree(GetProcessHeap(), 0, cursor);
    LeaveCriticalSection(&csChannelHook);
}

/* RPC Channel Buffer Functions */

static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
{
    *ppv = NULL;
    if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
    {
        *ppv = (LPVOID)iface;
        IUnknown_AddRef(iface);
        return S_OK;
    }
    return E_NOINTERFACE;
}

static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
{
    RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
    return InterlockedIncrement(&This->refs);
}

static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
{
    RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
    ULONG ref;

    ref = InterlockedDecrement(&This->refs);
    if (ref)
        return ref;

    HeapFree(GetProcessHeap(), 0, This);
    return 0;
}

static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
{
    ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
    ULONG ref;

    ref = InterlockedDecrement(&This->super.refs);
    if (ref)
        return ref;

    if (This->event) CloseHandle(This->event);
    RpcBindingFree(&This->bind);
    HeapFree(GetProcessHeap(), 0, This);
    return 0;
}

static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
{
    RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
    RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
    RPC_STATUS status;
    ORPCTHAT *orpcthat;
    struct message_state *message_state;
    ULONG extensions_size;
    struct channel_hook_buffer_data *channel_hook_data;
    unsigned int channel_hook_count;
    ULONG extension_count;

    TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));

    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;

    extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info,
                                                 &channel_hook_data, &channel_hook_count, &extension_count);

    msg->BufferLength += FIELD_OFFSET(ORPCTHAT, extensions) + 4;
    if (extensions_size)
    {
        msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size;
        if (extension_count & 1)
            msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
    }

    status = I_RpcGetBuffer(msg);

    orpcthat = (ORPCTHAT *)msg->Buffer;
    msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHAT, extensions);

    orpcthat->flags = ORPCF_NULL /* FIXME? */;

    /* NDR representation of orpcthat->extensions */
    *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
    msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);

    if (extensions_size)
    {
        ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
        orpc_extent_array->size = extension_count;
        orpc_extent_array->reserved = 0;
        msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
        /* NDR representation of orpc_extent_array->extent */
        *(DWORD *)msg->Buffer = 1;
        msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
        /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
        *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
        msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);

        msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info,
                                                    msg->Buffer, channel_hook_data, channel_hook_count);

        /* we must add a dummy extension if there is an odd extension
         * count to meet the contract specified by the size_is attribute */
        if (extension_count & 1)
        {
            WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
            wire_orpc_extent->conformance = 0;
            memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id));
            wire_orpc_extent->size = 0;
            msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
        }
    }

    /* store the prefixed data length so that we can restore the real buffer
     * later */
    message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat;
    msg->BufferLength -= message_state->prefix_data_len;
    /* save away the message state again */
    msg->Handle = message_state;

    TRACE("-- %ld\n", status);

    return HRESULT_FROM_WIN32(status);
}

static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
{
    ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
    RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
    RPC_CLIENT_INTERFACE *cif;
    RPC_STATUS status;
    ORPCTHIS *orpcthis;
    struct message_state *message_state;
    ULONG extensions_size;
    struct channel_hook_buffer_data *channel_hook_data;
    unsigned int channel_hook_count;
    ULONG extension_count;

    TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));

    cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
    if (!cif)
        return E_OUTOFMEMORY;

    message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
    if (!message_state)
    {
        HeapFree(GetProcessHeap(), 0, cif);
        return E_OUTOFMEMORY;
    }

    cif->Length = sizeof(RPC_CLIENT_INTERFACE);
    /* RPC interface ID = COM interface ID */
    cif->InterfaceId.SyntaxGUID = *riid;
    /* COM objects always have a version of 0.0 */
    cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
    cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
    msg->Handle = This->bind;
    msg->RpcInterfaceInformation = cif;

    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 */

    extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
        &channel_hook_data, &channel_hook_count, &extension_count);

    msg->BufferLength += FIELD_OFFSET(ORPCTHIS, extensions) + 4;
    if (extensions_size)
    {
        msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size;
        if (extension_count & 1)
            msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
    }

    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)
    {
        orpcthis = (ORPCTHIS *)msg->Buffer;
        msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);

        orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
        orpcthis->version.MinorVersion = COM_MINOR_VERSION;
        orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
        orpcthis->reserved1 = 0;
        orpcthis->cid = message_state->channel_hook_info.uCausality;

        /* NDR representation of orpcthis->extensions */
        *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
        msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);

        if (extensions_size)
        {
            ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
            orpc_extent_array->size = extension_count;
            orpc_extent_array->reserved = 0;
            msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
            /* NDR representation of orpc_extent_array->extent */
            *(DWORD *)msg->Buffer = 1;
            msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
            /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
            *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
            msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);

            msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
                msg->Buffer, channel_hook_data, channel_hook_count);

            /* we must add a dummy extension if there is an odd extension
             * count to meet the contract specified by the size_is attribute */
            if (extension_count & 1)
            {
                WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
                wire_orpc_extent->conformance = 0;
                memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id));
                wire_orpc_extent->size = 0;
                msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
            }
        }

        /* store the prefixed data length so that we can restore the real buffer
         * pointer in ClientRpcChannelBuffer_SendReceive. */
        message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
        msg->BufferLength -= message_state->prefix_data_len;
    }

    TRACE("-- %ld\n", status);

    return HRESULT_FROM_WIN32(status);
}

static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
{
    FIXME("stub\n");
    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)
{
    struct dispatch_params *data = (struct dispatch_params *) param;

    /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level
     * RPC functions do */
    data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);

    TRACE("completed with status 0x%lx\n", data->status);

    SetEvent(data->handle);

    return 0;
}

static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt)
{
    OXID oxid;
    if (!apt)
        return S_FALSE;
    if (apartment_getoxid(apt, &oxid) != S_OK)
        return S_FALSE;
    if (This->oxid != oxid)
        return S_FALSE;
    return S_OK;
}

static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
{
    ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
    HRESULT hr;
    RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
    RPC_STATUS status;
    DWORD index;
    struct dispatch_params *params;
    APARTMENT *apt = NULL;
    IPID ipid;
    struct message_state *message_state;
    ORPCTHAT orpcthat;
    ORPC_EXTENT_ARRAY orpc_ext_array;
    WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
    HRESULT hrFault = S_OK;

    TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);

    hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
    if (hr != S_OK)
    {
        ERR("called from wrong apartment, should have been 0x%s\n",
            wine_dbgstr_longlong(This->oxid));
        return RPC_E_WRONG_THREAD;
    }
    /* this situation should be impossible in multi-threaded apartments,
     * because the calling thread isn't re-entrable.
     * 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 &&
        COM_CurrentInfo()->pending_call_count_client &&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -