home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / activexcontrol / basectl / framewrk / autoobj.cpp next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  16.0 KB  |  532 lines

  1. //=--------------------------------------------------------------------------=
  2. // AutoObj.Cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995-1997 Microsoft Corporation.  All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // all of our objects will inherit from this class to share as much of the same
  13. // code as possible.  this super-class contains the unknown, dispatch and
  14. // error info implementations for them.
  15. //
  16. #include "IPServer.H"
  17. #include "LocalSrv.H"
  18.  
  19. #include "AutoObj.H"
  20. #include "Globals.H"
  21. #include "Util.H"
  22.  
  23.  
  24. // for ASSERT and FAIL
  25. //
  26. SZTHISFILE
  27.  
  28. //=--------------------------------------------------------------------------=
  29. // CAutomationObject::CAutomationObject
  30. //=--------------------------------------------------------------------------=
  31. // create the object and initialize the refcount
  32. //
  33. // Parameters:
  34. //    IUnknown *      - [in] controlling Unknown
  35. //    int             - [in] the object type that we are
  36. //    void *          - [in] the VTable of of the object we really are.
  37. //
  38. // Notes:
  39. //
  40. CAutomationObject::CAutomationObject 
  41. (
  42.     IUnknown *pUnkOuter,
  43.     int   ObjType,
  44.     void *pVTable,
  45.     BOOL fExpandoEnabled
  46. )
  47. : CUnknownObject(pUnkOuter, pVTable), m_ObjectType (ObjType)
  48. {
  49.     m_fLoadedTypeInfo = FALSE;
  50.     m_fExpandoEnabled = fExpandoEnabled;
  51.     m_pexpando = NULL;
  52. }
  53.  
  54.  
  55. //=--------------------------------------------------------------------------=
  56. // CAutomationObject::~CAutomationObject
  57. //=--------------------------------------------------------------------------=
  58. // "I have a rendezvous with Death, At some disputed barricade"
  59. // - Alan Seeger (1888-1916)
  60. //
  61. // Notes:
  62. //
  63. CAutomationObject::~CAutomationObject ()
  64. {
  65.     // if we loaded up a type info, release our count on the globally stashed
  66.     // type infos, and release if it becomes zero.
  67.     //
  68.     if (m_fLoadedTypeInfo) {
  69.  
  70.         // we have to crit sect this since it's possible to have more than
  71.         // one thread partying with this object.
  72.         //
  73.         EnterCriticalSection(&g_CriticalSection);
  74.         ASSERT(CTYPEINFOOFOBJECT(m_ObjectType), "Bogus ref counting on the Type Infos");
  75.         CTYPEINFOOFOBJECT(m_ObjectType)--;
  76.  
  77.         // if we're the last one, free that sucker!
  78.         //
  79.         if (!CTYPEINFOOFOBJECT(m_ObjectType)) {
  80.             PTYPEINFOOFOBJECT(m_ObjectType)->Release();
  81.             PTYPEINFOOFOBJECT(m_ObjectType) = NULL;
  82.         }
  83.         LeaveCriticalSection(&g_CriticalSection);
  84.     }
  85.  
  86.     if (m_pexpando)
  87.     {
  88.         delete m_pexpando;
  89.     }
  90.     return;
  91. }
  92.  
  93. //=--------------------------------------------------------------------------=
  94. // CAutomationObject::InternalQueryInterface
  95. //=--------------------------------------------------------------------------=
  96. // the controlling unknown will call this for us in the case where they're
  97. // looking for a specific interface.
  98. //
  99. // Parameters:
  100. //    REFIID        - [in]  interface they want
  101. //    void **       - [out] where they want to put the resulting object ptr.
  102. //
  103. // Output:
  104. //    HRESULT       - S_OK, E_NOINTERFACE
  105. //
  106. // Notes:
  107. //
  108. HRESULT CAutomationObject::InternalQueryInterface
  109. (
  110.     REFIID riid,
  111.     void **ppvObjOut
  112. )
  113. {
  114.     ASSERT(ppvObjOut, "controlling Unknown should be checking this!");
  115.  
  116.     // start looking for the guids we support, namely IDispatch, and 
  117.     // IDispatchEx
  118.  
  119.     if (DO_GUIDS_MATCH(riid, IID_IDispatch)) {
  120.         // If expando functionality is enabled, attempt to allocate an
  121.         // expando object and return that for the IDispatch interface.
  122.         // If the allocation fails, we will fall back on using the regular
  123.         // IDispatch from m_pvInterface;
  124.         if (m_fExpandoEnabled)
  125.         {
  126.             if (!m_pexpando)
  127.                 m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);  
  128.  
  129.             if (m_pexpando)
  130.             {
  131.                 *ppvObjOut = (void*)(IDispatch*) m_pexpando;
  132.                 ((IUnknown *)(*ppvObjOut))->AddRef();
  133.                 return S_OK;
  134.             }
  135.         }
  136.  
  137.         *ppvObjOut = (void*) (IDispatch*) m_pvInterface;
  138.         ((IUnknown *)(*ppvObjOut))->AddRef();
  139.         return S_OK;
  140.     }
  141.     else if (DO_GUIDS_MATCH(riid, IID_IDispatchEx) && m_fExpandoEnabled) {
  142.         // Allocate the expando object if it hasn't been allocated already
  143.         if (!m_pexpando)
  144.             m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);  
  145.  
  146.         // If the allocation succeeded, return the IDispatchEx interface from
  147.         // the expando.  Otherwise fall through to CUnknownObject::InternalQueryInterface,
  148.         // (which will most likely fail)
  149.         if (m_pexpando)
  150.         {
  151.              *ppvObjOut = (void *)(IDispatchEx *) m_pexpando;
  152.             ((IUnknown *)(*ppvObjOut))->AddRef();
  153.             return S_OK;
  154.         }
  155.     }
  156.  
  157.     // just get our parent class to process it from here on out.
  158.     //
  159.     return CUnknownObject::InternalQueryInterface(riid, ppvObjOut);
  160. }
  161.  
  162. //=--------------------------------------------------------------------------=
  163. // CAutomationObject::GetTypeInfoCount
  164. //=--------------------------------------------------------------------------=
  165. // returns the number of type information interfaces that the object provides
  166. //
  167. // Parameters:
  168. //    UINT *            - [out] the number of interfaces supported.
  169. //
  170. // Output:
  171. //    HRESULT           - S_OK, E_NOTIMPL, E_INVALIDARG
  172. //
  173. // Notes:
  174. //
  175. STDMETHODIMP CAutomationObject::GetTypeInfoCount
  176. (
  177.     UINT *pctinfo
  178. )
  179. {
  180.     // arg checking
  181.     //
  182.     if (!pctinfo)
  183.         return E_INVALIDARG;
  184.  
  185.     // we support GetTypeInfo, so we need to return the count here.
  186.     //
  187.     *pctinfo = 1;
  188.     return S_OK;
  189. }
  190.  
  191. //=--------------------------------------------------------------------------=
  192. // CAutomationObject::GetTypeInfo
  193. //=--------------------------------------------------------------------------=
  194. // Retrieves a type information object, which can be used to get the type
  195. // information for an interface.
  196. //
  197. // Parameters:
  198. //    UINT              - [in]  the type information they'll want returned
  199. //    LCID              - [in]  the LCID of the type info we want
  200. //    ITypeInfo **      - [out] the new type info object.
  201. //
  202. // Output:
  203. //    HRESULT           - S_OK, E_INVALIDARG, etc.
  204. //
  205. // Notes:
  206. //
  207. STDMETHODIMP CAutomationObject::GetTypeInfo
  208. (
  209.     UINT        itinfo,
  210.     LCID        lcid,
  211.     ITypeInfo **ppTypeInfoOut
  212. )
  213. {
  214.     DWORD       dwPathLen;
  215.     char        szDllPath[MAX_PATH];
  216.     HRESULT     hr;
  217.     ITypeLib   *pTypeLib;
  218.     ITypeInfo **ppTypeInfo =NULL;
  219.  
  220.     // arg checking
  221.     //
  222.     if (itinfo != 0)
  223.         return DISP_E_BADINDEX;
  224.  
  225.     if (!ppTypeInfoOut)
  226.         return E_POINTER;
  227.  
  228.     *ppTypeInfoOut = NULL;
  229.  
  230.     // ppTypeInfo will point to our global holder for this particular
  231.     // type info.  if it's null, then we have to load it up. if it's not
  232.     // NULL, then it's already loaded, and we're happy.
  233.     // crit sect this entire nightmare so we're okay with multiple
  234.     // threads trying to use this object.
  235.     //
  236.     EnterCriticalSection(&g_CriticalSection);
  237.     ppTypeInfo = PPTYPEINFOOFOBJECT(m_ObjectType);
  238.  
  239.     if (*ppTypeInfo == NULL) {
  240.  
  241.         ITypeInfo *pTypeInfoTmp;
  242.         HREFTYPE   hrefType;
  243.  
  244.         // we don't have the type info around, so go load the sucker.
  245.         //
  246.         hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType), 0,
  247.                             LANG_NEUTRAL, &pTypeLib);
  248.  
  249.         // if, for some reason, we failed to load the type library this
  250.         // way, we're going to try and load the type library directly out of
  251.         // our resources.  this has the advantage of going and re-setting all
  252.         // the registry information again for us.
  253.         //
  254.         if (FAILED(hr)) {
  255.  
  256.             dwPathLen = GetModuleFileName(g_hInstance, szDllPath, MAX_PATH);
  257.             if (!dwPathLen) {
  258.                 hr = E_FAIL;
  259.                 goto CleanUp;
  260.             }
  261.  
  262.             MAKE_WIDEPTR_FROMANSI(pwsz, szDllPath);
  263.             hr = LoadTypeLib(pwsz, &pTypeLib);
  264.             CLEANUP_ON_FAILURE(hr);
  265.         }
  266.  
  267.         // we've got the Type Library now, so get the type info for the interface
  268.         // we're interested in.
  269.         //
  270.         hr = pTypeLib->GetTypeInfoOfGuid((REFIID)INTERFACEOFOBJECT(m_ObjectType), &pTypeInfoTmp);
  271.         pTypeLib->Release();
  272.         CLEANUP_ON_FAILURE(hr);
  273.  
  274.         // the following couple of lines of code are to dereference the dual
  275.         // interface stuff and take us right to the dispatch portion of the
  276.         // interfaces.
  277.         //
  278.         hr = pTypeInfoTmp->GetRefTypeOfImplType(0xffffffff, &hrefType);
  279.         if (FAILED(hr)) {
  280.             pTypeInfoTmp->Release();
  281.             goto CleanUp;
  282.         }
  283.  
  284.         hr = pTypeInfoTmp->GetRefTypeInfo(hrefType, ppTypeInfo);
  285.         pTypeInfoTmp->Release();
  286.         CLEANUP_ON_FAILURE(hr);
  287.  
  288.         // add an extra reference to this object.  if it ever becomes zero, then
  289.         // we need to release it ourselves.  crit sect this since more than
  290.         // one thread can party on this object.
  291.         //
  292.         CTYPEINFOOFOBJECT(m_ObjectType)++;
  293.         m_fLoadedTypeInfo = TRUE;
  294.     }
  295.  
  296.  
  297.     // we still have to go and addref the Type info object, however, so that
  298.     // the people using it can release it.
  299.     //
  300.     (*ppTypeInfo)->AddRef();
  301.     *ppTypeInfoOut = *ppTypeInfo;
  302.     hr = S_OK;
  303.  
  304.   CleanUp:
  305.     LeaveCriticalSection(&g_CriticalSection);
  306.     return hr;
  307. }
  308.  
  309.  
  310.  
  311. //=--------------------------------------------------------------------------=
  312. // CAutomationObject::GetIDsOfNames
  313. //=--------------------------------------------------------------------------=
  314. // Maps a single member and an optional set of argument names to a
  315. // corresponding set of integer DISPIDs
  316. //
  317. // Parameters:
  318. //    REFIID            - [in]  must be IID_NULL
  319. //    OLECHAR **        - [in]  array of names to map.
  320. //    UINT              - [in]  count of names in the array.
  321. //    LCID              - [in]  LCID on which to operate
  322. //    DISPID *          - [in]  place to put the corresponding DISPIDs.
  323. //
  324. // Output:
  325. //    HRESULT           - S_OK, E_OUTOFMEMORY, DISP_E_UNKNOWNNAME,
  326. //                        DISP_E_UNKNOWNLCID
  327. //
  328. // Notes:
  329. //    - we're just going to use DispGetIDsOfNames to save us a lot of hassle,
  330. //      and to let this superclass handle it.
  331. //
  332. STDMETHODIMP CAutomationObject::GetIDsOfNames
  333. (
  334.     REFIID    riid,
  335.     OLECHAR **rgszNames,
  336.     UINT      cNames,
  337.     LCID      lcid,
  338.     DISPID   *rgdispid
  339. )
  340. {
  341.     HRESULT     hr;
  342.     ITypeInfo  *pTypeInfo;
  343.  
  344.     if (!DO_GUIDS_MATCH(riid, IID_NULL))
  345.         return E_INVALIDARG;
  346.  
  347.     // get the type info for this dude!
  348.     //
  349.     hr = GetTypeInfo(0, lcid, &pTypeInfo);
  350.     RETURN_ON_FAILURE(hr);
  351.  
  352.     // use the standard provided routines to do all the work for us.
  353.     //
  354.     hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  355.     pTypeInfo->Release();
  356.  
  357.     return hr;
  358. }
  359.  
  360. //=--------------------------------------------------------------------------=
  361. // CAutomationObject::Invoke
  362. //=--------------------------------------------------------------------------=
  363. // provides access to the properties and methods on this object.
  364. //
  365. // Parameters:
  366. //    DISPID            - [in]  identifies the member we're working with.
  367. //    REFIID            - [in]  must be IID_NULL.
  368. //    LCID              - [in]  language we're working under
  369. //    USHORT            - [in]  flags, propput, get, method, etc ...
  370. //    DISPPARAMS *      - [in]  array of arguments.
  371. //    VARIANT *         - [out] where to put result, or NULL if they don't care.
  372. //    EXCEPINFO *       - [out] filled in in case of exception
  373. //    UINT *            - [out] where the first argument with an error is.
  374. //
  375. // Output:
  376. //    HRESULT           - tonnes of them.
  377. //
  378. // Notes:
  379. //    
  380. STDMETHODIMP CAutomationObject::Invoke
  381. (
  382.     DISPID      dispid,
  383.     REFIID      riid,
  384.     LCID        lcid,
  385.     WORD        wFlags,
  386.     DISPPARAMS *pdispparams,
  387.     VARIANT    *pvarResult,
  388.     EXCEPINFO  *pexcepinfo,
  389.     UINT       *puArgErr
  390. )
  391. {
  392.     HRESULT    hr;
  393.     ITypeInfo *pTypeInfo;
  394.  
  395.     if (!DO_GUIDS_MATCH(riid, IID_NULL))
  396.         return E_INVALIDARG;
  397.  
  398.     // get our typeinfo first!
  399.     //
  400.     hr = GetTypeInfo(0, lcid, &pTypeInfo);
  401.     RETURN_ON_FAILURE(hr);
  402.  
  403.     // Clear exceptions
  404.     //
  405.     SetErrorInfo(0L, NULL);
  406.  
  407.     // This is exactly what DispInvoke does--so skip the overhead.
  408.     //
  409.     hr = pTypeInfo->Invoke(m_pvInterface, dispid, wFlags,
  410.                            pdispparams, pvarResult,
  411.                            pexcepinfo, puArgErr);
  412.     pTypeInfo->Release();
  413.  
  414.     return hr;
  415.  
  416. }
  417.  
  418. //=--------------------------------------------------------------------------=
  419. // CAutomationObject::Exception
  420. //=--------------------------------------------------------------------------=
  421. // fills in the rich error info object so that both our vtable bound interfaces
  422. // and calls through ITypeInfo::Invoke get the right error informaiton.
  423. //
  424. // Parameters:
  425. //    HRESULT          - [in] the SCODE that should be associated with this err
  426. //    WORD             - [in] the RESOURCE ID of the error message.
  427. //    DWORD            - [in] helpcontextid for the error
  428. //
  429. // Output:
  430. //    HRESULT          - the HRESULT that was passed in.
  431. //
  432. // Notes:
  433. //
  434. HRESULT CAutomationObject::Exception
  435. (
  436.     HRESULT hrExcep,
  437.     WORD    idException,
  438.     DWORD   dwHelpContextID
  439. )
  440. {
  441.     ICreateErrorInfo *pCreateErrorInfo;
  442.     IErrorInfo *pErrorInfo;
  443.     WCHAR   wszTmp[256];
  444.     char    szTmp[256];
  445.     HRESULT hr;
  446.  
  447.  
  448.     // first get the createerrorinfo object.
  449.     //
  450.     hr = CreateErrorInfo(&pCreateErrorInfo);
  451.     if (FAILED(hr)) return hrExcep;
  452.  
  453.     MAKE_WIDEPTR_FROMANSI(wszHelpFile, HELPFILEOFOBJECT(m_ObjectType));
  454.  
  455.     // set up some default information on it.
  456.     //
  457.     pCreateErrorInfo->SetGUID((REFIID)INTERFACEOFOBJECT(m_ObjectType));
  458.     pCreateErrorInfo->SetHelpFile(wszHelpFile);
  459.     pCreateErrorInfo->SetHelpContext(dwHelpContextID);
  460.  
  461.     // load in the actual error string value.  max of 256.
  462.     //
  463.     LoadString(GetResourceHandle(), idException, szTmp, 256);
  464.     MultiByteToWideChar(CP_ACP, 0, szTmp, -1, wszTmp, 256);
  465.     pCreateErrorInfo->SetDescription(wszTmp);
  466.  
  467.     // load in the source
  468.     //
  469.     MultiByteToWideChar(CP_ACP, 0, NAMEOFOBJECT(m_ObjectType), -1, wszTmp, 256);
  470.     pCreateErrorInfo->SetSource(wszTmp);
  471.  
  472.     // now set the Error info up with the system
  473.     //
  474.     hr = pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void **)&pErrorInfo);
  475.     CLEANUP_ON_FAILURE(hr);
  476.  
  477.     SetErrorInfo(0, pErrorInfo);
  478.     pErrorInfo->Release();
  479.  
  480.   CleanUp:
  481.     pCreateErrorInfo->Release();
  482.     return hrExcep;
  483. }
  484.  
  485. //=--------------------------------------------------------------------------=
  486. // CAutomationObject::InterfaceSupportsErrorInfo
  487. //=--------------------------------------------------------------------------=
  488. // indicates whether or not the given interface supports rich error information
  489. //
  490. // Parameters:
  491. //    REFIID        - [in] the interface we want the answer for.
  492. //
  493. // Output:
  494. //    HRESULT       - S_OK = Yes, S_FALSE = No.
  495. //
  496. // Notes:
  497. //
  498. HRESULT CAutomationObject::InterfaceSupportsErrorInfo
  499. (
  500.     REFIID riid
  501. )
  502. {
  503.     // see if it's the interface for the type of object that we are.
  504.     //
  505.     if (riid == (REFIID)INTERFACEOFOBJECT(m_ObjectType))
  506.         return S_OK;
  507.  
  508.     return S_FALSE;
  509. }
  510.  
  511. //=--------------------------------------------------------------------------=
  512. // CAutomationObject::GetResourceHandle    [helper]
  513. //=--------------------------------------------------------------------------=
  514. // virtual routine to get the resource handle.  virtual, so that inheriting
  515. // objects, such as COleControl can use theirs instead, which goes and gets
  516. // the Host's version ...
  517. //
  518. // Output:
  519. //    HINSTANCE
  520. //
  521. // Notes:
  522. //
  523. HINSTANCE CAutomationObject::GetResourceHandle
  524. (
  525.     void
  526. )
  527. {
  528.     return ::GetResourceHandle();
  529. }
  530.  
  531.  
  532.