home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / vjplusb / activex / inetsdk / samples / axscript / spruuids / src / oleauto.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-03  |  15.2 KB  |  516 lines

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