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

📄 marshal.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
             * instead of making new proxy do a roundtrip through the server */
            do
            {
                ULONG cPublicRefsNew;
                cPublicRefsOld = cPublicRefs;
                stdobjref.cPublicRefs = cPublicRefs / 2;
                cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
                cPublicRefs = InterlockedCompareExchange(
                    (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
            } while (cPublicRefs != cPublicRefsOld);
        }

        /* normal and table-strong marshaling need at least one reference */
        if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
        {
            IRemUnknown *remunk;
            hr = proxy_manager_get_remunknown(This, &remunk);
            if (hr == S_OK)
            {
                HRESULT hrref = S_OK;
                REMINTERFACEREF rif;
                rif.ipid = ifproxy->stdobjref.ipid;
                rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
                rif.cPrivateRefs = 0;
                hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
                IRemUnknown_Release(remunk);
                if (hr == S_OK && hrref == S_OK)
                {
                    /* table-strong marshaling doesn't give the refs to the
                     * client that unmarshals the STDOBJREF */
                    if (mshlflags != MSHLFLAGS_TABLESTRONG)
                        stdobjref.cPublicRefs = rif.cPublicRefs;
                }
                else
                    ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
            }
        }

        if (SUCCEEDED(hr))
        {
            TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
                stdobjref.flags, stdobjref.cPublicRefs,
                wine_dbgstr_longlong(stdobjref.oxid),
                wine_dbgstr_longlong(stdobjref.oid),
                debugstr_guid(&stdobjref.ipid));
            hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
        }
    }
    else
    {
        /* we don't have the interface already unmarshaled so we have to
         * request the object from the server */
        IRemUnknown *remunk;
        IPID *ipid;
        REMQIRESULT *qiresults = NULL;
        IID iid = *riid;

        /* get the ipid of the first entry */
        /* FIXME: should we implement ClientIdentity on the ifproxies instead
         * of the proxy_manager so we use the correct ipid here? */
        ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;

        /* get IRemUnknown proxy so we can communicate with the remote object */
        hr = proxy_manager_get_remunknown(This, &remunk);

        if (hr == S_OK)
        {
            hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
                                               1, &iid, &qiresults);
            if (SUCCEEDED(hr))
            {
                hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
                if (FAILED(hr))
                {
                    REMINTERFACEREF rif;
                    rif.ipid = qiresults->std.ipid;
                    rif.cPublicRefs = qiresults->std.cPublicRefs;
                    rif.cPrivateRefs = 0;
                    IRemUnknown_RemRelease(remunk, 1, &rif);
                }
                CoTaskMemFree(qiresults);
            }
            else
                ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
            IRemUnknown_Release(remunk);
        }
    }

    return hr;
}

static const IMarshalVtbl ProxyMarshal_Vtbl =
{
    Proxy_QueryInterface,
    Proxy_AddRef,
    Proxy_Release,
    StdMarshalImpl_GetUnmarshalClass,
    StdMarshalImpl_GetMarshalSizeMax,
    Proxy_MarshalInterface,
    StdMarshalImpl_UnmarshalInterface,
    StdMarshalImpl_ReleaseMarshalData,
    StdMarshalImpl_DisconnectObject
};

static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
{
    ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
    return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
}

static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
{
    ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
    return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
}

static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
{
    ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
    return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
}

static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
                                               IUnknown *pProxy,
                                               DWORD *pAuthnSvc,
                                               DWORD *pAuthzSvc,
                                               OLECHAR **pServerPrincName,
                                               DWORD *pAuthnLevel,
                                               DWORD *pImpLevel,
                                               void **pAuthInfo,
                                               DWORD *pCapabilities)
{
    FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
          pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
          pCapabilities);
    return E_NOTIMPL;
}

static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
                                             IUnknown *pProxy, DWORD AuthnSvc,
                                             DWORD AuthzSvc,
                                             OLECHAR *pServerPrincName,
                                             DWORD AuthnLevel, DWORD ImpLevel,
                                             void *pAuthInfo,
                                             DWORD Capabilities)
{
    FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc,
          AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel,
          pAuthInfo, Capabilities);
    return E_NOTIMPL;
}

static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
                                            IUnknown *pProxy, IUnknown **ppCopy)
{
    FIXME("(%p, %p): stub\n", pProxy, ppCopy);
    *ppCopy = NULL;
    return E_NOTIMPL;
}

static const IClientSecurityVtbl ProxyCliSec_Vtbl =
{
    ProxyCliSec_QueryInterface,
    ProxyCliSec_AddRef,
    ProxyCliSec_Release,
    ProxyCliSec_QueryBlanket,
    ProxyCliSec_SetBlanket,
    ProxyCliSec_CopyProxy
};

static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
{
    HRESULT hr = S_OK;

    if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
    {
        ERR("Wait failed for ifproxy %p\n", This);
        return E_UNEXPECTED;
    }

    if (This->refs == 0)
    {
        IRemUnknown *remunk = NULL;

        TRACE("getting public ref for ifproxy %p\n", This);

        hr = proxy_manager_get_remunknown(This->parent, &remunk);
        if (hr == S_OK)
        {
            HRESULT hrref = S_OK;
            REMINTERFACEREF rif;
            rif.ipid = This->stdobjref.ipid;
            rif.cPublicRefs = NORMALEXTREFS;
            rif.cPrivateRefs = 0;
            hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
            IRemUnknown_Release(remunk);
            if (hr == S_OK && hrref == S_OK)
                InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
            else
                ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
        }
    }
    ReleaseMutex(This->parent->remoting_mutex);

    return hr;
}

static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
{
    HRESULT hr = S_OK;
    LONG public_refs;

    if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
    {
        ERR("Wait failed for ifproxy %p\n", This);
        return E_UNEXPECTED;
    }

    public_refs = This->refs;
    if (public_refs > 0)
    {
        IRemUnknown *remunk = NULL;

        TRACE("releasing %d refs\n", public_refs);

        hr = proxy_manager_get_remunknown(This->parent, &remunk);
        if (hr == S_OK)
        {
            REMINTERFACEREF rif;
            rif.ipid = This->stdobjref.ipid;
            rif.cPublicRefs = public_refs;
            rif.cPrivateRefs = 0;
            hr = IRemUnknown_RemRelease(remunk, 1, &rif);
            IRemUnknown_Release(remunk);
            if (hr == S_OK)
                InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
            else if (hr == RPC_E_DISCONNECTED)
                WARN("couldn't release references because object was "
                     "disconnected: oxid = %s, oid = %s\n",
                     wine_dbgstr_longlong(This->parent->oxid),
                     wine_dbgstr_longlong(This->parent->oid));
            else
                ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
        }
    }
    ReleaseMutex(This->parent->remoting_mutex);

    return hr;
}

/* should be called inside This->parent->cs critical section */
static void ifproxy_disconnect(struct ifproxy * This)
{
    ifproxy_release_public_refs(This);
    if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);

    IRpcChannelBuffer_Release(This->chan);
    This->chan = NULL;
}

/* should be called in This->parent->cs critical section if it is an entry in parent's list */
static void ifproxy_destroy(struct ifproxy * This)
{
    TRACE("%p\n", This);

    /* release public references to this object so that the stub can know
     * when to destroy itself */
    ifproxy_release_public_refs(This);

    list_remove(&This->entry);

    if (This->chan)
    {
        IRpcChannelBuffer_Release(This->chan);
        This->chan = NULL;
    }

    if (This->proxy) IRpcProxyBuffer_Release(This->proxy);

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

static HRESULT proxy_manager_construct(
    APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
    const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
{
    struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
    if (!This) return E_OUTOFMEMORY;

    This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
    if (!This->remoting_mutex)
    {
        HeapFree(GetProcessHeap(), 0, This);
        return HRESULT_FROM_WIN32(GetLastError());
    }

    if (oxid_info)
    {
        This->oxid_info.dwPid = oxid_info->dwPid;
        This->oxid_info.dwTid = oxid_info->dwTid;
        This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
        This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
        This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
    }
    else
    {
        HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
        if (FAILED(hr))
        {
            CloseHandle(This->remoting_mutex);
            HeapFree(GetProcessHeap(), 0, This);
            return hr;
        }
    }

    This->lpVtbl = &ClientIdentity_Vtbl;
    This->lpVtblMarshal = &ProxyMarshal_Vtbl;
    This->lpVtblCliSec = &ProxyCliSec_Vtbl;

    list_init(&This->entry);
    list_init(&This->interfaces);

    InitializeCriticalSection(&This->cs);
    DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");

    /* the apartment the object was unmarshaled into */
    This->parent = apt;

    /* the source apartment and id of the object */
    This->oxid = oxid;
    This->oid = oid;

    This->refs = 1;

    /* the DCOM draft specification states that the SORF_NOPING flag is
     * proxy manager specific, not ifproxy specific, so this implies that we
     * should store the STDOBJREF flags here in the proxy manager. */
    This->sorflags = sorflags;

    /* we create the IRemUnknown proxy on demand */
    This->remunk = NULL;

    /* initialise these values to the weakest values and they will be
     * overwritten in proxy_manager_set_context */
    This->dest_context = MSHCTX_INPROC;
    This->dest_context_data = NULL;

    EnterCriticalSection(&apt->cs);
    /* FIXME: we are dependent on the ordering in here to make sure a proxy's
     * IRemUnknown proxy doesn't get destroyed before the regual proxy does
     * because we need the IRemUnknown proxy during the destruction of the
     * regular proxy. Ideally, we should maintain a separate list for the
     * IRemUnknown proxies that need late destruction */
    list_add_tail(&apt->proxies, &This->entry);
    LeaveCriticalSection(&apt->cs);

    TRACE("%p created for OXID %s, OID %s\n", This,
        wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));

    *proxy_manager = This;
    return S_OK;
}

static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
{
    MSHCTX old_dest_context = This->dest_context;
    MSHCTX new_dest_context;

    do
    {
        new_dest_context = old_dest_context;
        /* "stronger" values overwrite "weaker" values. stronger values are
         * ones that disable more optimisations */
        switch (old_dest_context)
        {
        case MSHCTX_INPROC:
            new_dest_context = dest_context;
            break;
        case MSHCTX_CROSSCTX:
            switch (dest_context)
            {
            case MSHCTX_INPROC:
                break;
            default:
                new_dest_context = dest_context;
            }
            break;

⌨️ 快捷键说明

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