IUILINK.CPP
/* 
 * IUILINK.CPP 
 * Patron Chapter 20 
 * 
 * Implementation of an object with the IOleUILinkContainer 
 * interface necessary to use the standard Links Dialog.  This 
 * is implemented as a stand-along object with access to the CPage 
 * with which its associated, primiarily because it is only used 
 * for the one dialog.  Therefore this object has it's own IUnknown. 
 * In addition, we use the Links Assistant object developed in this 
 * chapter to simplify our own code. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "patron.h" 
 
 
/* 
 * CIOleUILinkContainer::CIOleUILinkContainer 
 * CIOleUILinkContainer::~CIOleUILinkContainer 
 * 
 * Parameters (Constructor): 
 *  pPage           PCPage of the page we're in. 
 */ 
 
CIOleUILinkContainer::CIOleUILinkContainer(PCPage pPage) 
    { 
    m_cRef=0; 
    m_pPage=pPage; 
    m_iTenant=0; 
    m_pDelIUILinks=NULL; 
    m_fDirty=FALSE; 
    return; 
    } 
 
CIOleUILinkContainer::~CIOleUILinkContainer(void) 
    { 
    ReleaseInterface(m_pDelIUILinks); 
    return; 
    } 
 
 
 
/* 
 * CIOleUILinkContainer::Init 
 * 
 * Purpose: 
 *  Performs initialization on the object that might fail.  In 
 *  particular this creates an object of CLSID_LinksAssistant that 
 *  helps in implementing this interface. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if successful, FALSE otherwise. 
 */ 
 
BOOL CIOleUILinkContainer::Init(void) 
    { 
    HRESULT     hr; 
 
    hr=CoCreateInstance(CLSID_LinksAssistant, NULL 
        , CLSCTX_INPROC_SERVER, IID_IOleUILinkContainer 
        , (PPVOID)&m_pDelIUILinks); 
 
    return SUCCEEDED(hr); 
    } 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::QueryInterface 
 * CIOleUILinkContainer::AddRef 
 * CIOleUILinkContainer::Release 
 * 
 * Purpose: 
 *  IUnknown members for CIOleUILinkContainer object. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::QueryInterface(REFIID riid 
    , PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid || IID_IOleUILinkContainer==riid) 
        { 
        *ppv=this; 
        AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CIOleUILinkContainer::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
STDMETHODIMP_(ULONG) CIOleUILinkContainer::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    delete this; 
    return 0; 
    } 
 
 
 
/* 
 * CIOleUILinkContainer::GetNextLink 
 * 
 * Purpose: 
 *  Called when the Links dialog is filling its listbox.  Here we 
 *  need to return a key for the first link if dwLink is zero, then 
 *  return the next links if it's non-zero. 
 * 
 * Parameters: 
 *  dwLink          DWORD last returned from this function.  Zero if 
 *                  this is the first call to this function. 
 * 
 * Return Value: 
 *  DWORD           Some value that identifies this object.  Zero 
 *                  stops the sequence such that this function is 
 *                  no longer called. 
 */ 
 
STDMETHODIMP_(DWORD) CIOleUILinkContainer::GetNextLink(DWORD dwLink) 
    { 
    PCTenant        pTenant; 
 
    //If we're told to start the sequence, set index to zero. 
    if (0L==dwLink) 
        m_iTenant=0; 
 
    /* 
     * On each subsequent call, find the next linked object in 
     * this document and return it.  Make sure the index is 
     * incremented for the next time this function is called. 
     */ 
    for ( ; m_iTenant < m_pPage->m_cTenants; m_iTenant++) 
        { 
        if (m_pPage->TenantGet(m_iTenant, &pTenant, FALSE)) 
            { 
            if (TENANTTYPE_LINKEDOBJECT==pTenant->TypeGet()) 
                { 
                m_iTenant++; 
                return (DWORD)pTenant; 
                } 
            } 
        } 
 
    //If we hit the end of list, this tells the dialog to stop. 
    return 0L; 
    } 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::SetLinkUpdateOptions 
 * 
 * Purpose: 
 *  Informs the application to call IOleLink::SetUpdateOptions for 
 *  the object identified by dwLink. 
 * 
 * Parameters: 
 *  dwLink          DWORD object identifier as returned from 
 *                  GetNextLink. 
 *  dwOptions       DWORD containing the new options. 
 * 
 * Return Value: 
 *  HRESULT         Return value of IOleLink::SetUpdateOptions. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::SetLinkUpdateOptions(DWORD dwLink 
    , DWORD dwOptions) 
    { 
    LPOLELINK       pIOleLink; 
    HRESULT         hr; 
 
    if (NULL==dwLink) 
        return ResultFromScode(E_FAIL); 
 
    /* 
     * Your responsibility is to call the object's 
     * IOleLink::SetUpdateOptions function with dwOptions.  Simple? 
     * 
     * For Patron we must first get the object pointer obtainable 
     * from the tenant's ObjectGet function, then QI for IOleLink. 
     */ 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=pIOleLink->SetUpdateOptions(dwOptions); 
    pIOleLink->Release(); 
 
    m_fDirty=SUCCEEDED(hr); 
    return hr; 
    } 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::GetLinkUpdateOptions 
 * 
 * Purpose: 
 *  Requests the container to call IOleLink::GetUpdateOptions for 
 *  the object identified by dwLink. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the object 
 *  pdwOptions      LPDWORD in which to store the options. 
 * 
 * Return Value: 
 *  HRESULT         Return value of IOleLink::GetUpdateOptions 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::GetLinkUpdateOptions(DWORD dwLink 
    , LPDWORD pdwOptions) 
    { 
    LPOLELINK       pIOleLink; 
    HRESULT         hr; 
 
    if (NULL==dwLink) 
        return ResultFromScode(E_FAIL); 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=pIOleLink->GetUpdateOptions(pdwOptions); 
    pIOleLink->Release(); 
 
    return hr; 
    } 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::SetLinkSource 
 * 
 * Purpose: 
 *  Changes the moniker to which an object is linked. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the object in question. 
 *  pszName         LPTSTR to the displayable name of the source. 
 *  cchName         ULONG length of the file portaion of pszName 
 *  pchEaten        ULONG * in which to return the number of 
 *                  characters used in parsing pszDisplayName. 
 *  fValidate       BOOL indicating if we're to validate that the 
 *                  source exists first. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if successful, E_FAIL otherwise. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::SetLinkSource(DWORD dwLink 
    , LPTSTR pszName, ULONG cchName, ULONG *pchEaten 
    , BOOL fValidate) 
    { 
    PCTenant        pTenant=(PCTenant)dwLink; 
    HRESULT         hr; 
    LPOLELINK       pIOleLink; 
 
    if (NULL==dwLink) 
        return ResultFromScode(E_FAIL); 
 
    //This is for use in GetLinkSource, below. 
    pTenant->m_fLinkAvail=FALSE; 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=m_pDelIUILinks->SetLinkSource((DWORD)pIOleLink, pszName 
        , cchName, pchEaten, fValidate); 
    pIOleLink->Release(); 
 
    if (FAILED(hr)) 
        return hr; 
 
    //hr will be S_FALSE if link is unavailable. 
    pTenant->Repaint(); 
    pTenant->m_fLinkAvail=(NOERROR==hr); 
    m_fDirty=TRUE; 
    return NOERROR; 
    } 
 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::GetLinkSource 
 * 
 * Purpose: 
 *  Retrieves various strings and values for this link source. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the object affected. 
 *  ppszName        LPTSTR * in which to return the new source 
 *                  name 
 *  pcchName        ULONG * in which to return the length of 
 *                  pszName 
 *  ppszFullLink    LPTSTR * in which to return the full name of 
 *                  the class of linked object. 
 *  ppszShortLink   LPTSTR * in which to return the short name of 
 *                  the class of linked object. 
 *  pfSourceAvail   BOOL * in which to return if this is an 
 *                  available link source. 
 *  pfSelected      BOOL * in which to return if this object is 
 *                  currently selected in the document.  This 
 *                  selects the item in the listbox for this object. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR on success, error code otherwise. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::GetLinkSource(DWORD dwLink 
    , LPTSTR *ppszName, ULONG *pcchName, LPTSTR *ppszFullLink 
    , LPTSTR *ppszShortLink, BOOL *pfSourceAvail, BOOL *pfSelected) 
    { 
    HRESULT         hr; 
    PCTenant        pTenant=(PCTenant)dwLink; 
    LPOLELINK       pIOleLink=NULL; 
    LPOLEOBJECT     pIOleObject=NULL; 
    LPMONIKER       pmk=NULL; 
    LPMONIKER       pmkFirst=NULL; 
    LPBC            pbc=NULL; 
 
    if (NULL==dwLink) 
        return ResultFromScode(E_FAIL); 
 
    //We know what this is from SetLinkSource 
    *pfSourceAvail=pTenant->m_fLinkAvail; 
 
    if (pfSelected) 
        *pfSelected=pTenant->FIsSelected(); 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=m_pDelIUILinks->GetLinkSource((DWORD)pIOleLink, ppszName 
        , pcchName, ppszFullLink, ppszShortLink, pfSourceAvail 
        , pfSelected); 
 
    pIOleLink->Release(); 
    return hr; 
    } 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::OpenLinkSource 
 * 
 * Purpose: 
 *  Asks the container to call DoVerb on this object with 
 *  OLEIVERB_SHOW. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the linked object. 
 * 
 * Return Value: 
 *  HRESULT         Standard. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::OpenLinkSource(DWORD dwLink) 
    { 
    PCTenant        pTenant=(PCTenant)dwLink; 
 
    pTenant->Activate(OLEIVERB_OPEN); 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CIOleUILinkContainer::UpdateLink 
 * 
 * Purpose: 
 *  Asks the container to update the link for this object. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the linked object. 
 *  fErrorMessage   BOOL indicating if we can show errors. 
 *  fErrorAction    BOOL making no sense whatsoever. 
 * 
 * Return Value: 
 *  HRESULT         Standard. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::UpdateLink(DWORD dwLink 
    , BOOL fErrorMessage, BOOL fErrorAction) 
    { 
    PCTenant        pTenant=(PCTenant)dwLink; 
    LPOLELINK       pIOleLink; 
    HRESULT         hr; 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=m_pDelIUILinks->UpdateLink((DWORD)pIOleLink, fErrorMessage 
        , fErrorAction); 
 
    pTenant->Repaint(); 
    pTenant->m_fLinkAvail=SUCCEEDED(hr); 
    pIOleLink->Release(); 
 
    if (FAILED(hr)) 
        { 
        if (fErrorMessage) 
            { 
            MessageBox(m_pPage->m_hWnd 
                , TEXT("Could not update link."), TEXT("Patron") 
                , MB_OK); 
            } 
        } 
    else 
        m_fDirty=TRUE; 
 
    return hr; 
    } 
 
 
 
 
 
 
/* 
 * CIOleUILinkContainer::CancelLink 
 * 
 * Purpose: 
 *  Requests that the container turn this linked object into a 
 *  static object. 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the linked object. 
 * 
 * Return Value: 
 *  HRESULT         Standard. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::CancelLink(DWORD dwLink) 
    { 
    PCTenant        pTenant=(PCTenant)dwLink; 
    LPOLELINK       pIOleLink; 
    HRESULT         hr; 
 
    hr=GetObjectInterface(dwLink, IID_IOleLink, (PPVOID)&pIOleLink); 
 
    if (FAILED(hr)) 
        return hr; 
 
    //This sets the source moniker to NULL. 
    m_pDelIUILinks->CancelLink((DWORD)pIOleLink); 
    pIOleLink->Release(); 
 
    //Go change this object over to a static one. 
    pTenant->ConvertToStatic(); 
 
    m_fDirty=TRUE; 
    return NOERROR; 
    } 
 
 
 
 
 
 
//PROTECTED FUNCTIONS INTERNAL TO CIOleUILinkContainer 
 
 
/* 
 * CIOleUILinkContainer::GetObjectInterface 
 * (Protected) 
 * 
 * Purpose: 
 *  Retrieves and interface pointer for the object identified by 
 *  dwLink 
 * 
 * Parameters: 
 *  dwLink          DWORD identifying the object 
 *  riid            REFIID of the interface desired. 
 *  ppv             PPVOID into which we return the pointer. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR on success, error code otherwise. 
 */ 
 
STDMETHODIMP CIOleUILinkContainer::GetObjectInterface(DWORD dwLink 
    , REFIID riid, PPVOID ppv) 
    { 
    PCTenant        pTenant=(PCTenant)dwLink; 
    LPUNKNOWN       pIUnknown; 
    HRESULT         hr; 
 
    pTenant->ObjectGet(&pIUnknown); 
    hr=pIUnknown->QueryInterface(riid, ppv); 
    pIUnknown->Release(); 
 
    return hr; 
    }