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

📄 iolecont.cpp

📁 英文版的 想要的话可以下载了 为大家服务
💻 CPP
字号:
/*
 * IOLECONT.CPP
 * Link Source Server Chapter 9
 *
 * Implementation of the IOleItemContainer interface for
 * LinkSource's CFileObject and CContainerItem, using constructor
 * arguments to distinguish the relevant object.
 *
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
 *
 * Kraig Brockschmidt, Microsoft
 * Internet  :  kraigb@microsoft.com
 * Compuserve:  >INTERNET:kraigb@microsoft.com
 */


#include "linksrc.h"


#ifdef WIN32ANSI
/*
 * This is to turn off the mapping to ANSI wrapper APIs because
 * we're actually using wide char strings under Win32 all the time
 * in parts of this code.
 */
#undef CreateItemMoniker
#define CreateItemMoniker CreateItemMoniker

#endif

extern ULONG g_cObj;


/*
 * CImpIOleItemContainer::CImpIOleItemContainer
 * CImpIOleItemContainer::~CImpIOleItemContainer
 *
 * Parameters (Constructor):
 *  pObj            LPVOID of the page or pages.
 *  pUnkOuter       LPUNKNOWN to which we delegate.
 *  fFileObj        BOOL indicating if we're in CFileObject.
 */

CImpIOleItemContainer::CImpIOleItemContainer(LPVOID pObj
    , LPUNKNOWN pUnkOuter, BOOL fFileObj)
    {
    m_cRef=0;
    m_fFileObj=fFileObj;

    if (fFileObj)
        {
        m_pObjFile=(PCFileObject)pObj;
        m_pObjCont=NULL;
        }
    else
        {
        m_pObjFile=NULL;
        m_pObjCont=(PCContainerItem)pObj;
        }

    m_pUnkOuter=pUnkOuter;
    return;
    }

CImpIOleItemContainer::~CImpIOleItemContainer(void)
    {
    return;
    }




/*
 * CImpIOleItemContainer::QueryInterface
 * CImpIOleItemContainer::AddRef
 * CImpIOleItemContainer::Release
 */

STDMETHODIMP CImpIOleItemContainer::QueryInterface(REFIID riid
    , PPVOID ppv)
    {
    return m_pUnkOuter->QueryInterface(riid, ppv);
    }

STDMETHODIMP_(ULONG) CImpIOleItemContainer::AddRef(void)
    {
    ++m_cRef;
    return m_pUnkOuter->AddRef();
    }

STDMETHODIMP_(ULONG) CImpIOleItemContainer::Release(void)
    {
    --m_cRef;
    return m_pUnkOuter->Release();
    }



/*
 * CImpIOleItemContainer::ParseDisplayName
 *
 * Purpose:
 *  Parse the given name into a moniker as far as we know how
 *  to parse.
 *
 * Parameters:
 *  pbc             LPBC to the binding context
 *  pszName         LPOLESTR to the name to parse.
 *  pchEaten        ULONG * into which to store how many
 *                  characters we scanned in the display name.
 *  ppmk            LPMONIKER * in which to return the moniker.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIOleItemContainer::ParseDisplayName(LPBC pbc
    , LPOLESTR pszName, ULONG *pchEaten, LPMONIKER *ppmk)
    {
    OLECHAR     ch;
    ULONG       chEaten=0;
    TCHAR       szName[256];
    TCHAR       szComp[15];
    LPTSTR      psz;
    UINT        cch;

    *ppmk=NULL;
    *pchEaten=0;

    /*
     * All we have to look for is the string between the !
     * delimeters (or a null terminator).  pszName should be pointing
     * to a !, so skip it and scan the string for a ! or 0,
     * then pass the result to CreateItemMoniker.
     */

    psz=szName;

    ch=*pszName++;
    chEaten++;

    if ((OLECHAR)'!'!=ch)
        return ResultFromScode(MK_E_SYNTAX);

    ch=*pszName++;

    while ((OLECHAR)0!=ch && (OLECHAR)'!' !=ch)
        {
        *psz++=(TCHAR)ch;
        chEaten++;
        ch=*pszName++;
        }

    *psz=(TCHAR)0;

    /*
     * Syntax check.  If we're the File object, check for "Object n"
     * at the beginning of the string.  Otherwise check for
     * "Sub-Object n".
     */
    lstrcpy(szComp, m_fFileObj ? TEXT("Object ")
        : TEXT("Sub-Object "));

    //Does szName start with szComp?
    cch=lstrlen(szComp);

    if (0!=_tcsncicmp(szName, szComp, cch))
        {
        *pchEaten=1;    //Parsed ! at least
        return ResultFromScode(MK_E_SYNTAX);
        }

    //Check for a number in szName
    if ((TCHAR)'0' != szName[cch])
        {
        if (0==_ttoi(szName+cch))
            {
            *pchEaten=cch;  //Got past name
            return ResultFromScode(MK_E_SYNTAX);
            }
        }

    *pchEaten=chEaten;
   #ifdef WIN32ANSI
    //Use the ANSI version here since szName is ANSI
    return INOLE_CreateItemMoniker(TEXT("!"), szName, ppmk);
   #else
    return CreateItemMoniker(OLETEXT("!"), szName, ppmk);
   #endif
    }




/*
 * CImpIOleItemContainer::EnumObjects
 *
 * Purpose:
 *  Creates and returns an IEnumUnknown object that allows the
 *  caller to walk through the objects in this continer thing.
 *
 * Parameters:
 *  dwFlags         DWORD specifying what kind of objects to
 *                  enumerate.
 *  ppEnum          LPENUMUNKNOWN * into which to return the
 *                  enumerator
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIOleItemContainer::EnumObjects(DWORD dwFlags
    , LPENUMUNKNOWN *ppEnum)
    {
    *ppEnum=NULL;

    /*
     * We can leave this unimplemented in this sample since
     * we know no one will ever call it.  A real container
     * should be able to enumerate its contents.
     */
    return ResultFromScode(E_NOTIMPL);
    }




/*
 * CImpIOleItemContainer::LockContainer
 *
 * Purpose:
 *  Establishes a lock on the container to prevent it from shutting
 *  down outside of user control.  This is used to control the
 *  lifetime of the container when it's used to update a link to an
 *  embedded object within it.  If we're unlock and the user has not
 *  taken control, we close.
 *
 * Parameters:
 *  fLock           BOOL indicating a lock or unlock.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIOleItemContainer::LockContainer(BOOL fLock)
    {
    /*
     * For the purposes of this server, we need only AddRef
     * and release ourselves depending on fLock.
     */

    if (fLock)
        AddRef();
    else
        Release();

    return NOERROR;
    }






/*
 * CImpIOleItemContainer::GetObject
 *
 * Purpose:
 *  Returns the requested interface pointer on an object in this
 *  container.
 *
 * Parameters:
 *  pszItem         LPOLESTR to the item we must locate.
 *  dwSpeed         DWORD identifying how long the caller is willing
 *                  to wait.
 *  pcb             LPBINDCTX providing the binding context.
 *  riid            REFIID of the interface requested.
 *  ppv             PPVOID into which to return the object.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIOleItemContainer::GetObject(LPOLESTR pszItem
    , DWORD dwSpeed, LPBINDCTX pbc, REFIID riid, PPVOID ppv)
    {
    HRESULT         hr;
    IStorage       *pIStorage;
    PCContainerItem pCI;
    PCSimpleItem    pSI;
    BOOL            fSuccess;
    IUnknown       *pUnk;

    *ppv=NULL;

    /*
     * The item name given to either CFileObj or CContainerItem
     * instantiations of this interface will be the name of
     * a storage below the current object's storage.  So we
     * use m_fFileObj to know which storage to look under
     * (names are either "Object n" or "Sub-Object n").
     *
     * If that storage exists, the object exists.  If it is
     * already running, we can check in the Running Object Table
     * and just return that object.  This is the only case that
     * works when the bind speed in the bind context is
     * immediate.
     *
     * Otherwise we open the storage and hand it to a new
     * instance of the right type of object (CContainerItem or
     * CSimpleItem), and register the new objects as running.
     */

    //Get the object if running
    hr=GetRunning(pszItem, pbc, riid, ppv, FALSE);

    if (BINDSPEED_IMMEDIATE==dwSpeed && NOERROR!=hr)
        return ResultFromScode(MK_E_EXCEEDEDDEADLINE);

    //If object was running, we're done!
    if (NOERROR==hr)
        return NOERROR;

    //Otherwise we need to get the storage.
    hr=GetObjectStorage(pszItem, pbc, IID_IStorage
        , (void **)&pIStorage);

    if (FAILED(hr))
        return hr;

    /*
     * Storage exists, so create an object and give that storage
     * to it.  The new object will also register itself in the
     * Running Object Table.
     */
    fSuccess=FALSE;

    if (m_fFileObj)
        {
        pCI=new CContainerItem(m_pObjFile, m_pObjFile->m_pfnDestroy);

        pUnk=pCI;

        if (NULL!=pCI)
            {
            pUnk->AddRef();
            fSuccess=pCI->Init(m_pObjFile->m_pmk, pbc, pszItem
                , pIStorage);
            }
        }
    else
        {
        pSI=new CSimpleItem(m_pObjCont, m_pObjCont->m_pfnDestroy);

        pUnk=pSI;

        if (NULL!=pSI)
            {
            pUnk->AddRef();
            fSuccess=pSI->Init(m_pObjCont->m_pmk, pbc, pszItem
                , pIStorage);
            }
        }

    if (!fSuccess)
        {
        if (NULL!=pUnk)
            pUnk->Release();

        return ResultFromScode(E_OUTOFMEMORY);
        }

    g_cObj++;

    //If QueryInterface fails, this Release destroys the object
    hr=pUnk->QueryInterface(riid, ppv);
    pUnk->Release();

    if (FAILED(hr))
        return hr;

    return NOERROR;
    }






/*
 * CImpIOleItemContainer::GetObjectStorage
 *
 * Purpose:
 *  Similar to GetObject in that we have to locate the object
 *  described by a given name, but instead of returning any old
 *  interface we return a storage element.
 *
 * Parameters:
 *  pszItem         LPOLESTR to the item we must locate.
 *  pcb             LPBINDCTX providing the binding context.
 *  riid            REFIID of the interface requested.  Usually
 *                  IStorage or IStream.
 *  ppv             PPVOID into which to return the object.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIOleItemContainer::GetObjectStorage(LPOLESTR pszItem
    , LPBINDCTX pbc, REFIID riid, PPVOID ppv)
    {
    IStorage       *pIStorageObj;
    IStorage       *pIStorageNew;
    HRESULT         hr;

    if (IID_IStorage!=riid)
        return ResultFromScode(MK_E_NOSTORAGE);

    pIStorageObj=m_fFileObj ? m_pObjFile->m_pIStorage
        : m_pObjCont->m_pIStorage;

    //Check storage existence
    hr=pIStorageObj->OpenStorage(pszItem
        , NULL, STGM_TRANSACTED | STGM_READ | STGM_SHARE_EXCLUSIVE
        , NULL, 0, &pIStorageNew);

    if (FAILED(hr))
        {
        IUnknown   *pUnk;

        /*
         * Because you must open a substorage with exclusive access,
         * we'll run into a problem where an object created for use
         * with parsing will still be running when another object of
         * the same type is used for binding.  The reason is that the
         * bind context holds these thing for optimization purposes.
         * But that does mean that OpenStorage above might fail
         * with STG_E_ACCESSDENIED.  In this case, we'll try to get
         * a previously opened storage from the bind context
         * (see below).
         */
        if (STG_E_ACCESSDENIED!=GetScode(hr))
            return hr;

        if (FAILED(pbc->GetObjectParam(SZOPENSTORAGE, &pUnk)))
            return ResultFromScode(STG_E_ACCESSDENIED);

        //This does the necessary AddRef on the IStorage pointer
        hr=pUnk->QueryInterface(IID_IStorage
            , (void **)&pIStorageNew);
        pUnk->Release();

        //This sets the out-parameter to NULL on failure
        *ppv=pIStorageNew;
        return hr;
        }

    *ppv=pIStorageNew;
    pbc->RegisterObjectParam(SZOPENSTORAGE, pIStorageNew);
    return NOERROR;
    }






/*
 * CImpIOleItemContainer::IsRunning
 *
 * Purpose:
 *  Answers if the object under the given name is currently running.
 *
 * Parameters:
 *  pszItem         LPOLESTR of the item to check
 *
 * Return Value:
 *  HRESULT         NOERROR if the object is running, S_FALSE
 *                  otherwise.  Possibly MK_E_NOOBJECT if the name
 *                  is bogus.
 */

STDMETHODIMP CImpIOleItemContainer::IsRunning(LPOLESTR pszItem)
    {
    return GetRunning(pszItem, NULL, IID_NULL, NULL, TRUE);
    }





/*
 * (Internal)
 * CImpIOleItemContainer::GetRunning
 *
 * Purpose:
 *  Grabs a running object from the running object table or
 *  just checks existence.
 *
 * Parameters:
 *  pszItem         LPOLESTR of the item to check
 *  pbc             IBindCtx * to use, can be NULL.
 *  riid            REFIID to return if fCheck is FALSE.
 *  ppv             void ** in which to return a pointer.
 *  fCheck          BOOL indicating to check (TRUE) or
 *                  retrieve (FALSE).
 *
 * Return Value:
 *  HRESULT         NOERROR if the object is running, S_FALSE
 *                  or an error otherwise.
 */

HRESULT CImpIOleItemContainer::GetRunning(LPOLESTR pszItem
    , IBindCtx *pbc, REFIID riid, void **ppv, BOOL fCheck)
    {
    OLECHAR              szDelim[]=OLETEXT("!");
    HRESULT              hr=ResultFromScode(S_FALSE);
    IMoniker            *pmkBase;
    IMoniker            *pmkItem;
    IMoniker            *pmkComp;
    IRunningObjectTable *pROT;

    pmkBase=m_fFileObj ? m_pObjFile->m_pmk : m_pObjCont->m_pmk;

    if (FAILED(CreateItemMoniker(szDelim, pszItem, &pmkItem)))
        return hr;

    //Create a composite with this item
    hr=pmkBase->ComposeWith(pmkItem, FALSE, &pmkComp);

    if (FAILED(hr))
        {
        pmkItem->Release();
        return hr;
        }


    if (NULL!=pbc)
        hr=pbc->GetRunningObjectTable(&pROT);
    else
        hr=GetRunningObjectTable(0, &pROT);

    if (SUCCEEDED(hr))
        {
        hr=pROT->IsRunning(pmkComp);

        //If running, grab the object if necessary
        if (!fCheck && NOERROR==hr)
            {
            IUnknown *pUnk;

            if(SUCCEEDED(pROT->GetObject(pmkComp, &pUnk)))
                {
                hr=pUnk->QueryInterface(riid, ppv);
                pUnk->Release();
                }
            }

        pROT->Release();
        }

    pmkComp->Release();
    pmkItem->Release();
    return hr;
    }

⌨️ 快捷键说明

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