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

📄 moniker.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 *	Monikers
 *
 *	Copyright 1998	Marcus Meissner
 *      Copyright 1999  Noomen Hamza
 *      Copyright 2005  Robert Shearman (for CodeWeavers)
 *      Copyright 2007  Robert Shearman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * TODO:
 * - IRunningObjectTable should work interprocess, but currently doesn't.
 *   Native (on Win2k at least) uses an undocumented RPC interface, IROT, to
 *   communicate with RPCSS which contains the table of marshalled data.
 */

#include <assert.h>
#include <stdarg.h>
#include <string.h>

#define COBJMACROS

#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wtypes.h"
#include "ole2.h"

#include "wine/list.h"
#include "wine/debug.h"
#include "wine/unicode.h"

#include "compobj_private.h"
#include "moniker.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

/* see MSDN docs for IROTData::GetComparisonData, which states what this
 * constant is (http://msdn2.microsoft.com/en-us/library/ms693773.aspx) */
#define MAX_COMPARISON_DATA 2048

/* define the structure of the running object table elements */
struct rot_entry
{
    struct list        entry;
    MInterfacePointer* object; /* marshaled running object*/
    MInterfacePointer* moniker; /* marshaled moniker that identifies this object */
    MInterfacePointer* moniker_data; /* moniker comparison data that identifies this object */
    DWORD              cookie; /* cookie identifying this object */
    FILETIME           last_modified;
};

/* define the RunningObjectTableImpl structure */
typedef struct RunningObjectTableImpl
{
    const IRunningObjectTableVtbl *lpVtbl;
    LONG ref;

    struct list rot; /* list of ROT entries */
    CRITICAL_SECTION lock;
} RunningObjectTableImpl;

static RunningObjectTableImpl* runningObjectTableInstance = NULL;



static inline HRESULT WINAPI
IrotRegister(DWORD *cookie)
{
    static LONG last_cookie = 1;
    *cookie = InterlockedIncrement(&last_cookie);
    return S_OK;
}

/* define the EnumMonikerImpl structure */
typedef struct EnumMonikerImpl
{
    const IEnumMonikerVtbl *lpVtbl;
    LONG ref;

    MInterfacePointer **monikers;
    ULONG moniker_count;
    ULONG pos;
} EnumMonikerImpl;


/* IEnumMoniker Local functions*/
static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers,
    ULONG moniker_count, ULONG pos, IEnumMoniker **ppenumMoniker);

static HRESULT create_stream_on_mip_ro(const MInterfacePointer *mip, IStream **stream)
{
    HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData);
    void *pv = GlobalLock(hglobal);
    memcpy(pv, mip->abData, mip->ulCntData);
    GlobalUnlock(hglobal);
    return CreateStreamOnHGlobal(hglobal, TRUE, stream);
}

static inline void rot_entry_delete(struct rot_entry *rot_entry)
{
    /* FIXME: revoke entry from rpcss's copy of the ROT */
    if (rot_entry->object)
    {
        IStream *stream;
        HRESULT hr;
        hr = create_stream_on_mip_ro(rot_entry->object, &stream);
        if (hr == S_OK)
        {
            CoReleaseMarshalData(stream);
            IUnknown_Release(stream);
        }
    }
    if (rot_entry->moniker)
    {
        IStream *stream;
        HRESULT hr;
        hr = create_stream_on_mip_ro(rot_entry->moniker, &stream);
        if (hr == S_OK)
        {
            CoReleaseMarshalData(stream);
            IUnknown_Release(stream);
        }
    }
    HeapFree(GetProcessHeap(), 0, rot_entry->object);
    HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
    HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
    HeapFree(GetProcessHeap(), 0, rot_entry);
}

/* moniker_data must be freed with HeapFree when no longer in use */
static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer **moniker_data)
{
    HRESULT hr;
    IROTData *pROTData = NULL;
    hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData);
    if (SUCCEEDED(hr))
    {
        ULONG size = MAX_COMPARISON_DATA;
        *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
        hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size);
        if (hr != S_OK)
        {
            ERR("Failed to copy comparison data into buffer, hr = 0x%08x\n", hr);
            HeapFree(GetProcessHeap(), 0, *moniker_data);
            return hr;
        }
        (*moniker_data)->ulCntData = size;
    }
    else
    {
        IBindCtx *pbc;
        LPOLESTR pszDisplayName;
        CLSID clsid;
        int len;

        TRACE("generating comparison data from display name\n");

        hr = CreateBindCtx(0, &pbc);
        if (FAILED(hr))
            return hr;
        hr = IMoniker_GetDisplayName(pMoniker, pbc, NULL, &pszDisplayName);
        IBindCtx_Release(pbc);
        if (FAILED(hr))
            return hr;
        hr = IMoniker_GetClassID(pMoniker, &clsid);
        if (FAILED(hr))
        {
            CoTaskMemFree(pszDisplayName);
            return hr;
        }

        len = strlenW(pszDisplayName);
        *moniker_data = HeapAlloc(GetProcessHeap(), 0,
            FIELD_OFFSET(MInterfacePointer, abData[sizeof(CLSID) + (len+1)*sizeof(WCHAR)]));
        if (!*moniker_data)
        {
            CoTaskMemFree(pszDisplayName);
            return E_OUTOFMEMORY;
        }
        (*moniker_data)->ulCntData = sizeof(CLSID) + (len+1)*sizeof(WCHAR);

        memcpy(&(*moniker_data)->abData[0], &clsid, sizeof(clsid));
        memcpy(&(*moniker_data)->abData[sizeof(clsid)], pszDisplayName, (len+1)*sizeof(WCHAR));
    }
    return S_OK;
}

static HRESULT reduce_moniker(IMoniker *pmk, IBindCtx *pbc, IMoniker **pmkReduced)
{
    IBindCtx *pbcNew = NULL;
    HRESULT hr;
    if (!pbc)
    {
        hr = CreateBindCtx(0, &pbcNew);
        if (FAILED(hr))
            return hr;
        pbc = pbcNew;
    }
    hr = IMoniker_Reduce(pmk, pbc, MKRREDUCE_ALL, NULL, pmkReduced);
    if (FAILED(hr))
        ERR("reducing moniker failed with error 0x%08x\n", hr);
    if (pbcNew) IBindCtx_Release(pbcNew);
    return hr;
}

/***********************************************************************
 *        RunningObjectTable_QueryInterface
 */
static HRESULT WINAPI
RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface,
                                      REFIID riid,void** ppvObject)
{
    RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;

    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);

    /* validate arguments */

    if (ppvObject==0)
        return E_INVALIDARG;

    *ppvObject = 0;

    if (IsEqualIID(&IID_IUnknown, riid) ||
        IsEqualIID(&IID_IRunningObjectTable, riid))
        *ppvObject = (IRunningObjectTable*)This;

    if ((*ppvObject)==0)
        return E_NOINTERFACE;

    IRunningObjectTable_AddRef(iface);

    return S_OK;
}

/***********************************************************************
 *        RunningObjectTable_AddRef
 */
static ULONG WINAPI
RunningObjectTableImpl_AddRef(IRunningObjectTable* iface)
{
    RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;

    TRACE("(%p)\n",This);

    return InterlockedIncrement(&This->ref);
}

/***********************************************************************
 *        RunningObjectTable_Initialize
 */
static HRESULT WINAPI
RunningObjectTableImpl_Destroy(void)
{
    struct list *cursor, *cursor2;

    TRACE("()\n");

    if (runningObjectTableInstance==NULL)
        return E_INVALIDARG;

    /* free the ROT table memory */
    LIST_FOR_EACH_SAFE(cursor, cursor2, &runningObjectTableInstance->rot)
    {
        struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
        list_remove(&rot_entry->entry);
        rot_entry_delete(rot_entry);
    }

    DEBUG_CLEAR_CRITSEC_NAME(&runningObjectTableInstance->lock);
    DeleteCriticalSection(&runningObjectTableInstance->lock);

    /* free the ROT structure memory */
    HeapFree(GetProcessHeap(),0,runningObjectTableInstance);
    runningObjectTableInstance = NULL;

    return S_OK;
}

/***********************************************************************
 *        RunningObjectTable_Release
 */
static ULONG WINAPI
RunningObjectTableImpl_Release(IRunningObjectTable* iface)
{
    RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
    ULONG ref;

    TRACE("(%p)\n",This);

    ref = InterlockedDecrement(&This->ref);

    /* uninitialize ROT structure if there's no more references to it */
    if (ref == 0)
    {
        struct list *cursor, *cursor2;
        LIST_FOR_EACH_SAFE(cursor, cursor2, &This->rot)
        {
            struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
            list_remove(&rot_entry->entry);
            rot_entry_delete(rot_entry);
        }
        /*  RunningObjectTable data structure will be not destroyed here ! the destruction will be done only
         *  when RunningObjectTableImpl_UnInitialize function is called
         */
    }

    return ref;
}

/***********************************************************************
 *        RunningObjectTable_Register
 *
 * PARAMS
 * grfFlags       [in] Registration options 
 * punkObject     [in] the object being registered
 * pmkObjectName  [in] the moniker of the object being registered
 * pdwRegister    [in] the value identifying the registration
 */
static HRESULT WINAPI
RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags,
               IUnknown *punkObject, IMoniker *pmkObjectName, DWORD *pdwRegister)
{
    RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
    struct rot_entry *rot_entry;
    HRESULT hr = S_OK;
    IStream *pStream = NULL;
    DWORD mshlflags;
    IBindCtx *pbc;

    TRACE("(%p,%d,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister);

    if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
    {
        ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
        return E_INVALIDARG;
    }

    if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL)
        return E_INVALIDARG;

    rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
    if (!rot_entry)
        return E_OUTOFMEMORY;

    /* marshal object */
    hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        return hr;
    }
    mshlflags = (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK;
    hr = CoMarshalInterface(pStream, &IID_IUnknown, punkObject, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, mshlflags);
    /* FIXME: a cleaner way would be to create an IStream class that writes
     * directly to an MInterfacePointer */
    if (hr == S_OK)
    {
        HGLOBAL hglobal;
        hr = GetHGlobalFromStream(pStream, &hglobal);
        if (hr == S_OK)
        {
            SIZE_T size = GlobalSize(hglobal);
            const void *pv = GlobalLock(hglobal);
            rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
            rot_entry->object->ulCntData = size;
            memcpy(&rot_entry->object->abData, pv, size);
            GlobalUnlock(hglobal);
        }
    }
    IStream_Release(pStream);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        return hr;
    }

    hr = CreateBindCtx(0, &pbc);
    if (FAILED(hr))
    {
        rot_entry_delete(rot_entry);
        return hr;
    }

    hr = reduce_moniker(pmkObjectName, pbc, &pmkObjectName);
    if (FAILED(hr))
    {
        rot_entry_delete(rot_entry);
        IBindCtx_Release(pbc);
        return hr;
    }

    hr = IMoniker_GetTimeOfLastChange(pmkObjectName, pbc, NULL,
                                      &rot_entry->last_modified);
    IBindCtx_Release(pbc);
    if (FAILED(hr))
    {
        CoFileTimeNow(&rot_entry->last_modified);
        hr = S_OK;
    }

    hr = get_moniker_comparison_data(pmkObjectName,
                                     &rot_entry->moniker_data);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        IMoniker_Release(pmkObjectName);
        return hr;
    }

    hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        IMoniker_Release(pmkObjectName);
        return hr;
    }
    /* marshal moniker */
    hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName,
                            MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG);
    /* FIXME: a cleaner way would be to create an IStream class that writes
     * directly to an MInterfacePointer */
    if (hr == S_OK)
    {
        HGLOBAL hglobal;
        hr = GetHGlobalFromStream(pStream, &hglobal);
        if (hr == S_OK)
        {
            SIZE_T size = GlobalSize(hglobal);
            const void *pv = GlobalLock(hglobal);
            rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
            rot_entry->moniker->ulCntData = size;
            memcpy(&rot_entry->moniker->abData, pv, size);
            GlobalUnlock(hglobal);
        }
    }
    IStream_Release(pStream);
    IMoniker_Release(pmkObjectName);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        return hr;
    }

    /* FIXME: not the right signature of IrotRegister function */
    hr = IrotRegister(&rot_entry->cookie);
    if (hr != S_OK)
    {
        rot_entry_delete(rot_entry);
        return hr;
    }

    /* gives a registration identifier to the registered object*/
    *pdwRegister = rot_entry->cookie;

    EnterCriticalSection(&This->lock);
    /* FIXME: see if object was registered before and return MK_S_MONIKERALREADYREGISTERED */
    list_add_tail(&This->rot, &rot_entry->entry);
    LeaveCriticalSection(&This->lock);

    return hr;
}

⌨️ 快捷键说明

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