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

📄 rpc.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
        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, &params->stub, &params->chan,
                                  &params->iid, &params->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, &params->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 + -