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 / ctlmisc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  48.5 KB  |  1,681 lines

  1. //=--------------------------------------------------------------------------=
  2. // CtlMisc.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. // things that aren't elsewhere, such as property pages, and connection
  13. // points.
  14.  
  15. #include "IPServer.H"
  16. #include "CtrlObj.H"
  17. #include "CtlHelp.H"
  18. #include "Globals.H"
  19. #include "StdEnum.H"
  20. #include "Util.H"
  21.  
  22. #include <stdarg.h>
  23.  
  24. // for ASSERT and FAIL
  25. //
  26. SZTHISFILE
  27.  
  28. // this is used in our window proc so that we can find out who was last created
  29. //
  30. static COleControl *s_pLastControlCreated;
  31.  
  32. //=--------------------------------------------------------------------------=
  33. // COleControl::COleControl
  34. //=--------------------------------------------------------------------------=
  35. // constructor
  36. //
  37. // Parameters:
  38. //    IUnknown *          - [in] controlling Unknown
  39. //    int                 - [in] type of primary dispatch interface OBJECT_TYPE_*
  40. //    void *              - [in] pointer to entire object
  41. //      BOOL                - [in] whether to enable IDispatchEx functionality
  42. //                            to allow dynamic adding of properties
  43. // Notes:
  44. //
  45. COleControl::COleControl
  46. (
  47.     IUnknown *pUnkOuter,
  48.     int       iPrimaryDispatch,
  49.     void     *pMainInterface,
  50.     BOOL     fExpandoEnabled
  51. )
  52. : CAutomationObject(pUnkOuter, iPrimaryDispatch, pMainInterface, fExpandoEnabled),
  53.   m_cpEvents(SINK_TYPE_EVENT),
  54.   m_cpPropNotify(SINK_TYPE_PROPNOTIFY)
  55. {
  56.     // initialize all our variables -- we decided against using a memory-zeroing
  57.     // memory allocator, so we sort of have to do this work now ...
  58.     //
  59.     m_nFreezeEvents = 0;
  60.  
  61.     m_pClientSite = NULL;
  62.     m_pControlSite = NULL;
  63.     m_pInPlaceSite = NULL;
  64.     m_pInPlaceFrame = NULL;
  65.     m_pInPlaceUIWindow = NULL;
  66.  
  67.  
  68.     m_pInPlaceSiteWndless = NULL;
  69.  
  70.     // certain hosts don't like 0,0 as your initial size, so we're going to set
  71.     // our initial size to 100,50 [so it's at least sort of visible on the screen]
  72.     //
  73.     m_Size.cx = 0;
  74.     m_Size.cy = 0;
  75.     memset(&m_rcLocation, 0, sizeof(m_rcLocation));
  76.  
  77.     m_hRgn = NULL;
  78.     m_hwnd = NULL;
  79.     m_hwndParent = NULL;
  80.     m_hwndReflect = NULL;
  81.     m_fHostReflects = TRUE;
  82.     m_fCheckedReflecting = FALSE;
  83.  
  84.     m_nFreezeEvents = 0;
  85.     m_pSimpleFrameSite = NULL;
  86.     m_pOleAdviseHolder = NULL;
  87.     m_pViewAdviseSink = NULL;
  88.     m_pDispAmbient = NULL;
  89.  
  90.     m_fDirty = FALSE;
  91.     m_fModeFlagValid = FALSE;
  92.     m_fInPlaceActive = FALSE;
  93.     m_fInPlaceVisible = FALSE;
  94.     m_fUIActive = FALSE;
  95.     m_fSaveSucceeded = FALSE;
  96.     m_fViewAdvisePrimeFirst = FALSE;
  97.     m_fViewAdviseOnlyOnce = FALSE;
  98.     m_fRunMode = FALSE;
  99. }
  100.  
  101. //=--------------------------------------------------------------------------=
  102. // COleControl::~COleControl
  103. //=--------------------------------------------------------------------------=
  104. // "We are all of us resigned to death; it's life we aren't resigned to."
  105. //    - Graham Greene (1904-91)
  106. //
  107. // Notes:
  108. //
  109. COleControl::~COleControl()
  110. {
  111.     // if we've still got a window, go and kill it now.
  112.     //
  113.     if (m_hwnd) {
  114.         // so our window proc doesn't crash.
  115.         //
  116.         SetWindowLong(m_hwnd, GWL_USERDATA, 0xFFFFFFFF);
  117.         DestroyWindow(m_hwnd);
  118.     }
  119.  
  120.     if (m_hwndReflect) {
  121.         SetWindowLong(m_hwndReflect, GWL_USERDATA, 0);
  122.         DestroyWindow(m_hwndReflect);
  123.     }
  124.  
  125.     if (m_hRgn != NULL)
  126.     {
  127.        DeleteObject(m_hRgn);
  128.        m_hRgn = NULL;
  129.     }
  130.  
  131.     // clean up all the pointers we're holding around.
  132.     //
  133.     QUICK_RELEASE(m_pClientSite);
  134.     QUICK_RELEASE(m_pControlSite);
  135.     QUICK_RELEASE(m_pInPlaceSite);
  136.     QUICK_RELEASE(m_pInPlaceFrame);
  137.     QUICK_RELEASE(m_pInPlaceUIWindow);
  138.     QUICK_RELEASE(m_pSimpleFrameSite);
  139.     QUICK_RELEASE(m_pOleAdviseHolder);
  140.     QUICK_RELEASE(m_pViewAdviseSink);
  141.     QUICK_RELEASE(m_pDispAmbient);
  142.  
  143.     QUICK_RELEASE(m_pInPlaceSiteWndless);
  144. }
  145.  
  146. #ifndef DEBUG
  147. #pragma optimize("t", on)
  148. #endif // DEBUG
  149.  
  150. //=--------------------------------------------------------------------------=
  151. // COleControl::InternalQueryInterface
  152. //=--------------------------------------------------------------------------=
  153. // derived-controls should delegate back to this when they decide to support
  154. // additional interfaces
  155. //
  156. // Parameters:
  157. //    REFIID        - [in]  interface they want
  158. //    void **       - [out] where they want to put the resulting object ptr.
  159. //
  160. // Output:
  161. //    HRESULT       - S_OK, E_NOINTERFACE
  162. //
  163. // Notes:
  164. //    - NOTE: this function is speed critical!!!!
  165. //
  166. HRESULT COleControl::InternalQueryInterface
  167. (
  168.     REFIID riid,
  169.     void **ppvObjOut
  170. )
  171. {
  172.     switch (riid.Data1) {
  173.         // private interface for prop page support
  174.         case Data1_IControlPrv:
  175.           if(DO_GUIDS_MATCH(riid, IID_IControlPrv)) {
  176.             *ppvObjOut = (void *)this;
  177.             ExternalAddRef();
  178.             return S_OK;
  179.           }
  180.           goto NoInterface;
  181.         QI_INHERITS(this, IOleControl);
  182.         QI_INHERITS(this, IPointerInactive);
  183.         QI_INHERITS(this, IQuickActivate);
  184.         QI_INHERITS(this, IOleObject);
  185.         QI_INHERITS((IPersistStorage *)this, IPersist);
  186.         QI_INHERITS(this, IPersistStreamInit);
  187.         QI_INHERITS(this, IOleInPlaceObject);
  188.         QI_INHERITS(this, IOleInPlaceObjectWindowless);
  189.         QI_INHERITS((IOleInPlaceActiveObject *)this, IOleWindow);
  190.         QI_INHERITS(this, IOleInPlaceActiveObject);
  191.         QI_INHERITS(this, IViewObject);
  192.         QI_INHERITS(this, IViewObject2);
  193.         QI_INHERITS(this, IViewObjectEx);
  194.         QI_INHERITS(this, IConnectionPointContainer);
  195.         QI_INHERITS(this, ISpecifyPropertyPages);
  196.         QI_INHERITS(this, IPersistStorage);
  197.         QI_INHERITS(this, IPersistPropertyBag);
  198.         QI_INHERITS(this, IProvideClassInfo);
  199.         default:
  200.             goto NoInterface;
  201.     }
  202.  
  203.     // we like the interface, so addref and return
  204.     //
  205.     ((IUnknown *)(*ppvObjOut))->AddRef();
  206.     return S_OK;
  207.  
  208.   NoInterface:
  209.     // delegate to super-class for automation interfaces, etc ...
  210.     //
  211.     return CAutomationObject::InternalQueryInterface(riid, ppvObjOut);
  212. }
  213.  
  214. #ifndef DEBUG
  215. #pragma optimize("s", on)
  216. #endif // DEBUG
  217.  
  218. //=--------------------------------------------------------------------------=
  219. // COleControl::FindConnectionPoint    [IConnectionPointContainer]
  220. //=--------------------------------------------------------------------------=
  221. // given an IID, find a connection point sink for it.
  222. //
  223. // Parameters:
  224. //    REFIID              - [in]  interfaces they want
  225. //    IConnectionPoint ** - [out] where the cp should go
  226. //
  227. // Output:
  228. //    HRESULT
  229. //
  230. // Notes:
  231. //
  232. STDMETHODIMP COleControl::FindConnectionPoint
  233. (
  234.     REFIID             riid,
  235.     IConnectionPoint **ppConnectionPoint
  236. )
  237. {
  238.     CHECK_POINTER(ppConnectionPoint);
  239.  
  240.     // we support the event interface, and IDispatch for it, and we also
  241.     // support IPropertyNotifySink.
  242.     //
  243.     if (DO_GUIDS_MATCH(riid, EVENTIIDOFCONTROL(m_ObjectType)) || DO_GUIDS_MATCH(riid, IID_IDispatch))
  244.         *ppConnectionPoint = &m_cpEvents;
  245.     else if (DO_GUIDS_MATCH(riid, IID_IPropertyNotifySink))
  246.         *ppConnectionPoint = &m_cpPropNotify;
  247.     else
  248.         return E_NOINTERFACE;
  249.  
  250.     // generic post-processing.
  251.     //
  252.     (*ppConnectionPoint)->AddRef();
  253.     return S_OK;
  254. }
  255.  
  256. //=--------------------------------------------------------------------------=
  257. // COleControl::EnumConnectionPoints    [IConnectionPointContainer]
  258. //=--------------------------------------------------------------------------=
  259. // creates an enumerator for connection points.
  260. //
  261. // Parameters:
  262. //    IEnumConnectionPoints **    - [out]
  263. //
  264. // Output:
  265. //    HRESULT
  266. //
  267. // Notes:
  268. //
  269. STDMETHODIMP COleControl::EnumConnectionPoints
  270. (
  271.     IEnumConnectionPoints **ppEnumConnectionPoints
  272. )
  273. {
  274.     IConnectionPoint **rgConnectionPoints;
  275.  
  276.     CHECK_POINTER(ppEnumConnectionPoints);
  277.  
  278.     // HeapAlloc an array of connection points [since our standard enum
  279.     // assumes this and HeapFree's it later ]
  280.     //
  281.     rgConnectionPoints = (IConnectionPoint **)HeapAlloc(g_hHeap, 0, sizeof(IConnectionPoint *) * 2);
  282.     RETURN_ON_NULLALLOC(rgConnectionPoints);
  283.  
  284.     // we support the event interface for this dude as well as IPropertyNotifySink
  285.     //
  286.     rgConnectionPoints[0] = &m_cpEvents;
  287.     rgConnectionPoints[1] = &m_cpPropNotify;
  288.  
  289.     *ppEnumConnectionPoints = (IEnumConnectionPoints *)(IEnumGeneric *) new CStandardEnum(IID_IEnumConnectionPoints,
  290.                                 2, sizeof(IConnectionPoint *), (void *)rgConnectionPoints,
  291.                                 CopyAndAddRefObject);
  292.     if (!*ppEnumConnectionPoints) {
  293.         HeapFree(g_hHeap, 0, rgConnectionPoints);
  294.         return E_OUTOFMEMORY;
  295.     }
  296.  
  297.     return S_OK;
  298. }
  299.  
  300. //=--------------------------------------------------------------------------=
  301. // COleControl::GetPages    [ISpecifyPropertyPages]
  302. //=--------------------------------------------------------------------------=
  303. // returns a counted array with the guids for our property pages.
  304. //
  305. // parameters:
  306. //    CAUUID *    - [out] where to put the counted array.
  307. //
  308. // Output:
  309. //    HRESULT
  310. //
  311. // NOtes:
  312. //
  313. STDMETHODIMP COleControl::GetPages
  314. (
  315.     CAUUID *pPages
  316. )
  317. {
  318.     const GUID **pElems;
  319.     void *pv;
  320.     WORD  x;
  321.  
  322.     // if there are no property pages, this is actually pretty easy.
  323.     //
  324.     if (!CPROPPAGESOFCONTROL(m_ObjectType)) {
  325.         pPages->cElems = 0;
  326.         pPages->pElems = NULL;
  327.         return S_OK;
  328.     }
  329.  
  330.     // fill out the Counted array, using IMalloc'd memory.
  331.     //
  332.     pPages->cElems = CPROPPAGESOFCONTROL(m_ObjectType);
  333.     pv = CoTaskMemAlloc(sizeof(GUID) * (pPages->cElems));
  334.     RETURN_ON_NULLALLOC(pv);
  335.     pPages->pElems = (GUID *)pv;
  336.  
  337.     // loop through our array of pages and get 'em.
  338.     //
  339.     pElems = PPROPPAGESOFCONTROL(m_ObjectType);
  340.     for (x = 0; x < pPages->cElems; x++)
  341.         pPages->pElems[x] = *(pElems[x]);
  342.  
  343.     return S_OK;
  344. }
  345.  
  346. //=--------------------------------------------------------------------------=
  347. // COleControl::CConnectionPoint::m_pOleControl
  348. //=--------------------------------------------------------------------------=
  349. // returns a pointer to the control in which we are nested.
  350. //
  351. // Output:
  352. //    COleControl *
  353. //
  354. // Notes:
  355. //
  356. inline COleControl *COleControl::CConnectionPoint::m_pOleControl
  357. (
  358.     void
  359. )
  360. {
  361.     return (COleControl *)((BYTE *)this - ((m_bType == SINK_TYPE_EVENT)
  362.                                           ? offsetof(COleControl, m_cpEvents)
  363.                                           : offsetof(COleControl, m_cpPropNotify)));
  364. }
  365.  
  366. //=--------------------------------------------------------------------------=
  367. // COleControl::CConnectionPoint::QueryInterface
  368. //=--------------------------------------------------------------------------=
  369. // standard qi
  370. //
  371. // Parameters:
  372. //    REFIID        - [in]  interface they want
  373. //    void **       - [out] where they want to put the resulting object ptr.
  374. //
  375. // Output:
  376. //    HRESULT       - S_OK, E_NOINTERFACE
  377. //
  378. // Notes:
  379. //
  380. STDMETHODIMP COleControl::CConnectionPoint::QueryInterface
  381. (
  382.     REFIID riid,
  383.     void **ppvObjOut
  384. )
  385. {
  386.     if (DO_GUIDS_MATCH(riid, IID_IConnectionPoint) || DO_GUIDS_MATCH(riid, IID_IUnknown)) {
  387.         *ppvObjOut = (IConnectionPoint *)this;
  388.         AddRef();
  389.         return S_OK;
  390.     }
  391.  
  392.     return E_NOINTERFACE;
  393. }
  394.  
  395. //=--------------------------------------------------------------------------=
  396. // COleControl::CConnectionPoint::AddRef
  397. //=--------------------------------------------------------------------------=
  398. //
  399. // Output:
  400. //    ULONG        - the new reference count
  401. //
  402. // Notes:
  403. //
  404. ULONG COleControl::CConnectionPoint::AddRef
  405. (
  406.     void
  407. )
  408. {
  409.     return m_pOleControl()->ExternalAddRef();
  410. }
  411.  
  412. //=--------------------------------------------------------------------------=
  413. // COleControl::CConnectionPoint::Release
  414. //=--------------------------------------------------------------------------=
  415. //
  416. // Output:
  417. //    ULONG         - remaining refs
  418. //
  419. // Notes:
  420. //
  421. ULONG COleControl::CConnectionPoint::Release
  422. (
  423.     void
  424. )
  425. {
  426.     return m_pOleControl()->ExternalRelease();
  427. }
  428.  
  429. //=--------------------------------------------------------------------------=
  430. // COleControl::CConnectionPoint::GetConnectionInterface
  431. //=--------------------------------------------------------------------------=
  432. // returns the interface we support connections on.
  433. //
  434. // Parameters:
  435. //    IID *        - [out] interface we support.
  436. //
  437. // Output:
  438. //    HRESULT
  439. //
  440. // Notes:
  441. //
  442. STDMETHODIMP COleControl::CConnectionPoint::GetConnectionInterface
  443. (
  444.     IID *piid
  445. )
  446. {
  447.     if (m_bType == SINK_TYPE_EVENT)
  448.         *piid = EVENTIIDOFCONTROL(m_pOleControl()->m_ObjectType);
  449.     else
  450.         *piid = IID_IPropertyNotifySink;
  451.  
  452.     return S_OK;
  453. }
  454.  
  455. //=--------------------------------------------------------------------------=
  456. // COleControl::CConnectionPoint::GetConnectionPointContainer
  457. //=--------------------------------------------------------------------------=
  458. // returns the connection point container
  459. //
  460. // Parameters:
  461. //    IConnectionPointContainer **ppCPC
  462. //
  463. // Output:
  464. //    HRESULT
  465. //
  466. // Notes:
  467. //
  468. STDMETHODIMP COleControl::CConnectionPoint::GetConnectionPointContainer
  469. (
  470.     IConnectionPointContainer **ppCPC
  471. )
  472. {
  473.     return m_pOleControl()->ExternalQueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
  474. }
  475.  
  476.  
  477. //=--------------------------------------------------------------------------=
  478. // COleControl::CConnectiontPoint::Advise
  479. //=--------------------------------------------------------------------------=
  480. // someboyd wants to be advised when something happens.
  481. //
  482. // Parameters:
  483. //    IUnknown *        - [in]  guy who wants to be advised.
  484. //    DWORD *           - [out] cookie
  485. //
  486. // Output:
  487. //    HRESULT
  488. //
  489. // Notes:
  490. //
  491. STDMETHODIMP COleControl::CConnectionPoint::Advise
  492. (
  493.     IUnknown *pUnk,
  494.     DWORD    *pdwCookie
  495. )
  496. {
  497.     HRESULT    hr;
  498.     void      *pv;
  499.  
  500.     CHECK_POINTER(pdwCookie);
  501.  
  502.     // first, make sure everybody's got what they thinks they got
  503.     //
  504.     if (m_bType == SINK_TYPE_EVENT) {
  505.  
  506.         // CONSIDER: 12.95 -- this theoretically is broken -- if they do a find
  507.         // connection point on IDispatch, and they just happened to also support
  508.         // the Event IID, we'd advise on that.  this is not awesome, but will
  509.         // prove entirely acceptable short term.
  510.         //
  511.         hr = pUnk->QueryInterface(EVENTIIDOFCONTROL(m_pOleControl()->m_ObjectType), &pv);
  512.         if (FAILED(hr))
  513.             hr = pUnk->QueryInterface(IID_IDispatch, &pv);
  514.     }
  515.     else
  516.         hr = pUnk->QueryInterface(IID_IPropertyNotifySink, &pv);
  517.     RETURN_ON_FAILURE(hr);
  518.  
  519.     // finally, add the sink.  it's now been cast to the correct type and has
  520.     // been AddRef'd.
  521.     //
  522.     return AddSink(pv, pdwCookie);
  523. }
  524.  
  525. //=--------------------------------------------------------------------------=
  526. // COleControl::CConnectionPoint::AddSink
  527. //=--------------------------------------------------------------------------=
  528. // in some cases, we'll already have done the QI, and won't need to do the
  529. // work that is done in the Advise routine above.  thus, these people can
  530. // just call this instead. [this stems really from IQuickActivate]
  531. //
  532. // Parameters:
  533. //    void *        - [in]  the sink to add. it's already been addref'd
  534. //    DWORD *       - [out] cookie
  535. //
  536. // Output:
  537. //    HRESULT
  538. //
  539. // Notes:
  540. //
  541. HRESULT COleControl::CConnectionPoint::AddSink
  542. (
  543.     void  *pv,
  544.     DWORD *pdwCookie
  545. )
  546. {
  547.     IUnknown **rgUnkNew;
  548.     int        i = 0;
  549.  
  550.     // we optimize the case where there is only one sink to not allocate
  551.     // any storage.  turns out very rarely is there more than one.
  552.     //
  553.     switch (m_cSinks) {
  554.  
  555.         case 0:
  556.             ASSERT(!m_rgSinks, "this should be null when there are no sinks");
  557.             m_rgSinks = (IUnknown **)pv;
  558.             break;
  559.  
  560.         case 1:
  561.             // go ahead and do the initial allocation.  we'll get 8 at a time
  562.             //
  563.             rgUnkNew = (IUnknown **)HeapAlloc(g_hHeap, 0, 8 * sizeof(IUnknown *));
  564.             RETURN_ON_NULLALLOC(rgUnkNew);
  565.             rgUnkNew[0] = (IUnknown *)m_rgSinks;
  566.             rgUnkNew[1] = (IUnknown *)pv;
  567.             m_rgSinks = rgUnkNew;
  568.             break;
  569.  
  570.         default:
  571.             // if we're out of sinks, then we have to increase the size
  572.             // of the array
  573.             //
  574.             if (!(m_cSinks & 0x7)) {
  575.                 rgUnkNew = (IUnknown **)HeapReAlloc(g_hHeap, 0, m_rgSinks, (m_cSinks + 8) * sizeof(IUnknown *));
  576.                 RETURN_ON_NULLALLOC(rgUnkNew);
  577.                 m_rgSinks = rgUnkNew;
  578.             } else
  579.                 rgUnkNew = m_rgSinks;
  580.  
  581.             rgUnkNew[m_cSinks] = (IUnknown *)pv;
  582.             break;
  583.     }
  584.  
  585.     *pdwCookie = (DWORD)pv;
  586.     m_cSinks++;
  587.     return S_OK;
  588. }
  589.  
  590.  
  591. //=--------------------------------------------------------------------------=
  592. // COleControl::CConnectionPoint::Unadvise
  593. //=--------------------------------------------------------------------------=
  594. // they don't want to be told any more.
  595. //
  596. // Parameters:
  597. //    DWORD        - [in]  the cookie we gave 'em.
  598. //
  599. // Output:
  600. //    HRESULT
  601. //
  602. // Notes:
  603. //
  604. STDMETHODIMP COleControl::CConnectionPoint::Unadvise
  605. (
  606.     DWORD dwCookie
  607. )
  608. {
  609.     IUnknown *pUnk;
  610.     int       x;
  611.  
  612.     if (!dwCookie)
  613.         return S_OK;
  614.  
  615.     // see how many sinks we've currently got, and deal with things based
  616.     // on that.
  617.     //
  618.     switch (m_cSinks) {
  619.         case 1:
  620.             // it's the only sink.  make sure the ptrs are the same, and
  621.             // then free things up
  622.             //
  623.             if ((DWORD)m_rgSinks != dwCookie)
  624.                 return CONNECT_E_NOCONNECTION;
  625.             m_rgSinks = NULL;
  626.             break;
  627.  
  628.         case 2:
  629.             // there are two sinks.  go back down to one sink scenario
  630.             //
  631.             if ((DWORD)m_rgSinks[0] != dwCookie && (DWORD)m_rgSinks[1] != dwCookie)
  632.                 return CONNECT_E_NOCONNECTION;
  633.  
  634.             pUnk = ((DWORD)m_rgSinks[0] == dwCookie)
  635.                    ? m_rgSinks[1]
  636.                    : ((DWORD)m_rgSinks[1] == dwCookie) ? m_rgSinks[0] : NULL;
  637.  
  638.             if (!pUnk) return CONNECT_E_NOCONNECTION;
  639.  
  640.             HeapFree(g_hHeap, 0, m_rgSinks);
  641.             m_rgSinks = (IUnknown **)pUnk;
  642.             break;
  643.  
  644.         default:
  645.             // there are more than two sinks.  just clean up the hole we've
  646.             // got in our array now.
  647.             //
  648.             for (x = 0; x < m_cSinks; x++) {
  649.                 if ((DWORD)m_rgSinks[x] == dwCookie)
  650.                     break;
  651.             }
  652.             if (x == m_cSinks) return CONNECT_E_NOCONNECTION;
  653.             if (x < m_cSinks - 1) 
  654.                 memcpy(&(m_rgSinks[x]), &(m_rgSinks[x + 1]), (m_cSinks -1 - x) * sizeof(IUnknown *));
  655.             else
  656.                 m_rgSinks[x] = NULL;
  657.             break;
  658.     }
  659.  
  660.  
  661.     // we're happy
  662.     //
  663.     m_cSinks--;
  664.     ((IUnknown *)dwCookie)->Release();
  665.     return S_OK;
  666. }
  667.  
  668. //=--------------------------------------------------------------------------=
  669. // COleControl::CConnectionPoint::EnumConnections
  670. //=--------------------------------------------------------------------------=
  671. // enumerates all current connections
  672. //
  673. // Paramters:
  674. //    IEnumConnections ** - [out] new enumerator object
  675. //
  676. // Output:
  677. //    HRESULT
  678. //
  679. // NOtes:
  680. //
  681. STDMETHODIMP COleControl::CConnectionPoint::EnumConnections
  682. (
  683.     IEnumConnections **ppEnumOut
  684. )
  685. {
  686.     CONNECTDATA *rgConnectData = NULL;
  687.     int i;
  688.  
  689.     if (m_cSinks) {
  690.         // allocate some memory big enough to hold all of the sinks.
  691.         //
  692.         rgConnectData = (CONNECTDATA *)HeapAlloc(g_hHeap, 0, m_cSinks * sizeof(CONNECTDATA));
  693.         RETURN_ON_NULLALLOC(rgConnectData);
  694.  
  695.         // fill in the array
  696.         //
  697.         if (m_cSinks == 1) {
  698.             rgConnectData[0].pUnk = (IUnknown *)m_rgSinks;
  699.             rgConnectData[0].dwCookie = (DWORD)m_rgSinks;
  700.         } else {
  701.             // loop through all available sinks.
  702.             //
  703.             for (i = 0; i < m_cSinks; i++) {
  704.                 rgConnectData[i].pUnk = m_rgSinks[i];
  705.                 rgConnectData[i].dwCookie = (DWORD)m_rgSinks[i];
  706.             }
  707.         }
  708.     }
  709.  
  710.     // create yon enumerator object.
  711.     //
  712.     *ppEnumOut = (IEnumConnections *)(IEnumGeneric *)new CStandardEnum(IID_IEnumConnections,
  713.                         m_cSinks, sizeof(CONNECTDATA), rgConnectData, CopyAndAddRefObject);
  714.     if (!*ppEnumOut) {
  715.         HeapFree(g_hHeap, 0, rgConnectData);
  716.         return E_OUTOFMEMORY;
  717.     }
  718.  
  719.     return S_OK;
  720. }
  721.  
  722. //=--------------------------------------------------------------------------=
  723. // COleControl::CConnectionPoint::~CConnectionPoint
  724. //=--------------------------------------------------------------------------=
  725. // cleans up
  726. //
  727. // Notes:
  728. //
  729. COleControl::CConnectionPoint::~CConnectionPoint ()
  730. {
  731.     int x;
  732.  
  733.     // clean up some memory stuff
  734.     //
  735.     if (!m_cSinks)
  736.         return;
  737.     else if (m_cSinks == 1)
  738.         ((IUnknown *)m_rgSinks)->Release();
  739.     else {
  740.         for (x = 0; x < m_cSinks; x++)
  741.             QUICK_RELEASE(m_rgSinks[x]);
  742.         HeapFree(g_hHeap, 0, m_rgSinks);
  743.     }
  744. }
  745.  
  746. //=--------------------------------------------------------------------------=
  747. // COleControl::CConnectionPiont::DoInvoke
  748. //=--------------------------------------------------------------------------=
  749. // fires an event to all listening on our event interface.
  750. //
  751. // Parameters:
  752. //    DISPID            - [in] event to fire.
  753. //    DISPPARAMS        - [in]
  754. //
  755. // Notes:
  756. //
  757. void COleControl::CConnectionPoint::DoInvoke
  758. (
  759.     DISPID      dispid,
  760.     DISPPARAMS *pdispparams
  761. )
  762. {
  763.     int iConnection;
  764.  
  765.     // if we don't have any sinks, then there's nothing to do.  we intentionally
  766.     // ignore errors here.
  767.     //
  768.     if (m_cSinks == 0)
  769.         return;
  770.     else if (m_cSinks == 1)
  771.         ((IDispatch *)m_rgSinks)->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, pdispparams, NULL, NULL, NULL);
  772.     else
  773.         for (iConnection = 0; iConnection < m_cSinks; iConnection++)
  774.             ((IDispatch *)m_rgSinks[iConnection])->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, pdispparams, NULL, NULL, NULL);
  775. }
  776.  
  777. //=--------------------------------------------------------------------------=
  778. // COleControl::CConnectionPoint::DoOnChanged
  779. //=--------------------------------------------------------------------------=
  780. // fires the OnChanged event for IPropertyNotifySink listeners.
  781. //
  782. // Parameters:
  783. //    DISPID            - [in] dude that changed.
  784. //
  785. // Output:
  786. //    none
  787. //
  788. // Notes:
  789. //
  790. void COleControl::CConnectionPoint::DoOnChanged
  791. (
  792.     DISPID dispid
  793. )
  794. {
  795.     int iConnection;
  796.  
  797.     // if we don't have any sinks, then there's nothing to do.
  798.     //
  799.     if (m_cSinks == 0)
  800.         return;
  801.     else if (m_cSinks == 1)
  802.         ((IPropertyNotifySink *)m_rgSinks)->OnChanged(dispid);
  803.     else
  804.         for (iConnection = 0; iConnection < m_cSinks; iConnection++)
  805.             ((IPropertyNotifySink *)m_rgSinks[iConnection])->OnChanged(dispid);
  806. }
  807.  
  808. //=--------------------------------------------------------------------------=
  809. // COleControl::CConnectionPoint::DoOnRequestEdit
  810. //=--------------------------------------------------------------------------=
  811. // fires the OnRequestEdit for IPropertyNotifySinkListeners
  812. //
  813. // Parameters:
  814. //    DISPID             - [in] dispid user wants to change.
  815. //
  816. // Output:
  817. //    BOOL               - false means you cant
  818. //
  819. // Notes:
  820. //
  821. BOOL COleControl::CConnectionPoint::DoOnRequestEdit
  822. (
  823.     DISPID dispid
  824. )
  825. {
  826.     HRESULT hr;
  827.     int     iConnection;
  828.  
  829.     // if we don't have any sinks, then there's nothing to do.
  830.     //
  831.     if (m_cSinks == 0)
  832.         hr = S_OK;
  833.     else if (m_cSinks == 1)
  834.         hr =((IPropertyNotifySink *)m_rgSinks)->OnRequestEdit(dispid);
  835.     else {
  836.         for (iConnection = 0; iConnection < m_cSinks; iConnection++) {
  837.             hr = ((IPropertyNotifySink *)m_rgSinks[iConnection])->OnRequestEdit(dispid);
  838.             if (hr != S_OK) break;
  839.         }
  840.     }
  841.  
  842.     return (hr == S_OK) ? TRUE : FALSE;
  843. }
  844.  
  845. //=--------------------------------------------------------------------------=
  846. // COleControl::CreateInPlaceWindow
  847. //=--------------------------------------------------------------------------=
  848. // creates the window with which we will be working.
  849. // yay.
  850. //
  851. // Parameters:
  852. //    int            - [in] left
  853. //    int            - [in] top
  854. //    BOOL           - [in] can we skip redrawing?
  855. //
  856. // Output:
  857. //    HWND
  858. //
  859. // Notes:
  860. //    - DANGER! DANGER!  this function is protected so that anybody can call it
  861. //      from their control.  however, people should be extremely careful of when
  862. //      and why they do this.  preferably, this function would only need to be
  863. //      called by an end-control writer in design mode to take care of some
  864. //      hosting/painting issues.  otherwise, the framework should be left to
  865. //      call it when it wants.
  866. //
  867. HWND COleControl::CreateInPlaceWindow
  868. (
  869.     int  x,
  870.     int  y,
  871.     BOOL fNoRedraw
  872. )
  873. {
  874.     BOOL    fVisible;
  875.     HRESULT hr;
  876.     DWORD   dwWindowStyle, dwExWindowStyle;
  877.     char    szWindowTitle[128];
  878.  
  879.     // if we've already got a window, do nothing.
  880.     //
  881.     if (m_hwnd)
  882.         return m_hwnd;
  883.  
  884.     // get the user to register the class if it's not already
  885.     // been done.  we have to critical section this since more than one thread
  886.     // can be trying to create this control
  887.     //
  888.     EnterCriticalSection(&g_CriticalSection);
  889.     if (!CTLWNDCLASSREGISTERED(m_ObjectType)) {
  890.         if (!RegisterClassData()) {
  891.             LeaveCriticalSection(&g_CriticalSection);
  892.             return NULL;
  893.         } else 
  894.             CTLWNDCLASSREGISTERED(m_ObjectType) = TRUE;
  895.     }
  896.     LeaveCriticalSection(&g_CriticalSection);
  897.  
  898.     // let the user set up things like the window title, the
  899.     // style, and anything else they feel interested in fiddling
  900.     // with.
  901.     //
  902.     dwWindowStyle = dwExWindowStyle = 0;
  903.     szWindowTitle[0] = '\0';
  904.     if (!BeforeCreateWindow(&dwWindowStyle, &dwExWindowStyle, szWindowTitle))
  905.         return NULL;
  906.  
  907.     dwWindowStyle |= (WS_CHILD | WS_CLIPSIBLINGS);
  908.  
  909.     // create window visible if parent hidden (common case)
  910.     // otherwise, create hidden, then shown.  this is a little subtle, but
  911.     // it makes sense eventually.
  912.     //
  913.     if (!m_hwndParent)
  914.         m_hwndParent = GetParkingWindow();
  915.  
  916.     fVisible = IsWindowVisible(m_hwndParent);
  917.  
  918.     // This one kinda sucks -- if a control is subclassed, and we're in
  919.     // a host that doesn't support Message Reflecting, we have to create
  920.     // the user window in another window which will do all the reflecting.
  921.     // VERY blech. [don't however, bother in design mode]
  922.     //
  923.     if (SUBCLASSWNDPROCOFCONTROL(m_ObjectType) && (m_hwndParent != GetParkingWindow())) {
  924.         // determine if the host supports message reflecting.
  925.         //
  926.         if (!m_fCheckedReflecting) {
  927.             VARIANT_BOOL f;
  928.             hr = GetAmbientProperty(DISPID_AMBIENT_MESSAGEREFLECT, VT_BOOL, &f);
  929.             if (FAILED(hr) || !f)
  930.                 m_fHostReflects = FALSE;
  931.             m_fCheckedReflecting = TRUE;
  932.         }
  933.  
  934.         // if the host doesn't support reflecting, then we have to create
  935.         // an extra window around the control window, and then parent it
  936.         // off that.
  937.         //
  938.         if (!m_fHostReflects) {
  939.             ASSERT(m_hwndReflect == NULL, "Where'd this come from?");
  940.             m_hwndReflect = CreateReflectWindow(!fVisible, m_hwndParent, x, y, &m_Size);
  941.             if (!m_hwndReflect)
  942.                 return NULL;
  943.             SetWindowLong(m_hwndReflect, GWL_USERDATA, (long)this);
  944.             dwWindowStyle |= WS_VISIBLE;
  945.         }
  946.     } else {
  947.         if (!fVisible)
  948.             dwWindowStyle |= WS_VISIBLE;
  949.     }
  950.  
  951.     // we have to mutex the entire create window process since we need to use
  952.     // the s_pLastControlCreated to pass in the object pointer.  nothing too
  953.     // serious
  954.     //
  955.     EnterCriticalSection(&g_CriticalSection);
  956.     s_pLastControlCreated = this;
  957.     m_fCreatingWindow = TRUE;
  958.  
  959.     // finally, go create the window, parenting it as appropriate.
  960.     //
  961.     m_hwnd = CreateWindowEx(dwExWindowStyle,
  962.                             WNDCLASSNAMEOFCONTROL(m_ObjectType),
  963.                             szWindowTitle,
  964.                             dwWindowStyle,
  965.                             (m_hwndReflect) ? 0 : x,
  966.                             (m_hwndReflect) ? 0 : y,
  967.                             m_Size.cx, m_Size.cy,
  968.                             (m_hwndReflect) ? m_hwndReflect : m_hwndParent,
  969.                             NULL, g_hInstance, NULL);
  970.  
  971.     // clean up some variables, and leave the critical section
  972.     //
  973.     m_fCreatingWindow = FALSE;
  974.     s_pLastControlCreated = NULL;
  975.     LeaveCriticalSection(&g_CriticalSection);
  976.  
  977.     if (m_hwnd) {
  978.         // let the derived-control do something if they so desire
  979.         //
  980.         if (!AfterCreateWindow()) {
  981.             BeforeDestroyWindow();
  982.             SetWindowLong(m_hwnd, GWL_USERDATA, 0xFFFFFFFF);
  983.             DestroyWindow(m_hwnd);
  984.             m_hwnd = NULL;
  985.             return m_hwnd;
  986.         }
  987.  
  988.         // if we didn't create the window visible, show it now.
  989.         //
  990.         
  991.         if (fVisible)
  992.         {
  993.             if (GetParent(m_hwnd) != m_hwndParent)
  994.                 // SetWindowPos fails if parent hwnd is passed in so keep
  995.                 // this behaviour in those cases without ripping. 
  996.                 SetWindowPos(m_hwnd, m_hwndParent, 0, 0, 0, 0,
  997.                              SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW | ((fNoRedraw) ? SWP_NOREDRAW : 0));
  998.         }
  999.     }
  1000.  
  1001.     // finally, tell the host of this
  1002.     //
  1003.     if (m_pClientSite)
  1004.         m_pClientSite->ShowObject();
  1005.  
  1006.     return m_hwnd;
  1007. }
  1008.  
  1009. //=--------------------------------------------------------------------------=
  1010. // COleControl::SetInPlaceParent    [helper]
  1011. //=--------------------------------------------------------------------------=
  1012. // sets up the parent window for our control.
  1013. //
  1014. // Parameters:
  1015. //    HWND            - [in] new parent window
  1016. //
  1017. // Notes:
  1018. //
  1019. void COleControl::SetInPlaceParent
  1020. (
  1021.     HWND hwndParent
  1022. )
  1023. {
  1024.     ASSERT(!m_pInPlaceSiteWndless, "This routine should only get called for windowed OLE controls");
  1025.  
  1026.     if (m_hwndParent == hwndParent)
  1027.         return;
  1028.  
  1029.     m_hwndParent = hwndParent;
  1030.     if (m_hwnd)
  1031.         SetParent(GetOuterWindow(), hwndParent);
  1032. }
  1033.  
  1034. //=--------------------------------------------------------------------------=
  1035. // COleControl::ControlWindowProc
  1036. //=--------------------------------------------------------------------------=
  1037. // default window proc for an OLE Control.   controls will have their own
  1038. // window proc called from this one, after some processing is done.
  1039. //
  1040. // Parameters:
  1041. //    - see win32sdk docs.
  1042. //
  1043. // Notes:
  1044. //
  1045. LRESULT CALLBACK COleControl::ControlWindowProc
  1046. (
  1047.     HWND    hwnd,
  1048.     UINT    msg,
  1049.     WPARAM  wParam,
  1050.     LPARAM  lParam
  1051. )
  1052. {
  1053.     COleControl *pCtl = ControlFromHwnd(hwnd);
  1054.     HRESULT hr;
  1055.     LRESULT lResult;
  1056.     DWORD   dwCookie;
  1057.  
  1058.     // if the value isn't a positive value, then it's in some special
  1059.     // state [creation or destruction]  this is safe because under win32,
  1060.     // the upper 2GB of an address space aren't available.
  1061.     //
  1062.     if ((LONG)pCtl == 0) {
  1063.         pCtl = s_pLastControlCreated;
  1064.         SetWindowLong(hwnd, GWL_USERDATA, (LONG)pCtl);
  1065.         pCtl->m_hwnd = hwnd;
  1066.     } else if ((ULONG)pCtl == 0xffffffff) {
  1067.         return DefWindowProc(hwnd, msg, wParam, lParam);
  1068.     }
  1069.  
  1070.     // message preprocessing
  1071.     //
  1072.     if (pCtl->m_pSimpleFrameSite) {
  1073.         hr = pCtl->m_pSimpleFrameSite->PreMessageFilter(hwnd, msg, wParam, lParam, &lResult, &dwCookie);
  1074.         if (hr == S_FALSE) return lResult;
  1075.     }
  1076.  
  1077.     // for certain messages, do not call the user window proc. instead,
  1078.     // we have something else we'd like to do.
  1079.     //
  1080.     switch (msg) {
  1081.       case WM_PAINT:
  1082.         {
  1083.         // call the user's OnDraw routine.
  1084.         //
  1085.         PAINTSTRUCT ps;
  1086.         RECT        rc;
  1087.         HDC         hdc;
  1088.  
  1089.         // if we're given an HDC, then use it
  1090.         //
  1091.         if (!wParam)
  1092.             hdc = BeginPaint(hwnd, &ps);
  1093.         else
  1094.             hdc = (HDC)wParam;
  1095.  
  1096.         GetClientRect(hwnd, &rc);
  1097.         pCtl->OnDraw(DVASPECT_CONTENT, hdc, (RECTL *)&rc, NULL, NULL, TRUE);
  1098.  
  1099.         if (!wParam)
  1100.             EndPaint(hwnd, &ps);
  1101.         }
  1102.         break;
  1103.  
  1104.       default:
  1105.         // call the derived-control's window proc
  1106.         //
  1107.         lResult = pCtl->WindowProc(msg, wParam, lParam);
  1108.         break;
  1109.     }
  1110.  
  1111.     // message postprocessing
  1112.     //
  1113.     switch (msg) {
  1114.  
  1115.       case WM_NCDESTROY:
  1116.         // after this point, the window doesn't exist any more
  1117.         //
  1118.         pCtl->m_hwnd = NULL;
  1119.         break;
  1120.  
  1121.       case WM_SETFOCUS:
  1122.       case WM_KILLFOCUS:
  1123.         // give the control site focus notification
  1124.         //
  1125.         if (pCtl->m_fInPlaceActive && pCtl->m_pControlSite)
  1126.             pCtl->m_pControlSite->OnFocus(msg == WM_SETFOCUS);
  1127.         break;
  1128.  
  1129.       case WM_SIZE:
  1130.         // a change in size is a change in view
  1131.         //
  1132.         if (!pCtl->m_fCreatingWindow)
  1133.             pCtl->ViewChanged();
  1134.         break;
  1135.     }
  1136.  
  1137.     // lastly, simple frame postmessage processing
  1138.     //
  1139.     if (pCtl->m_pSimpleFrameSite)
  1140.         pCtl->m_pSimpleFrameSite->PostMessageFilter(hwnd, msg, wParam, lParam, &lResult, dwCookie);
  1141.  
  1142.     return lResult;
  1143. }
  1144.  
  1145. //=--------------------------------------------------------------------------=
  1146. // COleControl::SetFocus
  1147. //=--------------------------------------------------------------------------=
  1148. // we have to override this routine to get UI Activation correct.
  1149. //
  1150. // Parameters:
  1151. //    BOOL              - [in] true means take, false release
  1152. //
  1153. // Output:
  1154. //    BOOL
  1155. //
  1156. // Notes:
  1157. //    - CONSIDER: this is pretty messy, and it's still not entirely clear
  1158. //      what the ole control/focus story is.
  1159. //
  1160. BOOL COleControl::SetFocus
  1161. (
  1162.     BOOL fGrab
  1163. )
  1164. {
  1165.     HRESULT hr;
  1166.     HWND    hwnd;
  1167.  
  1168.     // first thing to do is check out UI Activation state, and then set
  1169.     // focus [either with windows api, or via the host for windowless
  1170.     // controls]
  1171.     //
  1172.     if (m_pInPlaceSiteWndless) {
  1173.         if (!m_fUIActive && fGrab)
  1174.             if (FAILED(InPlaceActivate(OLEIVERB_UIACTIVATE))) return FALSE;
  1175.  
  1176.         hr = m_pInPlaceSiteWndless->SetFocus(fGrab);
  1177.         return (hr == S_OK) ? TRUE : FALSE;
  1178.     } else {
  1179.  
  1180.         // we've got a window.
  1181.         //
  1182.         if (m_fInPlaceActive) {
  1183.             hwnd = (fGrab) ? m_hwnd : m_hwndParent;
  1184.             if (!m_fUIActive && fGrab)
  1185.                 return SUCCEEDED(InPlaceActivate(OLEIVERB_UIACTIVATE));
  1186.             else
  1187.                 return SetGUIFocus(hwnd);
  1188.         } else
  1189.             return FALSE;
  1190.     }
  1191.  
  1192.     // dead code
  1193. }
  1194.  
  1195. //=--------------------------------------------------------------------------=
  1196. // COleControl::SetGUIFocus
  1197. //=--------------------------------------------------------------------------=
  1198. // does the work of setting the Windows GUI focus to the specified window
  1199. //
  1200. // Parameters:
  1201. //    HWND              - [in] window that should get focus
  1202. //
  1203. // Output:
  1204. //    BOOL              - [out] whether setting focus succeeded
  1205. //
  1206. // Notes:
  1207. //    we do this because some controls host non-ole window hierarchies, like
  1208. // the Netscape plugin ocx.  in such cases, the control may need to be UIActive
  1209. // to function properly in the document, but cannot take the windows focus
  1210. // away from one of its child windows.  such controls may override this method
  1211. // and respond as appropriate.
  1212. //
  1213. BOOL COleControl::SetGUIFocus
  1214. (
  1215.     HWND hwndSet
  1216. )
  1217. {
  1218.     return (::SetFocus(hwndSet) == hwndSet);
  1219. }
  1220.  
  1221.  
  1222. //=--------------------------------------------------------------------------=
  1223. // COleControl::ReflectWindowProc
  1224. //=--------------------------------------------------------------------------=
  1225. // reflects window messages on to the child window.  very lame.
  1226. //
  1227. // Parameters and Output:
  1228. //    - see win32 sdk docs
  1229. //
  1230. // Notes:
  1231. //
  1232. LRESULT CALLBACK COleControl::ReflectWindowProc
  1233. (
  1234.     HWND    hwnd,
  1235.     UINT    msg,
  1236.     WPARAM  wParam,
  1237.     LPARAM  lParam
  1238. )
  1239. {
  1240.     COleControl *pCtl;
  1241.  
  1242.     switch (msg) {
  1243.         case WM_COMMAND:
  1244.         case WM_NOTIFY:
  1245.         case WM_CTLCOLORBTN:
  1246.         case WM_CTLCOLORDLG:
  1247.         case WM_CTLCOLOREDIT:
  1248.         case WM_CTLCOLORLISTBOX:
  1249.         case WM_CTLCOLORMSGBOX:
  1250.         case WM_CTLCOLORSCROLLBAR:
  1251.         case WM_CTLCOLORSTATIC:
  1252.         case WM_DRAWITEM:
  1253.         case WM_MEASUREITEM:
  1254.         case WM_DELETEITEM:
  1255.         case WM_VKEYTOITEM:
  1256.         case WM_CHARTOITEM:
  1257.         case WM_COMPAREITEM:
  1258.         case WM_HSCROLL:
  1259.         case WM_VSCROLL:
  1260.         case WM_PARENTNOTIFY:
  1261.         case WM_SETFOCUS:
  1262.         case WM_SIZE:
  1263.             pCtl = (COleControl *)GetWindowLong(hwnd, GWL_USERDATA);
  1264.             if (pCtl)
  1265.                 return SendMessage(pCtl->m_hwnd, OCM__BASE + msg, wParam, lParam);
  1266.             break;
  1267.     }
  1268.  
  1269.     return DefWindowProc(hwnd, msg, wParam, lParam);
  1270. }
  1271.  
  1272. //=--------------------------------------------------------------------------=
  1273. // COleControl::GetAmbientProperty    [callable]
  1274. //=--------------------------------------------------------------------------=
  1275. // returns the value of an ambient property
  1276. //
  1277. // Parameters:
  1278. //    DISPID        - [in]  property to get
  1279. //    VARTYPE       - [in]  type of desired data
  1280. //    void *        - [out] where to put the data
  1281. //
  1282. // Output:
  1283. //    BOOL          - FALSE means didn't work.
  1284. //
  1285. // Notes:
  1286. //
  1287. BOOL COleControl::GetAmbientProperty
  1288. (
  1289.     DISPID  dispid,
  1290.     VARTYPE vt,
  1291.     void   *pData
  1292. )
  1293. {
  1294.     DISPPARAMS dispparams;
  1295.     VARIANT v, v2;
  1296.     HRESULT hr;
  1297.  
  1298.     v.vt = VT_EMPTY;
  1299.     v.lVal = 0;
  1300.     v2.vt = VT_EMPTY;
  1301.     v2.lVal = 0;
  1302.  
  1303.     // get a pointer to the source of ambient properties.
  1304.     //
  1305.     if (!m_pDispAmbient) {
  1306.         if (m_pClientSite)
  1307.             m_pClientSite->QueryInterface(IID_IDispatch, (void **)&m_pDispAmbient);
  1308.  
  1309.         if (!m_pDispAmbient)
  1310.             return FALSE;
  1311.     }
  1312.  
  1313.     // now go and get the property into a variant.
  1314.     //
  1315.     memset(&dispparams, 0, sizeof(DISPPARAMS));
  1316.     hr = m_pDispAmbient->Invoke(dispid, IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams,
  1317.                                 &v, NULL, NULL);
  1318.     if (FAILED(hr)) return FALSE;
  1319.  
  1320.     // we've got the variant, so now go an coerce it to the type that the user
  1321.     // wants.  if the types are the same, then this will copy the stuff to
  1322.     // do appropriate ref counting ...
  1323.     //
  1324.     hr = VariantChangeType(&v2, &v, 0, vt);
  1325.     if (FAILED(hr)) {
  1326.         VariantClear(&v);
  1327.         return FALSE;
  1328.     }
  1329.  
  1330.     // copy the data to where the user wants it
  1331.     //
  1332.     CopyMemory(pData, &(v2.lVal), g_rgcbDataTypeSize[vt]);
  1333.     VariantClear(&v);
  1334.     return TRUE;
  1335. }
  1336.  
  1337. //=--------------------------------------------------------------------------=
  1338. // COleControl::GetAmbientFont    [callable]
  1339. //=--------------------------------------------------------------------------=
  1340. // gets the current font for the user.
  1341. //
  1342. // Parameters:
  1343. //    IFont **         - [out] where to put the font.
  1344. //
  1345. // Output:
  1346. //    BOOL             - FALSE means couldn't get it.
  1347. //
  1348. // Notes:
  1349. //
  1350. BOOL COleControl::GetAmbientFont
  1351. (
  1352.     IFont **ppFont
  1353. )
  1354. {
  1355.     IDispatch *pFontDisp;
  1356.  
  1357.     // we don't have to do much here except get the ambient property and QI
  1358.     // it for the user.
  1359.     //
  1360.     *ppFont = NULL;
  1361.     if (!GetAmbientProperty(DISPID_AMBIENT_FONT, VT_DISPATCH, &pFontDisp))
  1362.         return FALSE;
  1363.  
  1364.     pFontDisp->QueryInterface(IID_IFont, (void **)ppFont);
  1365.     pFontDisp->Release();
  1366.     return (*ppFont) ? TRUE : FALSE;
  1367. }
  1368.  
  1369. //=--------------------------------------------------------------------------=
  1370. // COleControl::DesignMode
  1371. //=--------------------------------------------------------------------------=
  1372. // returns TRUE if we're in Design mode.
  1373. //
  1374. // Output:
  1375. //    BOOL            - true is design mode, false is run mode
  1376. //
  1377. // Notes:
  1378. //
  1379. BOOL COleControl::DesignMode
  1380. (
  1381.     void
  1382. )
  1383. {
  1384.     VARIANT_BOOL f;
  1385.  
  1386.     // if we don't already know our run mode, go and get it.  we'll assume
  1387.     // it's true unless told otherwise [or if the operation fails ...]
  1388.     //
  1389.     if (!m_fModeFlagValid) {
  1390.         f = TRUE;
  1391.         m_fModeFlagValid = TRUE;
  1392.         GetAmbientProperty(DISPID_AMBIENT_USERMODE, VT_BOOL, &f);
  1393.         m_fRunMode = f;
  1394.     }
  1395.  
  1396.     return !m_fRunMode;
  1397. }
  1398.  
  1399.  
  1400. //=--------------------------------------------------------------------------=
  1401. // COleControl::FireEvent
  1402. //=--------------------------------------------------------------------------=
  1403. // fires an event.  handles arbitrary number of arguments.
  1404. //
  1405. // Parameters:
  1406. //    EVENTINFO *        - [in] struct that describes the event.
  1407. //    ...                - arguments to the event
  1408. //
  1409. // Output:
  1410. //    none
  1411. //
  1412. // Notes:
  1413. //    - use stdarg's va_* macros.
  1414. //
  1415. void __cdecl COleControl::FireEvent
  1416. (
  1417.     EVENTINFO *pEventInfo,
  1418.     ...
  1419. )
  1420. {
  1421.     va_list    valist;
  1422.     DISPPARAMS dispparams;
  1423.     VARIANT    rgvParameters[MAX_ARGS];
  1424.     VARIANT   *pv;
  1425.     VARTYPE    vt;
  1426.     int        iParameter;
  1427.     int        cbSize;
  1428.  
  1429.     ASSERT(pEventInfo->cParameters <= MAX_ARGS, "Don't support more than MAX_ARGS params.  sorry.");
  1430.  
  1431.     va_start(valist, pEventInfo);
  1432.  
  1433.     // copy the Parameters into the rgvParameters array.  make sure we reverse
  1434.     // them for automation
  1435.     //
  1436.     pv = &(rgvParameters[pEventInfo->cParameters - 1]);
  1437.     for (iParameter = 0; iParameter < pEventInfo->cParameters; iParameter++) {
  1438.  
  1439.         vt = pEventInfo->rgTypes[iParameter];
  1440.  
  1441.         // if it's a by value variant, then just copy the whole
  1442.         // dang thing
  1443.         //
  1444.         if (vt == VT_VARIANT)
  1445.             *pv = va_arg(valist, VARIANT);
  1446.         else {
  1447.             // copy the vt and the data value.
  1448.             //
  1449.             pv->vt = vt;
  1450.             if (vt & VT_BYREF)
  1451.                 cbSize = sizeof(void *);
  1452.             else
  1453.                 cbSize = g_rgcbDataTypeSize[vt];
  1454.  
  1455.             // small optimization -- we can copy 2/4 bytes over quite
  1456.             // quickly.
  1457.             //
  1458.             if (cbSize == sizeof(short))
  1459.                 V_I2(pv) = va_arg(valist, short);
  1460.             else if (cbSize == 4)
  1461.                 V_I4(pv) = va_arg(valist, long);
  1462.             else {
  1463.                 // copy over 8 bytes
  1464.                 //
  1465.                 ASSERT(cbSize == 8, "don't recognize the type!!");
  1466.                 V_CY(pv) = va_arg(valist, CURRENCY);
  1467.             }
  1468.         }
  1469.  
  1470.         pv--;
  1471.     }
  1472.  
  1473.     // fire the event
  1474.     //
  1475.     dispparams.rgvarg = rgvParameters;
  1476.     dispparams.cArgs = pEventInfo->cParameters;
  1477.     dispparams.rgdispidNamedArgs = NULL;
  1478.     dispparams.cNamedArgs = 0;
  1479.  
  1480.     m_cpEvents.DoInvoke(pEventInfo->dispid, &dispparams);
  1481.  
  1482.     va_end(valist);
  1483. }
  1484.  
  1485. //=--------------------------------------------------------------------------=
  1486. // COleControl::AfterCreateWindow    [overridable]
  1487. //=--------------------------------------------------------------------------=
  1488. // something the user can pay attention to
  1489. //
  1490. // Output:
  1491. //    BOOL             - false means fatal error, can't continue
  1492. // Notes:
  1493. //
  1494. BOOL COleControl::AfterCreateWindow
  1495. (
  1496.     void
  1497. )
  1498. {
  1499.     return TRUE;
  1500. }
  1501.  
  1502. //=--------------------------------------------------------------------------=
  1503. // COleControl::BeforeCreateWindow    [overridable]
  1504. //=--------------------------------------------------------------------------=
  1505. // called just before we create a window.  the user should register their
  1506. // window class here, and set up any other things, such as the title of
  1507. // the window, and/or sytle bits, etc ...
  1508. //
  1509. // Parameters:
  1510. //    DWORD *            - [out] dwWindowFlags
  1511. //    DWORD *            - [out] dwExWindowFlags
  1512. //    LPSTR              - [out] name of window to create
  1513. //
  1514. // Output:
  1515. //    BOOL               - false means fatal error, can't continue
  1516. //
  1517. // Notes:
  1518. //
  1519. BOOL COleControl::BeforeCreateWindow
  1520. (
  1521.     DWORD *pdwWindowStyle,
  1522.     DWORD *pdwExWindowStyle,
  1523.     LPSTR  pszWindowTitle
  1524. )
  1525. {
  1526.     return TRUE;
  1527. }
  1528.  
  1529. //=--------------------------------------------------------------------------=
  1530. // COleControl::InvalidateControl    [callable]
  1531. //=--------------------------------------------------------------------------=
  1532. void COleControl::InvalidateControl
  1533. (
  1534.     LPCRECT lpRect
  1535. )
  1536. {
  1537.     if (m_fInPlaceActive)
  1538.         InvalidateRect(m_hwnd, lpRect, TRUE);
  1539.     else
  1540.         ViewChanged();
  1541.  
  1542.     // CONSIDER: one might want to call pOleAdviseHolder->OnDataChanged() here
  1543.     // if there was support for IDataObject
  1544. }
  1545.  
  1546. //=--------------------------------------------------------------------------=
  1547. // COleControl::SetControlSize    [callable]
  1548. //=--------------------------------------------------------------------------=
  1549. // sets the control size. they'll give us the size in pixels.  we've got to
  1550. // convert them back to HIMETRIC before passing them on!
  1551. //
  1552. // Parameters:
  1553. //    SIZEL *        - [in] new size
  1554. //
  1555. // Output:
  1556. //    BOOL
  1557. //
  1558. // Notes:
  1559. //
  1560. BOOL COleControl::SetControlSize
  1561. (
  1562.     SIZEL *pSize
  1563. )
  1564. {
  1565.     HRESULT hr;
  1566.     SIZEL slHiMetric;
  1567.  
  1568.     PixelToHiMetric(pSize, &slHiMetric);
  1569.     hr = SetExtent(DVASPECT_CONTENT, &slHiMetric);
  1570.     return (FAILED(hr)) ? FALSE : TRUE;
  1571. }
  1572.  
  1573. //=--------------------------------------------------------------------------=
  1574. // COleControl::RecreateControlWindow    [callable]
  1575. //=--------------------------------------------------------------------------=
  1576. // called by a [subclassed, typically] control to recreate it's control
  1577. // window.
  1578. //
  1579. // Parameters:
  1580. //    none
  1581. //
  1582. // Output:
  1583. //    HRESULT
  1584. //
  1585. // Notes:
  1586. //    - NOTE: USE ME EXTREMELY SPARINGLY! THIS IS AN EXTREMELY EXPENSIVE
  1587. //      OPERATION!
  1588. //
  1589. HRESULT COleControl::RecreateControlWindow
  1590. (
  1591.     void
  1592. )
  1593. {
  1594.     HRESULT hr;
  1595.     HWND    hwndPrev;
  1596.  
  1597.     // we need to correctly preserve the control's position within the
  1598.     // z-order here.
  1599.     //
  1600.     if (m_hwnd)
  1601.         hwndPrev = ::GetWindow(m_hwnd, GW_HWNDPREV);
  1602.  
  1603.     // if we're in place active, then we have to deactivate, and reactivate
  1604.     // ourselves with the new window ...
  1605.     //
  1606.     if (m_fInPlaceActive) {
  1607.  
  1608.         hr = InPlaceDeactivate();
  1609.         RETURN_ON_FAILURE(hr);
  1610.         hr = InPlaceActivate((m_fUIActive) ? OLEIVERB_UIACTIVATE : OLEIVERB_INPLACEACTIVATE);
  1611.         RETURN_ON_FAILURE(hr);
  1612.  
  1613.     } else if (m_hwnd) {
  1614.         DestroyWindow(m_hwnd);
  1615.         m_hwnd = NULL;
  1616.         if (m_hwndReflect) {
  1617.             DestroyWindow(m_hwndReflect);
  1618.             m_hwndReflect = NULL;
  1619.         }
  1620.  
  1621.         CreateInPlaceWindow(0, 0, FALSE);
  1622.     }
  1623.  
  1624.     // restore z-order position
  1625.     //
  1626.     if (m_hwnd)
  1627.         SetWindowPos(m_hwnd, hwndPrev, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
  1628.  
  1629.     return m_hwnd ? S_OK : E_FAIL;
  1630. }
  1631.  
  1632. // from Globals.C. don't need to mutex it here since we only read it.
  1633. //
  1634. extern HINSTANCE g_hInstResources;
  1635.  
  1636. //=--------------------------------------------------------------------------=
  1637. // COleControl::GetResourceHandle    [callable]
  1638. //=--------------------------------------------------------------------------=
  1639. // gets the HINSTANCE of the DLL where the control should get resources
  1640. // from.  implemented in such a way to support satellite DLLs.
  1641. //
  1642. // Output:
  1643. //    HINSTANCE
  1644. //
  1645. // Notes:
  1646. //
  1647. HINSTANCE COleControl::GetResourceHandle
  1648. (
  1649.     void
  1650. )
  1651. {
  1652.     if (!g_fSatelliteLocalization)
  1653.         return g_hInstance;
  1654.  
  1655.     // if we've already got it, then there's not all that much to do.
  1656.     // don't need to crit sect this one right here since even if they do fall
  1657.     // into the ::GetResourceHandle call, it'll properly deal with things.
  1658.     //
  1659.     if (g_hInstResources)
  1660.         return g_hInstResources;
  1661.  
  1662.     // we'll get the ambient localeid from the host, and pass that on to the
  1663.     // automation object.
  1664.     //
  1665.     // crit sect this for apartment threading support.
  1666.     //
  1667.     EnterCriticalSection(&g_CriticalSection);
  1668.     if (!g_fHaveLocale)
  1669.         // if we can't get the ambient locale id, then we'll just continue
  1670.         // with the globally set up value.
  1671.         //
  1672.         if (!GetAmbientProperty(DISPID_AMBIENT_LOCALEID, VT_I4, &g_lcidLocale))
  1673.             goto Done;
  1674.  
  1675.     g_fHaveLocale = TRUE;
  1676.  
  1677.   Done:
  1678.     LeaveCriticalSection(&g_CriticalSection);
  1679.     return ::GetResourceHandle();
  1680. }
  1681.