home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap20 / lnkassis / lnkassis.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  14.9 KB  |  662 lines

  1. /*
  2.  * LNKASSIS.CPP
  3.  * Links Assistant Chapter 20
  4.  *
  5.  * Implementation of the CLinks object with the IOleUILinkContainer
  6.  * interface to assist handling the Links dialog for linking
  7.  * containers.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include "lnkassis.h"
  18.  
  19.  
  20. /*
  21.  * CLinks::CLinks
  22.  * CLinks::~CLinks
  23.  *
  24.  * Parameters (Constructor):
  25.  *  pfnDestroy      PFNDESTROYED to call when object is destroyed.
  26.  */
  27.  
  28. CLinks::CLinks(PFNDESTROYED pfnDestroy)
  29.     {
  30.     m_cRef=0;
  31.     m_pfnDestroy=pfnDestroy;
  32.     return;
  33.     }
  34.  
  35.  
  36. CLinks::~CLinks(void)
  37.     {
  38.     return;
  39.     }
  40.  
  41.  
  42.  
  43.  
  44. /*
  45.  * CLinks::QueryInterface
  46.  * CLinks::AddRef
  47.  * CLinks::Release
  48.  *
  49.  * Purpose:
  50.  *  IUnknown members for CLinks object.
  51.  */
  52.  
  53. STDMETHODIMP CLinks::QueryInterface(REFIID riid, PPVOID ppv)
  54.     {
  55.     *ppv=NULL;
  56.  
  57.     if (IID_IUnknown==riid || IID_IOleUILinkContainer==riid)
  58.         {
  59.         *ppv=this;
  60.         AddRef();
  61.         return NOERROR;
  62.         }
  63.  
  64.     return ResultFromScode(E_NOINTERFACE);
  65.     }
  66.  
  67.  
  68. STDMETHODIMP_(ULONG) CLinks::AddRef(void)
  69.     {
  70.     return ++m_cRef;
  71.     }
  72.  
  73.  
  74. STDMETHODIMP_(ULONG) CLinks::Release(void)
  75.     {
  76.     if (0L!=--m_cRef)
  77.         return m_cRef;
  78.  
  79.     if (NULL!=m_pfnDestroy)
  80.         (*m_pfnDestroy)();
  81.  
  82.     delete this;
  83.     return 0;
  84.     }
  85.  
  86.  
  87.  
  88.  
  89.  
  90. /*
  91.  * CLinks::GetNextLink
  92.  *
  93.  * Purpose:
  94.  *  Function to fill out the IOleUILinkContainer interface.
  95.  *  Does nothing.
  96.  *
  97.  * Parameters:
  98.  *  dwLink          DWORD ignored.
  99.  *
  100.  * Return Value:
  101.  *  DWORD           Alwaus 0L
  102.  *
  103.  */
  104.  
  105. STDMETHODIMP_(DWORD) CLinks::GetNextLink(DWORD dwLink)
  106.     {
  107.     return 0L;
  108.     }
  109.  
  110.  
  111.  
  112.  
  113.  
  114. /*
  115.  * CLinks::SetLinkUpdateOptions
  116.  *
  117.  * Purpose:
  118.  *  Calls IOleLink::SetUpdateOptions for the object identified by
  119.  *  dwLink.
  120.  *
  121.  * Parameters:
  122.  *  dwLink          DWORD, an IOleLink pointer to the object
  123.  *                  affected.
  124.  *  dwOptions       DWORD containing the new options.
  125.  *
  126.  * Return Value:
  127.  *  HRESULT         Return value of IOleLink::SetUpdateOptions.
  128.  */
  129.  
  130. STDMETHODIMP CLinks::SetLinkUpdateOptions(DWORD dwLink
  131.     , DWORD dwOptions)
  132.     {
  133.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  134.  
  135.     if (NULL==pIOleLink)
  136.         return ResultFromScode(E_FAIL);
  137.  
  138.     return pIOleLink->SetUpdateOptions(dwOptions);
  139.     }
  140.  
  141.  
  142.  
  143.  
  144.  
  145. /*
  146.  * CLinks::GetLinkUpdateOptions
  147.  *
  148.  * Purpose:
  149.  *  Call IOleLink::GetUpdateOptions for the object identified by
  150.  *  dwLink.
  151.  *
  152.  * Parameters:
  153.  *  dwLink          DWORD, an IOleLink pointer to the object
  154.  *                  affected.
  155.  *  pdwOptions      LPDWORD in which to store the options.
  156.  *
  157.  * Return Value:
  158.  *  HRESULT         Return value of IOleLink::GetUpdateOptions
  159.  */
  160.  
  161. STDMETHODIMP CLinks::GetLinkUpdateOptions(DWORD dwLink
  162.     , LPDWORD pdwOptions)
  163.     {
  164.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  165.  
  166.     if (NULL==pIOleLink)
  167.         return ResultFromScode(E_FAIL);
  168.  
  169.     return pIOleLink->GetUpdateOptions(pdwOptions);
  170.     }
  171.  
  172.  
  173.  
  174.  
  175.  
  176. /*
  177.  * CLinks::SetLinkSource
  178.  *
  179.  * Purpose:
  180.  *  Changes the moniker to which an object is linked.
  181.  *
  182.  * Parameters:
  183.  *  dwLink          DWORD, an IOleLink pointer to the object
  184.  *                  affected.
  185.  *  pszName         LPTSTR to the displayable name of the source.
  186.  *  cchName         ULONG length of the file portaion of pszName
  187.  *  pchEaten        ULONG * in which to return the number of
  188.  *                  characters used in parsing pszDisplayName.
  189.  *  fValidate       BOOL indicating if we're to validate that the
  190.  *                  source exists first.
  191.  *
  192.  * Return Value:
  193.  *  HRESULT         If successful, NOERROR indicates that the link
  194.  *                  is available, S_FALSE to indicate it's not.
  195.  *                  This information is later required in
  196.  *                  GetLinkSource.  E_FAIL on failure.
  197.  */
  198.  
  199. STDMETHODIMP CLinks::SetLinkSource(DWORD dwLink, LPTSTR pszName
  200.     , ULONG cchName, ULONG *pchEaten, BOOL fValidate)
  201.     {
  202.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  203.     HRESULT         hr;
  204.     CLSID           clsID=CLSID_NULL;
  205.     LPMONIKER       pmk=NULL;
  206.     BOOL            fAvail=FALSE;
  207.  
  208.     if (fValidate)
  209.         {
  210.         //Check things out and get a moniker and CLSID.
  211.         if (!ValidateLinkSource(pszName, pchEaten, &pmk, &clsID))
  212.             return ResultFromScode(E_FAIL);
  213.  
  214.         //If we got a CLSID, then we found the source.
  215.         if (CLSID_NULL!=clsID)
  216.             fAvail=TRUE;
  217.         }
  218.     else
  219.         {
  220.         if (!CreateNewSourceMoniker(pszName, cchName, &pmk))
  221.             return ResultFromScode(E_FAIL);
  222.         }
  223.  
  224.     if (NULL==pIOleLink)
  225.         {
  226.         pmk->Release();
  227.         return ResultFromScode(E_FAIL);
  228.         }
  229.  
  230.     if (NULL!=pmk)
  231.         {
  232.         hr=pIOleLink->SetSourceMoniker(pmk, clsID);
  233.         pmk->Release();
  234.         }
  235.     else
  236.        #ifdef WIN32ANSI
  237.         {
  238.         OLECHAR     szTemp[512];
  239.  
  240.         MultiByteToWideChar(CP_ACP, 0, pszName, -1, szTemp, 512);
  241.         hr=pIOleLink->SetSourceDisplayName(szTemp);
  242.         }
  243.        #else
  244.         hr=pIOleLink->SetSourceDisplayName(pszName);
  245.        #endif
  246.  
  247.     if (FAILED(hr))
  248.         return hr;
  249.  
  250.     return fAvail ? NOERROR : ResultFromScode(S_FALSE);
  251.     }
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258. /*
  259.  * CLinks::GetLinkSource
  260.  *
  261.  * Purpose:
  262.  *  Retrieves various strings and values for this link source.
  263.  *
  264.  * Parameters:
  265.  *  dwLink          DWORD, an IOleLink pointer to the object
  266.  *                  affected.
  267.  *  ppszName        LPTSTR * in which to return the new source
  268.  *                  name
  269.  *  pcchName        ULONG * in which to return the length of
  270.  *                  pszName
  271.  *  ppszFullLink    LPTSTR * in which to return the full name of
  272.  *                  the class of linked object.
  273.  *  ppszShortLink   LPTSTR * in which to return the short name of
  274.  *                  the class of linked object.
  275.  *  pfSourceAvail   BOOL * ignored.
  276.  *  pfSelected      BOOL * ignored.
  277.  *
  278.  * Return Value:
  279.  *  HRESULT         NOERROR on success, error code otherwise.
  280.  */
  281.  
  282. STDMETHODIMP CLinks::GetLinkSource(DWORD dwLink
  283.     , LPTSTR *ppszName, ULONG *pcchName
  284.     , LPTSTR *ppszFullLink, LPTSTR *ppszShortLink
  285.     , BOOL *pfSourceAvail, BOOL *pfSelected)
  286.     {
  287.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  288.     HRESULT         hr;
  289.     LPOLEOBJECT     pIOleObject=NULL;
  290.     LPMONIKER       pmk=NULL;
  291.     LPMONIKER       pmkFirst=NULL;
  292.     LPBC            pbc=NULL;
  293.    #ifdef WIN32ANSI
  294.     OLECHAR        *pszOut;
  295.     TCHAR          *pszTemp;
  296.    #endif
  297.  
  298.     if (NULL==pIOleLink)
  299.         return ResultFromScode(E_FAIL);
  300.  
  301.     *ppszName=NULL;
  302.     *pcchName=0;
  303.     *ppszFullLink=NULL;
  304.     *ppszShortLink=NULL;
  305.  
  306.     hr=pIOleLink->GetSourceMoniker(&pmk);
  307.  
  308.     if (SUCCEEDED(hr))
  309.         {
  310.         hr=pIOleLink->QueryInterface(IID_IOleObject
  311.             , (PPVOID)&pIOleObject);
  312.  
  313.         if (SUCCEEDED(hr))
  314.             {
  315.            #ifdef WIN32ANSI
  316.             pszTemp=(TCHAR *)CoTaskMemAlloc(80);
  317.             pIOleObject->GetUserType(USERCLASSTYPE_FULL
  318.                 , &pszOut);
  319.             WideCharToMultiByte(CP_ACP, 0, pszOut, -1
  320.                 , pszTemp, 80, NULL, NULL);
  321.             CoTaskMemFree((void *)pszOut);
  322.             *ppszFullLink=pszTemp;
  323.  
  324.             pszTemp=(TCHAR *)CoTaskMemAlloc(80);
  325.             pIOleObject->GetUserType(USERCLASSTYPE_SHORT
  326.                 , &pszOut);
  327.             WideCharToMultiByte(CP_ACP, 0, pszOut, -1
  328.                 , pszTemp, 80, NULL, NULL);
  329.             CoTaskMemFree((void *)pszOut);
  330.             *ppszShortLink=pszTemp;
  331.            #else
  332.             pIOleObject->GetUserType(USERCLASSTYPE_FULL
  333.                 , ppszFullLink);
  334.             pIOleObject->GetUserType(USERCLASSTYPE_SHORT
  335.                 , ppszShortLink);
  336.            #endif
  337.             pIOleObject->Release();
  338.             }
  339.  
  340.         *pcchName=CchFilePrefix(pmk);
  341.         pmk->Release();
  342.         }
  343.  
  344.    #ifdef WIN32ANSI
  345.     pszTemp=(TCHAR *)CoTaskMemAlloc(80);
  346.     hr=pIOleLink->GetSourceDisplayName(&pszOut);
  347.     WideCharToMultiByte(CP_ACP, 0, pszOut, -1
  348.         , pszTemp, 80, NULL, NULL);
  349.     CoTaskMemFree((void *)pszOut);
  350.     *ppszName=pszTemp;
  351.     return hr;
  352.    #else
  353.     return pIOleLink->GetSourceDisplayName(ppszName);
  354.    #endif
  355.     }
  356.  
  357.  
  358.  
  359.  
  360.  
  361. /*
  362.  * CLinks::OpenLinkSource
  363.  *
  364.  * Purpose:
  365.  *  Does nothing.  The container using this object is the only
  366.  *  one that knows how to activate an object properly.
  367.  *
  368.  * Parameters:
  369.  *  dwLink          DWORD ignored.
  370.  *
  371.  * Return Value:
  372.  *  HRESULT         NOERROR
  373.  */
  374.  
  375. STDMETHODIMP CLinks::OpenLinkSource(DWORD dwLink)
  376.     {
  377.     return NOERROR;
  378.     }
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385. /*
  386.  * CLinks::UpdateLink
  387.  *
  388.  * Purpose:
  389.  *  Updates the link for this object.
  390.  *
  391.  * Parameters:
  392.  *  dwLink          DWORD, an IOleLink pointer to the object
  393.  *                  affected.
  394.  *  fErrorMessage   BOOL indicating if we can show errors.
  395.  *  fErrorAction    BOOL making no sense whatsoever.
  396.  *
  397.  * Return Value:
  398.  *  HRESULT         NOERROR if successful, error code otherwise. If
  399.  *                  there is an error, the caller should set the
  400.  *                  link availability flag to FALSE.  Otherwise set
  401.  *                  to TRUE.
  402.  */
  403.  
  404. STDMETHODIMP CLinks::UpdateLink(DWORD dwLink
  405.     , BOOL fErrorMessage, BOOL fErrorAction)
  406.     {
  407.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  408.     HRESULT         hr;
  409.     LPOLEOBJECT     pIOleObject;
  410.  
  411.     if (NULL==pIOleLink)
  412.         return ResultFromScode(E_FAIL);
  413.  
  414.     hr=pIOleLink->QueryInterface(IID_IOleObject
  415.         , (PPVOID)&pIOleObject);
  416.  
  417.     if (FAILED(hr))
  418.         return hr;
  419.  
  420.     hr=pIOleObject->IsUpToDate();
  421.     
  422.     if (NOERROR!=hr)
  423.         {
  424.         hr=pIOleObject->Update();
  425.  
  426.         if (FAILED(hr))
  427.             return hr;
  428.         }
  429.  
  430.     return NOERROR;
  431.     }
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438. /*
  439.  * CLinks::CancelLink
  440.  *
  441.  * Purpose:
  442.  *  Sets the source moniker in the link to NULL but does nothing
  443.  *  else.  How the container decides to convert this to static
  444.  *  is its choice.
  445.  *
  446.  * Parameters:
  447.  *  dwLink          DWORD, an IOleLink pointer to the object
  448.  *                  affected.
  449.  *
  450.  * Return Value:
  451.  *  HRESULT         Standard.
  452.  */
  453.  
  454. STDMETHODIMP CLinks::CancelLink(DWORD dwLink)
  455.     {
  456.     LPOLELINK       pIOleLink=(LPOLELINK)dwLink;
  457.  
  458.     if (NULL!=pIOleLink)
  459.         return pIOleLink->SetSourceMoniker(NULL, CLSID_NULL);
  460.  
  461.     return NOERROR;
  462.     }
  463.  
  464.  
  465.  
  466.  
  467.  
  468. //PROTECTED FUNCTIONS INTERNAL TO CLinks
  469.  
  470. /*
  471.  * CLinks::ValidateLinkSource
  472.  * (Protected)
  473.  *
  474.  * Purpose:
  475.  *  Given a name of a link source retrieve a moniker for it and
  476.  *  a CLSID if we can bind.
  477.  *
  478.  * Parameters:
  479.  *  pszName         LPTSTR of the source
  480.  *  pchEaten        ULONG * into which to return how many
  481.  *                  characters we parse.
  482.  *  ppmk            LPMONIKER * into which to store the moniker
  483.  *  pclsID          LPCLSID into which to store the clsID.
  484.  *
  485.  * Return Value:
  486.  *  BOOL            TRUE if *ppmk has a valid moniker,
  487.  *                  FALSE otherwise.
  488.  */
  489.  
  490. BOOL CLinks::ValidateLinkSource(LPTSTR pszName
  491.     , ULONG *pchEaten, LPMONIKER *ppmk, LPCLSID pclsID)
  492.     {
  493.     HRESULT     hr;
  494.     LPBC        pbc=NULL;
  495.     LPOLEOBJECT pIOleObject;
  496.  
  497.     *ppmk=NULL;
  498.     *pclsID=CLSID_NULL;
  499.  
  500.     if (FAILED(CreateBindCtx(0, &pbc)))
  501.         return FALSE;
  502.  
  503.     hr=MkParseDisplayName(pbc, pszName, pchEaten, ppmk);
  504.  
  505.     if (SUCCEEDED(hr))
  506.         {
  507.         /*
  508.          * Now that we have a moniker for this new source, so try
  509.          * binding to that source and get its CLSID.
  510.          */
  511.         hr=(*ppmk)->BindToObject(pbc, NULL, IID_IOleObject
  512.             , (PPVOID)&pIOleObject);
  513.  
  514.         if (SUCCEEDED(hr))
  515.             {
  516.             pIOleObject->GetUserClassID(pclsID);
  517.             pIOleObject->Release();
  518.             }
  519.  
  520.         return TRUE;
  521.         }
  522.  
  523.     pbc->Release();
  524.     return FALSE;
  525.     }
  526.  
  527.  
  528.  
  529.  
  530. /*
  531.  * CLinks::CreateNewSourceMoniker
  532.  * (Protected)
  533.  *
  534.  * Purpose:
  535.  *  Given a name of a link source create a moniker for it.
  536.  *
  537.  * Parameters:
  538.  *  pszName         LPTSTR of the source
  539.  *  cchName         ULONG length of the filename in pszName.
  540.  *  ppmk            LPMONIKER * into which to store the moniker
  541.  *
  542.  * Return Value:
  543.  *  BOOL            TRUE if *ppmk has a valid moniker,
  544.  *                  FALSE otherwise.
  545.  */
  546.  
  547. BOOL CLinks::CreateNewSourceMoniker(LPTSTR pszName
  548.     , ULONG cchName, LPMONIKER *ppmk)
  549.     {
  550.     TCHAR       szName[CCHPATHMAX];
  551.     LPMONIKER   pmkFile=NULL;
  552.     LPMONIKER   pmkItem=NULL;
  553.  
  554.     *ppmk=NULL;
  555.     lstrcpyn(szName, pszName, (int)cchName+1);
  556.     CreateFileMoniker(szName, &pmkFile);
  557.  
  558.     if (NULL==pmkFile)
  559.         return FALSE;
  560.  
  561.     if (lstrlen(pszName) > (int)cchName)
  562.         {
  563.         lstrcpy(szName, pszName+cchName+1);
  564.         CreateItemMoniker(TEXT("!"), szName, &pmkItem);
  565.  
  566.         if (NULL!=pmkItem)
  567.             {
  568.             CreateGenericComposite(pmkFile, pmkItem, ppmk);
  569.             pmkItem->Release();
  570.             }
  571.  
  572.         pmkFile->Release();
  573.  
  574.         if (NULL==*ppmk)
  575.             return FALSE;
  576.         }
  577.     else
  578.         *ppmk=pmkFile;
  579.  
  580.     return TRUE;
  581.     }
  582.  
  583.  
  584.  
  585.  
  586. /*
  587.  * CLinks::CchFilePrefix
  588.  * (Protected)
  589.  *
  590.  * Purpose:
  591.  *  Returns the length of a file moniker given that pmk is either
  592.  *  a file moniker or a composite containing a file moniker
  593.  *  as the first item.
  594.  *
  595.  * Parameters:
  596.  *  pmk             IMoniker * to check.
  597.  *
  598.  * Return Value:
  599.  *  UINT            Length of the file moniker text.
  600.  */
  601.  
  602. UINT CLinks::CchFilePrefix(LPMONIKER pmk)
  603.     {
  604.     LPMONIKER       pmkFirst=NULL;
  605.     LPENUMMONIKER   pEnum;
  606.     DWORD           dwMk;
  607.     LPOLESTR        psz=NULL;
  608.     LPBC            pbc=NULL;
  609.     ULONG           cch=0;
  610.     HRESULT         hr;
  611.  
  612.     if (NULL==pmk)
  613.        return 0;
  614.  
  615.     hr=pmk->IsSystemMoniker(&dwMk);
  616.  
  617.     if (FAILED(hr) || MKSYS_GENERICCOMPOSITE!=dwMk)
  618.         {
  619.         //Already a single moniker
  620.         pmkFirst=pmk;
  621.         pmk->AddRef();
  622.         }
  623.     else
  624.         {
  625.         //Pull off the first moniker in a composite
  626.         hr=pmk->Enum(TRUE, &pEnum);
  627.  
  628.         if (FAILED(hr))
  629.             return NULL;
  630.  
  631.         hr=pEnum->Next(1, &pmkFirst, NULL);
  632.         pEnum->Release();
  633.         }
  634.  
  635.     if (NULL==pmkFirst)
  636.         return 0;
  637.  
  638.     hr=pmkFirst->IsSystemMoniker(&dwMk);
  639.  
  640.     if (SUCCEEDED(hr) && MKSYS_FILEMONIKER==dwMk);
  641.         {
  642.         if (SUCCEEDED(CreateBindCtx(0, &pbc)))
  643.             {
  644.             if (SUCCEEDED(pmkFirst->GetDisplayName(pbc, NULL
  645.                 , &psz)))
  646.                 {
  647.                #ifdef WIN32ANSI
  648.                 cch=wcslen(psz);
  649.                #else
  650.                 cch=lstrlen(psz);
  651.                #endif
  652.                 CoTaskMemFree((void *)psz);
  653.                 }
  654.  
  655.             pbc->Release();
  656.             }
  657.         }
  658.  
  659.     pmkFirst->Release();
  660.     return cch;
  661.     }
  662.