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 / chap14 / beeper3 / beeper.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  18.7 KB  |  773 lines

  1. /*
  2.  * BEEPER.CPP
  3.  * Beeper Automation Object #3 Chapter 14
  4.  *
  5.  * Implementation of the CBeeper class demonstrating the use of
  6.  * standard error handling that ties in with ITypeInfo::Invoke
  7.  * (as well as DispInvoke).  This includes an implementation of
  8.  * ISupportErrorInfo.
  9.  *
  10.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  11.  *
  12.  * Kraig Brockschmidt, Microsoft
  13.  * Internet  :  kraigb@microsoft.com
  14.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  15.  */
  16.  
  17.  
  18. #include "beeper.h"
  19.  
  20. extern HINSTANCE g_hInst;
  21.  
  22. #ifdef WIN32
  23. extern DWORD     g_dwTLS;
  24. #else
  25. LANGID           g_langID;
  26. #endif
  27.  
  28.  
  29. /*
  30.  * CBeeper::CBeeper
  31.  * CBeeper::~CBeeper
  32.  *
  33.  * Parameters (Constructor):
  34.  *  pUnkOuter       LPUNKNOWN of a controlling unknown.
  35.  *  pfnDestroy      PFNDESTROYED to call when an object
  36.  *                  is destroyed.
  37.  */
  38.  
  39. CBeeper::CBeeper(LPUNKNOWN pUnkOuter, PFNDESTROYED pfnDestroy)
  40.     {
  41.     m_cRef=0;
  42.     m_pUnkOuter=pUnkOuter;
  43.     m_pfnDestroy=pfnDestroy;
  44.  
  45.     m_lSound=0;
  46.     m_pImpIDispatch=NULL;
  47.     return;
  48.     }
  49.  
  50.  
  51. CBeeper::~CBeeper(void)
  52.     {
  53.     DeleteInterfaceImp(m_pImpIDispatch);
  54.     return;
  55.     }
  56.  
  57.  
  58.  
  59. /*
  60.  * CBeeper::Init
  61.  *
  62.  * Purpose:
  63.  *  Performs any intiailization of a CBeeper that's prone to failure
  64.  *  that we also use internally before exposing the object outside.
  65.  *
  66.  * Parameters:
  67.  *  None
  68.  *
  69.  * Return Value:
  70.  *  BOOL            TRUE if the function is successful,
  71.  *                  FALSE otherwise.
  72.  */
  73.  
  74. BOOL CBeeper::Init(void)
  75.     {
  76.     LPUNKNOWN       pIUnknown=this;
  77.  
  78.     if (NULL!=m_pUnkOuter)
  79.         pIUnknown=m_pUnkOuter;
  80.  
  81.     m_pImpIDispatch=new CImpIDispatch(this, pIUnknown);
  82.  
  83.     if (NULL==m_pImpIDispatch)
  84.         return FALSE;
  85.  
  86.     return TRUE;
  87.     }
  88.  
  89.  
  90.  
  91.  
  92. /*
  93.  * CBeeper::QueryInterface
  94.  * CBeeper::AddRef
  95.  * CBeeper::Release
  96.  */
  97.  
  98. STDMETHODIMP CBeeper::QueryInterface(REFIID riid, PPVOID ppv)
  99.     {
  100.     *ppv=NULL;
  101.  
  102.     /*
  103.      * The only calls for IUnknown are either in a nonaggregated
  104.      * case or when created in an aggregation, so in either case
  105.      * always return our IUnknown for IID_IUnknown.
  106.      *
  107.      * Note that IBeeper is implemented on CBeeper, and we must
  108.      * also expose that custom interface through QueryInterface.
  109.      */
  110.     if (IID_IUnknown==riid || IID_IBeeper==riid)
  111.         *ppv=this;
  112.  
  113.     /*
  114.      * QueryInterface must respond not only to IID_IDispatch for
  115.      * the primary automation interface, but also to the IID of the
  116.      * dispinterface itself, which in our case is DIID_DIBeeper.
  117.      */
  118.     if (IID_IDispatch==riid || DIID_DIBeeper==riid)
  119.         *ppv=m_pImpIDispatch;
  120.  
  121.     //Indicate that we support error information
  122.     if (IID_ISupportErrorInfo==riid)
  123.         *ppv=m_pImpISuppErr;
  124.  
  125.     //AddRef any interface we'll return.
  126.     if (NULL!=*ppv)
  127.         {
  128.         ((LPUNKNOWN)*ppv)->AddRef();
  129.         return NOERROR;
  130.         }
  131.  
  132.     return ResultFromScode(E_NOINTERFACE);
  133.     }
  134.  
  135.  
  136. STDMETHODIMP_(ULONG) CBeeper::AddRef(void)
  137.     {
  138.     return ++m_cRef;
  139.     }
  140.  
  141.  
  142. STDMETHODIMP_(ULONG) CBeeper::Release(void)
  143.     {
  144.     if (0L!=--m_cRef)
  145.         return m_cRef;
  146.  
  147.     if (NULL!=m_pfnDestroy)
  148.         (*m_pfnDestroy)();
  149.  
  150.     delete this;
  151.     return 0L;
  152.     }
  153.  
  154.  
  155.  
  156.  
  157. //IBeeper interface functions
  158.  
  159. /*
  160.  * CBeeper::get_Sound
  161.  * CBeeper::put_Sound
  162.  *
  163.  * Purpose:
  164.  *  Functions called from DispInvoke to handle the Sound property.
  165.  *
  166.  * Parameters (Set only):
  167.  *  lSound          long, new sound to save after validation
  168.  *
  169.  * Return Value: (Get only):
  170.  *  long            Current sound.
  171.  */
  172.  
  173. STDMETHODIMP_(long) CBeeper::get_Sound(void)
  174.     {
  175.     return m_lSound;
  176.     }
  177.  
  178.  
  179. STDMETHODIMP_(void) CBeeper::put_Sound(long lSound)
  180.     {
  181.     if (MB_OK!=lSound && MB_ICONEXCLAMATION!=lSound
  182.         && MB_ICONQUESTION!=lSound && MB_ICONHAND!=lSound
  183.         && MB_ICONASTERISK!=lSound)
  184.         {
  185.         /*
  186.          * Since we cannot return a value to ITypeInfo::Invoke to
  187.          * indicate an exception condition, we'll use
  188.          * m_pImpIDispatch->Exception to raise them.  This
  189.          * Exception function now uses the error info mechanism
  190.          * to raise exceptions rather than relying on our own
  191.          * single-threaded model as used in Beeper #2.
  192.          */
  193.         m_pImpIDispatch->Exception(EXCEPTION_INVALIDSOUND);
  194.         return;
  195.         }
  196.  
  197.     m_lSound=lSound;
  198.     return;
  199.     }
  200.  
  201.  
  202. /*
  203.  * CBeeper::Beep
  204.  *
  205.  * Purpose:
  206.  *  Function called from DispInvoke to invoke the Beep method.
  207.  *
  208.  * Return Value:
  209.  *  long           The sound played.
  210.  */
  211.  
  212. STDMETHODIMP_(long) CBeeper::Beep(void)
  213.     {
  214.     MessageBeep((UINT)m_lSound);
  215.     return m_lSound;
  216.     }
  217.  
  218.  
  219.  
  220.  
  221.  
  222. //IDispatch interface implementation
  223.  
  224. /*
  225.  * CImpIDispatch::CImpIDispatch
  226.  * CImpIDispatch::~CImpIDispatch
  227.  *
  228.  * Parameters (Constructor):
  229.  *  pObj            PCBeeper of the object we're in.
  230.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  231.  */
  232.  
  233. CImpIDispatch::CImpIDispatch(PCBeeper pObj, LPUNKNOWN pUnkOuter)
  234.     {
  235.     m_cRef=0;
  236.     m_pObj=pObj;
  237.     m_pUnkOuter=pUnkOuter;
  238.  
  239.     //These are created as needed in GetTypeInfo
  240.     m_pITINeutral=NULL;
  241.     m_pITIGerman=NULL;
  242.     return;
  243.     }
  244.  
  245. CImpIDispatch::~CImpIDispatch(void)
  246.     {
  247.     ReleaseInterface(m_pITIGerman);
  248.     ReleaseInterface(m_pITINeutral);
  249.     return;
  250.     }
  251.  
  252.  
  253.  
  254. /*
  255.  * CImpIDispatch::QueryInterface
  256.  * CImpIDispatch::AddRef
  257.  * CImpIDispatch::Release
  258.  *
  259.  * Purpose:
  260.  *  IUnknown members for CImpIDispatch object.
  261.  */
  262.  
  263. STDMETHODIMP CImpIDispatch::QueryInterface(REFIID riid, PPVOID ppv)
  264.     {
  265.     return m_pUnkOuter->QueryInterface(riid, ppv);
  266.     }
  267.  
  268.  
  269. STDMETHODIMP_(ULONG) CImpIDispatch::AddRef(void)
  270.     {
  271.     ++m_cRef;
  272.     return m_pUnkOuter->AddRef();
  273.     }
  274.  
  275. STDMETHODIMP_(ULONG) CImpIDispatch::Release(void)
  276.     {
  277.     --m_cRef;
  278.     return m_pUnkOuter->Release();
  279.     }
  280.  
  281.  
  282.  
  283. /*
  284.  * CImpIDispatch::GetTypeInfoCount
  285.  *
  286.  * Purpose:
  287.  *  Returns the number of type information (ITypeInfo) interfaces
  288.  *  that the object provides (0 or 1).
  289.  *
  290.  * Parameters:
  291.  *  pctInfo         UINT * to the location to receive
  292.  *                  the count of interfaces.
  293.  *
  294.  * Return Value:
  295.  *  HRESULT         NOERROR or a general error code.
  296.  */
  297.  
  298. STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
  299.     {
  300.     //We implement GetTypeInfo so return 1
  301.     *pctInfo=1;
  302.     return NOERROR;
  303.     }
  304.  
  305.  
  306.  
  307.  
  308. /*
  309.  * CImpIDispatch::GetTypeInfo
  310.  *
  311.  * Purpose:
  312.  *  Retrieves type information for the automation interface.  This
  313.  *  is used anywhere that the right ITypeInfo interface is needed
  314.  *  for whatever LCID is applicable.  Specifically, this is used
  315.  *  from within GetIDsOfNames and Invoke.
  316.  *
  317.  * Parameters:
  318.  *  itInfo          UINT reserved.  Must be zero.
  319.  *  lcid            LCID providing the locale for the type
  320.  *                  information.  If the object does not support
  321.  *                  localization, this is ignored.
  322.  *  ppITypeInfo     ITypeInfo ** in which to store the ITypeInfo
  323.  *                  interface for the object.
  324.  *
  325.  * Return Value:
  326.  *  HRESULT         NOERROR or a general error code.
  327.  */
  328.  
  329. STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid
  330.     , ITypeInfo **ppITypeInfo)
  331.     {
  332.     HRESULT     hr;
  333.     ITypeLib   *pITypeLib;
  334.     ITypeInfo **ppITI=NULL;
  335.  
  336.     if (0!=itInfo)
  337.         return ResultFromScode(TYPE_E_ELEMENTNOTFOUND);
  338.  
  339.     if (NULL==ppITypeInfo)
  340.         return ResultFromScode(E_POINTER);
  341.  
  342.     *ppITypeInfo=NULL;
  343.  
  344.     /*
  345.      * Since we returned one from GetTypeInfoCount, this function
  346.      * can be called for a specific locale.  We support English,
  347.      * German, and neutral (defaults to English) locales.  Anything
  348.      * else is an error.
  349.      *
  350.      * After this switch statement, ppITI will either be NULL or
  351.      * a valid pointer in it after.  If NULL, we know we need to
  352.      * load type information, retrieve the ITypeInfo we want, and
  353.      * then store it in *ppITI.
  354.      */
  355.     switch (PRIMARYLANGID(lcid))
  356.         {
  357.         case LANG_NEUTRAL:
  358.         case LANG_ENGLISH:
  359.             ppITI=&m_pITINeutral;
  360.             break;
  361.  
  362.         case LANG_GERMAN:
  363.             ppITI=&m_pITIGerman;
  364.             break;
  365.  
  366.         default:
  367.             return ResultFromScode(DISP_E_UNKNOWNLCID);
  368.         }
  369.  
  370.     //Load a type lib if we don't have the information already.
  371.     if (NULL==*ppITI)
  372.         {
  373.         /*
  374.          * The type libraries are registered under 0 (neutral),
  375.          * 7 (German), and 9 (English) with no specific sub-
  376.          * language, which would make them 407 or 409 and such.
  377.          * If you are sensitive to sub-languages, then use the
  378.          * full LCID instead of just the LANGID as done here.
  379.          */
  380.         hr=LoadRegTypeLib(LIBID_BeeperTypeLibrary, 1, 0
  381.             , PRIMARYLANGID(lcid), &pITypeLib);
  382.  
  383.         /*
  384.          * If LoadRegTypeLib fails, try loading directly with
  385.          * LoadTypeLib, which will register the library for us.
  386.          * Note that there's no default case here because the
  387.          * prior switch will have filtered lcid already.
  388.          *
  389.          * NOTE:  You should prepend your DIR registry key to the
  390.          * .TLB name so you don't depend on it being it the PATH.
  391.          * This sample will be updated later to reflect this.
  392.          */
  393.         if (FAILED(hr))
  394.             {
  395.             switch (PRIMARYLANGID(lcid))
  396.                 {
  397.                 case LANG_NEUTRAL:
  398.                 case LANG_ENGLISH:
  399.                     hr=LoadTypeLib(OLETEXT("BEEP0000.TLB"), &pITypeLib);
  400.                     break;
  401.  
  402.                 case LANG_GERMAN:
  403.                     hr=LoadTypeLib(OLETEXT("BEEP0007.TLB"), &pITypeLib);
  404.                     break;
  405.                 }
  406.             }
  407.  
  408.         if (FAILED(hr))
  409.             return hr;
  410.  
  411.         //Got the type lib, get type info for the interface we want
  412.         hr=pITypeLib->GetTypeInfoOfGuid(DIID_DIBeeper, ppITI);
  413.         pITypeLib->Release();
  414.  
  415.         if (FAILED(hr))
  416.             return hr;
  417.         }
  418.  
  419.     /*
  420.      * Note:  the type library is still loaded since we have
  421.      * an ITypeInfo from it.
  422.      */
  423.  
  424.     (*ppITI)->AddRef();
  425.     *ppITypeInfo=*ppITI;
  426.     return NOERROR;
  427.     }
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. /*
  438.  * CImpIDispatch::GetIDsOfNames
  439.  *
  440.  * Purpose:
  441.  *  Converts text names into DISPIDs to pass to Invoke
  442.  *
  443.  * Parameters:
  444.  *  riid            REFIID reserved.  Must be IID_NULL.
  445.  *  rgszNames       OLECHAR ** pointing to the array of names to be
  446.  *                  mapped.
  447.  *  cNames          UINT number of names to be mapped.
  448.  *  lcid            LCID of the locale.
  449.  *  rgDispID        DISPID * caller allocated array containing IDs
  450.  *                  corresponging to those names in rgszNames.
  451.  *
  452.  * Return Value:
  453.  *  HRESULT         NOERROR or a general error code.
  454.  */
  455.  
  456. STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
  457.     , OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
  458.     {
  459.     HRESULT     hr;
  460.     ITypeInfo  *pTI;
  461.  
  462.     if (IID_NULL!=riid)
  463.         return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  464.  
  465.     //Get the right ITypeInfo for lcid.
  466.     hr=GetTypeInfo(0, lcid, &pTI);
  467.  
  468.     if (SUCCEEDED(hr))
  469.         {
  470.         hr=DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
  471.         pTI->Release();
  472.         }
  473.  
  474.     return hr;
  475.     }
  476.  
  477.  
  478.  
  479. /*
  480.  * CImpIDispatch::Invoke
  481.  *
  482.  * Purpose:
  483.  *  Calls a method in the dispatch interface or manipulates a
  484.  *  property.
  485.  *
  486.  * Parameters:
  487.  *  dispID          DISPID of the method or property of interest.
  488.  *  riid            REFIID reserved, must be IID_NULL.
  489.  *  lcid            LCID of the locale.
  490.  *  wFlags          USHORT describing the context of the invocation.
  491.  *  pDispParams     DISPPARAMS * to the array of arguments.
  492.  *  pVarResult      VARIANT * in which to store the result.  Is
  493.  *                  NULL if the caller is not interested.
  494.  *  pExcepInfo      EXCEPINFO * to exception information.
  495.  *  puArgErr        UINT * in which to store the index of an
  496.  *                  invalid parameter if DISP_E_TYPEMISMATCH
  497.  *                  is returned.
  498.  *
  499.  * Return Value:
  500.  *  HRESULT         NOERROR or a general error code.
  501.  */
  502.  
  503. STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
  504.     , LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
  505.     , VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
  506.     {
  507.     HRESULT     hr;
  508.     ITypeInfo  *pTI;
  509.     LANGID      langID=PRIMARYLANGID(lcid);
  510.  
  511.     //riid is supposed to be IID_NULL always
  512.     if (IID_NULL!=riid)
  513.         return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  514.  
  515.     //Get the ITypeInfo for lcid
  516.     hr=GetTypeInfo(0, lcid, &pTI);
  517.  
  518.     if (FAILED(hr))
  519.         return hr;
  520.  
  521.    #ifdef WIN32
  522.     //This saves the language ID for this thread
  523.     TlsSetValue(g_dwTLS, &langID);
  524.    #else
  525.     g_langID=langID;
  526.    #endif
  527.  
  528.     //Clear exceptions
  529.     SetErrorInfo(0L, NULL);
  530.  
  531.     //This is exactly what DispInvoke does--so skip the overhead.
  532.     hr=pTI->Invoke((IBeeper *)m_pObj, dispID, wFlags
  533.         , pDispParams, pVarResult, pExcepInfo, puArgErr);
  534.  
  535.     //Exception handling is done within ITypeInfo::Invoke
  536.  
  537.     pTI->Release();
  538.     return hr;
  539.     }
  540.  
  541.  
  542.  
  543.  
  544. /*
  545.  * CImpIDispatch::Exception
  546.  *
  547.  * Purpose:
  548.  *  Raises an exception for CImpIDispatch::Invoke from within
  549.  *  ITypeInfo::Invoke using the CreateErrorInfo API and the
  550.  *  ICreateErrorInfo interface.
  551.  *
  552.  *  Note that this method doesn't allow for deferred filling
  553.  *  of an EXCEPINFO structure.
  554.  *
  555.  * Parameters:
  556.  *  wException      WORD exception code.
  557.  */
  558.  
  559. void CImpIDispatch::Exception(WORD wException)
  560.     {
  561.     HRESULT             hr;
  562.     ICreateErrorInfo   *pICreateErr;
  563.     BOOL                fSuccess;
  564.     LPTSTR              psz;
  565.     LPOLESTR            pszHelp;
  566.     UINT                idsSource;
  567.     UINT                idsException;
  568.     DWORD               dwHelpID;
  569.     LANGID              langID=LANG_NEUTRAL;
  570.    #ifdef WIN32
  571.     LANGID             *pLangID;
  572.    #endif
  573.  
  574.    #ifdef WIN32
  575.     pLangID=(LANGID *)TlsGetValue(g_dwTLS);
  576.  
  577.     if (NULL!=pLangID)
  578.         langID=*pLangID;
  579.    #else
  580.         langID=g_langID;
  581.    #endif
  582.  
  583.     /*
  584.      * Thread-safe exception handling means that we call
  585.      * CreateErrorInfo which gives us an ICreateErrorInfo pointer
  586.      * that we then use to set the error information (basically
  587.      * to set the fields of an EXCEPINFO structure.  We then
  588.      * call SetErrorInfo to attach this error to the current
  589.      * thread.  ITypeInfo::Invoke will look for this when it
  590.      * returns from whatever function was invokes by calling
  591.      * GetErrorInfo.
  592.      */
  593.  
  594.     //Not much we can do if this fails.
  595.     if (FAILED(CreateErrorInfo(&pICreateErr)))
  596.         return;
  597.  
  598.     psz=(LPTSTR)malloc(1024*sizeof(TCHAR));
  599.  
  600.     if (NULL==psz)
  601.         {
  602.         pICreateErr->Release();
  603.         return;
  604.         }
  605.  
  606.     fSuccess=FALSE;
  607.  
  608.     switch (wException)
  609.         {
  610.         case EXCEPTION_INVALIDSOUND:
  611.             pICreateErr->SetGUID(DIID_DIBeeper);
  612.  
  613.             dwHelpID=HID_SOUND_PROPERTY_LIMITATIONS;
  614.  
  615.             pszHelp=OLETEXT("beep0000.hlp");
  616.             idsSource=IDS_0_EXCEPTIONSOURCE;
  617.             idsException=IDS_0_EXCEPTIONINVALIDSOUND;
  618.  
  619.             switch (langID)
  620.                 {
  621.                 case LANG_GERMAN:
  622.                     idsSource=IDS_7_EXCEPTIONSOURCE;
  623.                     idsException=IDS_7_EXCEPTIONINVALIDSOUND;
  624.                     pszHelp=OLETEXT("beep0007.hlp");
  625.                     break;
  626.  
  627.                 case LANG_ENGLISH:
  628.                 case LANG_NEUTRAL:
  629.                 default:
  630.                     break;
  631.                 }
  632.  
  633.             fSuccess=TRUE;
  634.             break;
  635.  
  636.         default:
  637.             break;
  638.         }
  639.  
  640.  
  641.     if (fSuccess)
  642.         {
  643.         IErrorInfo *pIErr;
  644.  
  645.         /*
  646.          * If you have a help file, call the functions
  647.          * ICreateErrorInfo::SetHelpFile and
  648.          * ICreateErrorInfo::SetHelpContext as well.  If you
  649.          * set the help file to NULL the context is ignored.
  650.          */
  651.         pICreateErr->SetHelpFile(pszHelp);
  652.         pICreateErr->SetHelpContext(dwHelpID);
  653.  
  654.        #ifdef WIN32ANSI
  655.         OLECHAR     szTemp[256];
  656.  
  657.         LoadString(g_hInst, idsSource, psz, 256);
  658.         MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
  659.         pICreateErr->SetSource(szTemp);
  660.  
  661.         LoadString(g_hInst, idsException, psz, 256);
  662.         MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
  663.         pICreateErr->SetDescription(szTemp);
  664.        #else
  665.         LoadString(g_hInst, idsSource, psz, 1024);
  666.         pICreateErr->SetSource(psz);
  667.  
  668.         LoadString(g_hInst, idsException, psz, 1024);
  669.         pICreateErr->SetDescription(psz);
  670.        #endif
  671.  
  672.         hr=pICreateErr->QueryInterface(IID_IErrorInfo
  673.             , (PPVOID)&pIErr);
  674.  
  675.         if (SUCCEEDED(hr))
  676.             {
  677.             SetErrorInfo(0L, pIErr);
  678.             pIErr->Release();
  679.             }
  680.         }
  681.  
  682.     free(psz);
  683.  
  684.     //SetErrorInfo holds the object's IErrorInfo
  685.     pICreateErr->Release();
  686.     return;
  687.     }
  688.  
  689.  
  690.  
  691.  
  692.  
  693. //ISupportErrorInfo interface implementation
  694.  
  695. /*
  696.  * CImpISupportErrorInfo::CImpISupportErrorInfo
  697.  * CImpISupportErrorInfo::~CImpISupportErrorInfo
  698.  *
  699.  * Parameters (Constructor):
  700.  *  pObj            PCBeeper of the object we're in.
  701.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  702.  */
  703.  
  704. CImpISupportErrorInfo::CImpISupportErrorInfo(PCBeeper pObj
  705.     , LPUNKNOWN pUnkOuter)
  706.     {
  707.     m_cRef=0;
  708.     m_pObj=pObj;
  709.     m_pUnkOuter=pUnkOuter;
  710.     return;
  711.     }
  712.  
  713. CImpISupportErrorInfo::~CImpISupportErrorInfo(void)
  714.     {
  715.     return;
  716.     }
  717.  
  718.  
  719.  
  720. /*
  721.  * CImpISupportErrorInfo::QueryInterface
  722.  * CImpISupportErrorInfo::AddRef
  723.  * CImpISupportErrorInfo::Release
  724.  *
  725.  * Purpose:
  726.  *  IUnknown members for CImpISupportErrorInfo object.
  727.  */
  728.  
  729. STDMETHODIMP CImpISupportErrorInfo::QueryInterface(REFIID riid
  730.     , PPVOID ppv)
  731.     {
  732.     return m_pUnkOuter->QueryInterface(riid, ppv);
  733.     }
  734.  
  735.  
  736. STDMETHODIMP_(ULONG) CImpISupportErrorInfo::AddRef(void)
  737.     {
  738.     ++m_cRef;
  739.     return m_pUnkOuter->AddRef();
  740.     }
  741.  
  742. STDMETHODIMP_(ULONG) CImpISupportErrorInfo::Release(void)
  743.     {
  744.     --m_cRef;
  745.     return m_pUnkOuter->Release();
  746.     }
  747.  
  748.  
  749.  
  750. /*
  751.  * CImpISupportErrorInfo::InterfaceSupportsErrorInfo
  752.  *
  753.  * Purpose:
  754.  *  Informs a caller whether or not a specific interface
  755.  *  supports exceptions through the Set/GetErrorInfo mechanism.
  756.  *
  757.  * Parameters:
  758.  *  riid            REFIID of the interface in question.
  759.  *
  760.  * Return Value:
  761.  *  HRESULT         NOERROR if a call to GetErrorInfo will succeed
  762.  *                  for callers of riid.  S_FALSE if not.
  763.  */
  764.  
  765. STDMETHODIMP CImpISupportErrorInfo::InterfaceSupportsErrorInfo
  766.     (REFIID riid)
  767.     {
  768.     if (DIID_DIBeeper==riid)
  769.         return NOERROR;
  770.  
  771.     return ResultFromScode(S_FALSE);
  772.     }
  773.