home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / internet / scripting / spruuids / oleauto.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-12  |  15.1 KB  |  513 lines

  1. //---------------------------------------------------------------------------
  2. // OleAuto.cpp
  3. //---------------------------------------------------------------------------
  4. // Simple class for doing dual OLE Automation interfaces
  5. //---------------------------------------------------------------------------
  6. // (C) Copyright 1992-1997 by Microsoft Corporation.  All rights reserved.
  7. //
  8. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  9. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  10. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  11. // PARTICULAR PURPOSE.
  12. //---------------------------------------------------------------------------
  13.  
  14. #include "Main.h"
  15. #pragma hdrstop
  16.  
  17. #define NUM_RESERVED_EXTENDER_DISPIDS 500
  18. #define EXTENDER_DISPID_BASE ((ULONG)(0x80010000))
  19. #define IS_EXTENDER_DISPID(x) ( ( (ULONG)(x) & 0xFFFF0000 ) == EXTENDER_DISPID_BASE )
  20.  
  21. SZTHISFILE
  22.  
  23. //---------------------------------------------------------------------------
  24. // A little utility which simplifies firing dispatch events.
  25. //---------------------------------------------------------------------------
  26. HRESULT InvokeEvent
  27. (
  28.   IDispatch  *pdisp,    // IDispatch of Sink
  29.   DISPID      dispid,   // DISPID of event
  30.   VARIANTARG *pvararg,  // Args to event
  31.   UINT        carg      // # args
  32. )
  33. {
  34.   DISPPARAMS dp;
  35.   EXCEPINFO  ei;
  36.   UINT       uArgErr = 0;
  37.  
  38.   dp.rgvarg            = pvararg;
  39.   dp.rgdispidNamedArgs = NULL;
  40.   dp.cArgs             = carg;
  41.   dp.cNamedArgs        = 0;
  42.   return pdisp->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, &dp, NULL, &ei, &uArgErr);
  43. }
  44.  
  45.  
  46. //---------------------------------------------------------------------------
  47. // This routine will load a TypeLib and (optionally) find the TypeInfo inside
  48. // which matches the given clsid.  The TypeLib and TypeInfo pointers are
  49. // in/out so you can simply:
  50. //      hr = LoadTypeInfo(..., &g_pMyTypeLib, &m_pMyObjectsTypeInfo);
  51. // and it will fill in g_pMyTypeLib and m_pMyObjectsTypeInfo, if necessary.
  52. //---------------------------------------------------------------------------
  53. HRESULT LoadTypeInfo
  54. (
  55.   HINSTANCE   hinst,             // hinst of where to load TypeLib from, if not found
  56.   UINT        itinfo,            // index of TypeInfo requested, only 0 supported
  57.   USHORT      dwMaj,             // Maj version # of TypeLib
  58.   USHORT      dwMin,             // Min version # of TypeLib
  59.   LCID        lcid,              // Locale of TypeLib to load
  60.   REFGUID     libid,             // LIBID of TypeLib  to find
  61.   REFCLSID    clsid,             // CLSID of TypeInfo to find
  62.   REFIID      iid,               // IID   of TypeInfo to find
  63.   BOOL        fDispOnly,         // TRUE=ensure *ptinfoIntInOut is a TKIND_DISPATCH, not vtbl
  64.   ITypeLib  **pptlibInOut,       // Ptr to cache of pTypeLib, typically &g_ptlib
  65.   ITypeInfo **pptinfoClassInOut, // Ptr to cache of pTypeInfo, typically &s_ptinfoCls
  66.   ITypeInfo **pptinfoIntInOut    // Ptr to cache of pTypeInfo, typically &s_ptinfoInt
  67. )
  68. {
  69.   HRESULT    hr        = S_OK;
  70.   ITypeInfo *ptinfoT   = NULL;
  71.   TYPEATTR  *ptypeattr = NULL;
  72.  
  73.   // Arg checking
  74.   if (itinfo != 0)
  75.     return DISP_E_BADINDEX;
  76.  
  77.   if (!pptlibInOut)
  78.     return E_POINTER;
  79.  
  80.   // Check to see if we have a TypeLib, load it if not.
  81.   if (!*pptlibInOut)
  82.     {
  83.     hr = LoadRegTypeLib(libid, dwMaj, dwMin, lcid, pptlibInOut);
  84.     if (hr)
  85.       {
  86.       ASSERT(hinst, "hinst==NULL means in-memory TL; shouldn't have to load from resource");
  87.  
  88.       // If, for some reason, we failed to load the type library this way,
  89.       // we're going to try and load the type library directly out of our
  90.       // resources.  This has the advantage of going and re-setting all the
  91.       // registry information again for us.
  92.       DWORD dwPathLen;
  93.       char  szDllPath[MAX_PATH];
  94.  
  95.       dwPathLen = GetModuleFileName(hinst, szDllPath, MAX_PATH);
  96.       if (!dwPathLen)
  97.         return E_FAIL;
  98.  
  99.       MAKE_WIDEPTR_FROMANSI(pwsz, szDllPath);
  100.       CHECK(LoadTypeLib(pwsz, pptlibInOut));
  101.       }
  102.     }
  103.   ASSERT(*pptlibInOut, "Don't have a pTypeLib");
  104.  
  105.   // If the user wants a coclass TypeInfo...
  106.   if (pptinfoClassInOut)
  107.     {
  108.     // ...Check to see if we already have it, and find it in the TypeLib, if not.
  109.     if (!*pptinfoClassInOut)
  110.       {
  111.       // Get coclass TypeInfo
  112.       CHECK((*pptlibInOut)->GetTypeInfoOfGuid(clsid, pptinfoClassInOut));
  113.       }
  114.     }
  115.  
  116.   // If the user wants an interface TypeInfo...
  117.   if (pptinfoIntInOut)
  118.     {
  119.     // ...Check to see if we already have it, and find it in the TypeLib, if not.
  120.     if (!*pptinfoIntInOut)
  121.       {
  122.       // Get interface TypeInfo
  123.       CHECK((*pptlibInOut)->GetTypeInfoOfGuid(iid, &ptinfoT));
  124.       CHECK(ptinfoT->GetTypeAttr(&ptypeattr));
  125.  
  126.       // If we want a TKIND_DISPATCH, but we have a TKIND_INTERFACE, then switch if it's dual
  127.       if (fDispOnly && ptypeattr->typekind == TKIND_INTERFACE)
  128.         {
  129.         // We're on a TKIND_INTERFACE but want a dispatch.  If this is not a dual interface,
  130.         // we're out of luck, so stuff a NULL, and return S_FALSE.
  131.         if (!(ptypeattr->wTypeFlags & TYPEFLAG_FDUAL))
  132.           {
  133.           *pptinfoIntInOut = NULL;
  134.           hr = S_FALSE;
  135.           }
  136.  
  137.         // This is a dual interface, so get the corresponding Disp interface;
  138.         // 0xffffffff is a magic number which does this for us.
  139.         HREFTYPE hrefType;
  140.         CHECK(ptinfoT->GetRefTypeOfImplType(0xffffffff, &hrefType));
  141.         CHECK(ptinfoT->GetRefTypeInfo(hrefType, pptinfoIntInOut));
  142.         }
  143.       else
  144.         {
  145.         *pptinfoIntInOut = ptinfoT;
  146.         (*pptinfoIntInOut)->AddRef();
  147.         }
  148.       }
  149.     }
  150.  
  151. CleanUp:
  152.   // Release all frame variables
  153.   if (ptypeattr)
  154.     ptinfoT->ReleaseTypeAttr(ptypeattr);
  155.   if (ptinfoT)
  156.     ptinfoT->Release();
  157.  
  158.   return hr;
  159. }
  160.  
  161.  
  162.  
  163. //***************************************************************************
  164. // IDispatch Interface
  165. //***************************************************************************
  166.  
  167. //---------------------------------------------------------------------------
  168. // 
  169. //---------------------------------------------------------------------------
  170. STDMETHODIMP COleAuto::GetTypeInfoCount
  171. (
  172.   UINT* pctinfo
  173. )
  174. {
  175.   // Validate args
  176.   if (!pctinfo)
  177.     return E_INVALIDARG;
  178.  
  179.   // Return requested info
  180.   *pctinfo = 1;
  181.   return S_OK;
  182. }
  183.  
  184.  
  185. //---------------------------------------------------------------------------
  186. // 
  187. //---------------------------------------------------------------------------
  188. STDMETHODIMP COleAuto::GetTypeInfo
  189. (
  190.   UINT        itinfo,
  191.   LCID        lcid,
  192.   ITypeInfo** pptinfoOut
  193. )
  194. {
  195.   HRESULT hr = S_OK;
  196.  
  197.   // Validate args
  198.   if (!pptinfoOut)
  199.     return E_INVALIDARG;
  200.   *pptinfoOut = NULL;
  201.  
  202.   // Make sure we have the TypeInfo
  203.   CHECK(this->CheckTypeInfo(itinfo, lcid));
  204.  
  205.   // Return requested info
  206.   *pptinfoOut = *this->GetTinfoIntAddr();
  207.   (*pptinfoOut)->AddRef();    // For *pptiOut
  208.  
  209. CleanUp:
  210.   return hr;
  211. }
  212.  
  213.  
  214. //---------------------------------------------------------------------------
  215. // 
  216. //---------------------------------------------------------------------------
  217. HRESULT COleAuto::CheckTypeInfo
  218. (
  219.   UINT itinfo,
  220.   LCID lcid
  221. )
  222. {
  223.   HRESULT      hr;
  224.   HINSTANCE    hinst;
  225.   SHORT        wMaj, wMin;
  226.   const GUID  *plibid;
  227.   const CLSID *pclsid;
  228.   const IID   *piid;
  229.   ITypeLib   **pptl;
  230.   ITypeInfo  **pptinfoCls;
  231.   ITypeInfo  **pptinfoInt;
  232.  
  233.   pptinfoCls = this->GetTinfoClsAddr();
  234.   pptinfoInt = this->GetTinfoIntAddr();
  235.   if (*pptinfoCls && *pptinfoInt)
  236.     return S_OK;
  237.  
  238.   hr = GetTypeLibInfo(&hinst, &plibid, &wMaj, &wMin, &pclsid, &piid, &pptl);
  239.   if (hr)
  240.     return hr;
  241.  
  242.   return LoadTypeInfo(hinst, itinfo, wMaj, wMin, lcid, *plibid, *pclsid, *piid, FALSE,
  243.                       pptl, pptinfoCls, pptinfoInt);
  244. }
  245.  
  246.  
  247. //---------------------------------------------------------------------------
  248. // 
  249. //---------------------------------------------------------------------------
  250. STDMETHODIMP COleAuto::GetIDsOfNames
  251. (
  252.   REFIID    iid,
  253.   OLECHAR** rgszNames,
  254.   UINT      cNames,
  255.   LCID      lcid,
  256.   DISPID*   prgdispid
  257. )
  258. {
  259.   HRESULT hr;
  260.  
  261.   // Validate Args
  262.   if (iid != IID_NULL)
  263.       return E_INVALIDARG;
  264.  
  265.   // Make sure we have the TypeInfo
  266.   CHECK(this->CheckTypeInfo(0, lcid));
  267.  
  268.   // Use the standard provided routines to do all the work for us.
  269.   hr = (*this->GetTinfoIntAddr())->GetIDsOfNames(rgszNames, cNames, prgdispid);
  270.  
  271.   // Try the base object iff there is a base object and the previous call failed
  272.   if (FAILED(hr) && m_pdispBaseObject)
  273.     {
  274.     hr = m_pdispBaseObject->GetIDsOfNames(iid, rgszNames, cNames, lcid, prgdispid);
  275.     if (SUCCEEDED(hr))
  276.       {
  277.       // Adjust extender dispid.
  278.       if (IS_EXTENDER_DISPID(prgdispid[0]))
  279.         prgdispid[0] += NUM_RESERVED_EXTENDER_DISPIDS;
  280.       }
  281.     }
  282.  
  283. CleanUp:
  284.   return hr;
  285. }
  286.  
  287.  
  288. //---------------------------------------------------------------------------
  289. // 
  290. //---------------------------------------------------------------------------
  291. STDMETHODIMP COleAuto::Invoke
  292. (
  293.   DISPID      dispidMember,
  294.   REFIID      iid,
  295.   LCID        lcid,
  296.   WORD        wFlags,
  297.   DISPPARAMS* pdispparams,
  298.   VARIANT*    pvarResult,
  299.   EXCEPINFO*  pexcepinfo,
  300.   UINT*       puArgErr
  301. )
  302. {
  303.   HRESULT hr;
  304.  
  305.   // Validate args, clear out params
  306.   if (!pdispparams)
  307.     return E_INVALIDARG;
  308.   if (pvarResult)
  309.     VariantInit(pvarResult);
  310.   SetErrorInfo(0L, NULL);
  311.   if (puArgErr)
  312.     *puArgErr = 0;
  313.   if (iid != IID_NULL)
  314.     return E_INVALIDARG;
  315.  
  316.   // Make sure we have the TypeInfo
  317.   CHECK(this->CheckTypeInfo(0, lcid));
  318.  
  319.   // Use the standard provided routines to do all the work for us.
  320.   hr = (*this->GetTinfoIntAddr())->Invoke(this->GetPrimary(), dispidMember, wFlags,
  321.                                           pdispparams, pvarResult, pexcepinfo, puArgErr);
  322.   // Try the base object iff there is a base object and the previous invoke failed
  323.   if (FAILED(hr) && m_pdispBaseObject)
  324.     {
  325.     if (IS_EXTENDER_DISPID(dispidMember))
  326.       dispidMember -= NUM_RESERVED_EXTENDER_DISPIDS;
  327.  
  328.     hr = m_pdispBaseObject->Invoke(dispidMember, iid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  329.     }
  330.  
  331. CleanUp:
  332.   return hr;
  333. }
  334.  
  335.  
  336. //***************************************************************************
  337. // IProvideMultipleClassInfo Interface
  338. //***************************************************************************
  339.  
  340. //---------------------------------------------------------------------------
  341. //
  342. //---------------------------------------------------------------------------
  343. STDMETHODIMP COleAuto::GetMultiTypeInfoCount
  344. (
  345.   ULONG *pc
  346. )
  347.   {
  348.   HRESULT hr;
  349.   ULONG count;
  350.   IProvideClassInfo         *pclsinfo   = NULL;
  351.   IProvideMultipleClassInfo *pclsinfoex = NULL;
  352.  
  353.   // This should not be possible!
  354.   ASSERT(m_pdispBaseObject != NULL, "");
  355.  
  356.   hr = m_pdispBaseObject->QueryInterface(IID_IProvideMultipleClassInfo, (void**)&pclsinfoex);
  357.   if (SUCCEEDED(hr))
  358.     {
  359.     hr = pclsinfoex->GetMultiTypeInfoCount(&count);
  360.     if (SUCCEEDED(hr))
  361.       *pc = count + 1;
  362.     }
  363.   else
  364.     {
  365.     hr = m_pdispBaseObject->QueryInterface(IID_IProvideClassInfo, (void**)&pclsinfo);
  366.     if (FAILED(hr))
  367.       goto Exit;
  368.     *pc = 2;
  369.     }
  370.  
  371. Exit:
  372.   // Release the temp refs
  373.   if (pclsinfoex)
  374.     pclsinfoex->Release();
  375.   if (pclsinfo)
  376.     pclsinfo->Release();
  377.   return hr;
  378.   }
  379.  
  380.  
  381. //---------------------------------------------------------------------------
  382. //
  383. //---------------------------------------------------------------------------
  384. STDMETHODIMP COleAuto::GetInfoOfIndex
  385. (
  386.   ULONG       itinfo,
  387.   DWORD       dwFlags,
  388.   ITypeInfo** pptinfoCoClass,
  389.   DWORD*      pdwTIFlags,
  390.   ULONG*      pcdispidReserved,
  391.   IID*        piidPrimary,
  392.   IID*        piidSource
  393. )
  394.   {
  395.   HRESULT                    hr         = S_OK;
  396.   IProvideClassInfo         *pclsinfo   = NULL;
  397.   IProvideMultipleClassInfo *pclsinfoex = NULL;
  398.  
  399.   // This should not be possible!
  400.   ASSERT(m_pdispBaseObject != NULL, "");
  401.  
  402.   if (itinfo == 0)
  403.     {
  404.     // Return info on ourselves
  405.     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
  406.       {
  407.       // Make sure we have the TypeInfo
  408.       hr = this->CheckTypeInfo(0, 0x0409);
  409.       if (hr)
  410.         goto Exit;
  411.  
  412.       // Return requested info
  413.       *pptinfoCoClass = *this->GetTinfoClsAddr();
  414.       (*pptinfoCoClass)->AddRef();    // For *pptiOut
  415.       if (pdwTIFlags)
  416.         *pdwTIFlags = 0;
  417.       }
  418.     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
  419.       *pcdispidReserved = NUM_RESERVED_EXTENDER_DISPIDS;
  420.     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
  421.       // REVIEW: Not implemented
  422.       *piidPrimary = IID_NULL;
  423.     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
  424.       // REVIEW: Not implemented
  425.       *piidSource = IID_NULL;
  426.     else
  427.       {
  428.       // Look for an extender
  429.       hr = m_pdispBaseObject->QueryInterface(IID_IProvideMultipleClassInfo, (void**)&pclsinfoex);
  430.       if (SUCCEEDED(hr))
  431.         {
  432.         hr = pclsinfoex->GetInfoOfIndex(itinfo-1, dwFlags, pptinfoCoClass, pdwTIFlags,
  433.                                        pcdispidReserved, piidPrimary, piidSource);
  434.         if (SUCCEEDED(hr) && (dwFlags & MULTICLASSINFO_GETTYPEINFO)) 
  435.           *pdwTIFlags = TIFLAGS_EXTENDDISPATCHONLY;
  436.     }
  437.       else
  438.         {
  439.         if (itinfo != 1)
  440.           hr = TYPE_E_ELEMENTNOTFOUND;
  441.  
  442.         hr = m_pdispBaseObject->QueryInterface(IID_IProvideClassInfo, (void**)&pclsinfo);
  443.         if (FAILED(hr))
  444.           goto Exit;
  445.             
  446.         // Return info on unextended base object
  447.         if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
  448.           {
  449.           hr = pclsinfo->GetClassInfo(pptinfoCoClass);
  450.           if (FAILED(hr))
  451.             goto Exit;
  452.           if (pdwTIFlags)
  453.             *pdwTIFlags = TIFLAGS_EXTENDDISPATCHONLY;
  454.           }
  455.         if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
  456.           *pcdispidReserved = 0;
  457.         if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
  458.           // REVIEW: Not implemented
  459.           *piidPrimary = IID_NULL;
  460.         if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
  461.           // REVIEW: Not implemented
  462.           *piidSource = IID_NULL;
  463.         }
  464.       }
  465.     }
  466.  
  467. Exit:
  468.   // Release the temp refs
  469.   if (pclsinfoex)
  470.     pclsinfoex->Release();
  471.   if (pclsinfo)
  472.     pclsinfo->Release();
  473.   return hr;
  474.   }
  475.  
  476.  
  477.  
  478. //***************************************************************************
  479. // Misc 
  480. //***************************************************************************
  481.  
  482. //---------------------------------------------------------------------------
  483. //
  484. //---------------------------------------------------------------------------
  485. HRESULT COleAuto::SetBaseObject
  486. (
  487.   IDispatch *pdisp
  488. )
  489.   {
  490.   if (!pdisp)
  491.     {
  492.     if (m_pdispBaseObject)
  493.       {
  494.       IDispatch* pdispTemp = m_pdispBaseObject;
  495.  
  496.       m_pdispBaseObject = NULL;
  497.       pdispTemp->Release();
  498.       }    
  499.     }
  500.   else
  501.     {
  502.     // Only allow the base object to be set once
  503.     if (m_pdispBaseObject)
  504.       return E_UNEXPECTED;
  505.     m_pdispBaseObject = pdisp;
  506.     m_pdispBaseObject->AddRef();
  507.     }
  508.  
  509.   return S_OK;
  510.   }
  511.  
  512. //--- EOF -------------------------------------------------------------------
  513.