home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / BOCOLE.PAK / BOCXCTRL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  16.1 KB  |  592 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
  4. //
  5. // $Revision:   2.7  $
  6. //
  7. //  Implements the Bolero half of the OLE2 Control
  8. //
  9. //  BOleControlSite objects impersonate the client application (Container)
  10. //    from the point of view of the Bolero customer who's
  11. //    writing a control (IBPart and IBControl)
  12. //    BOleControlSite aggregate BOleSite or BOleInProcServer and provide
  13. //    implementation for control specific interfaces.
  14. //    BOleControlSite uses IBControl to talk to the control whereas
  15. //    the aggregated BOleInProcServer (BOleSite) uses IBpart.
  16. //    In consequence a control must implement both IBPart and IBControl.
  17. //----------------------------------------------------------------------------
  18. #ifndef _BOCXCTRL_H     
  19. #include <BOCXCtrl.h>
  20. #endif
  21.  
  22. #ifndef _BCONNPNT_H
  23. #include "BConnPnt.h"
  24. #endif
  25.  
  26. #ifndef BOLECMAN_H
  27. #include <BOleCMan.h>
  28. #endif
  29.  
  30. BOleControlSite::BOleControlSite (BOleClassManager *pClassManager,
  31.                               IBUnknownMain *pOuter):
  32.                           BOleComponent (pClassManager, pOuter),
  33.                           // initialize data members
  34.                           pObjInner(NULL), pEventList (NULL),
  35.                           pControlSite (NULL), pControl (NULL),
  36.                                                     fRegConnPoint (false), pDataDirty (NULL)
  37. {
  38.  
  39. }
  40.  
  41. BOleControlSite::~BOleControlSite()
  42. {
  43.   // release aggregate helper
  44.   if (pObjInner)
  45.     pObjInner->ReleaseMain();
  46.  
  47.   // release EventHandler
  48.   // Even if EventHandler is not an interface but a real object
  49.   // we call Realese() on it. EventHandler implements the enumeration
  50.   // of ConnectionPoints and so has got its own lifetime.
  51.   // Anyway we do not use that iterface enumeration to talk with the list
  52.   // but we go through standard C++
  53.   if (pEventList)
  54.     pEventList->Release();
  55.  
  56.   //** release interfaces **
  57.   // Container interfaces
  58.   if (pControlSite)
  59.     pControlSite->Release();
  60.  
  61.   // Control interface
  62.   //if (pControl)
  63.   //  pControl->Release();
  64. }
  65.  
  66. //**** IUnknown methods ****
  67. HRESULT _IFUNC BOleControlSite::QueryInterfaceMain(REFIID iid,
  68.                                       LPVOID FAR* ppVObj)
  69. {
  70.   HRESULT hr = ResultFromScode(E_NOINTERFACE);
  71.   *ppVObj = NULL;
  72.  
  73.   // answer for self (who can ask that???)
  74.   //if (IID_BOleControlSite == iid) {
  75.   //  (BOleControlSite *)*ppVObj = this;
  76.   //  AddRef();
  77.   //  return NOERROR;
  78.   //}
  79.  
  80.   // implemented interfaces
  81.   if (SUCCEEDED(hr = IBControlSite_QueryInterface(this, iid, ppVObj))) {
  82.   }
  83.   else if (SUCCEEDED(hr = IProvideClassInfo_QueryInterface(this, iid, ppVObj))) {
  84.   }
  85.   else if (SUCCEEDED(hr = IOleControl_QueryInterface(this, iid, ppVObj))) {
  86.   }
  87.   else if (SUCCEEDED(hr = IPersistStreamInit_QueryInterface(this, iid, ppVObj))) {
  88.   }
  89.   else if (SUCCEEDED(hr = IConnectionPointContainer_QueryInterface(this, iid, ppVObj))) {
  90.   }
  91.   else if (SUCCEEDED(hr = IBEventsHandler_QueryInterface(this, iid, ppVObj))) {
  92.   }
  93.  
  94.   // base classes
  95.   else if (SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppVObj))) {
  96.   }
  97.  
  98.   // ask aggregate if he knows iid
  99.   else if (pObjInner) {
  100.     hr = pObjInner->QueryInterfaceMain (iid, ppVObj);
  101.   }
  102.  
  103.   return hr;
  104. }
  105.  
  106. //**** IBControlSite methods ****
  107. HRESULT _IFUNC BOleControlSite::Init (UINT nHelperChoice, IBControl* pCnt, UINT CPCSize)
  108. {
  109.   //
  110.   // create aggregated object as required
  111.   //
  112.   if ( nHelperChoice != BOLE_USE_LIGHT ) { // use light control (no linking and embedding)
  113.     PIUnknown pInner = AsPIUnknown (pObjInner);
  114.     if (nHelperChoice == BOLE_USE_EXE )
  115.       pFactory->ComponentCreate (&pInner, AsPIUnknown(pObjOuter), cidBOleSite); // aggregate BOleSite
  116.     else
  117.       pFactory->ComponentCreate (&pInner, AsPIUnknown(pObjOuter), cidBOleInProcSite); // aggregate BOleInProcServer
  118.     pObjInner = AsPIUnknownMain (pInner);
  119.   }
  120.  
  121.   // keep IBControl interface
  122.   pControl = pCnt;
  123.   //pControl->AddRef();
  124.  
  125.     if (SUCCEEDED (pObjInner->QueryInterfaceMain (IID_IBDataState, (LPVOID FAR*)&pDataDirty)))
  126.       pDataDirty->Release ();
  127.  
  128.   // EventHandler deal with ConnecctionPoints
  129.   pEventList = new BEventList (CPCSize);
  130.   if (pEventList) pEventList->AddRef();
  131.  
  132.   return NOERROR;
  133. }
  134.  
  135. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  136. ////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
  137. // Container impementation
  138. //     The following 4 functions are implemented on the container side and
  139. //     do not need any implememtation here
  140. //
  141. //
  142. HRESULT _IFUNC BOleControlSite::OnPropertyChanged (DISPID)
  143. {
  144.   return ResultFromScode (E_NOTIMPL);
  145. }
  146.  
  147. HRESULT _IFUNC BOleControlSite::OnPropertyRequestEdit (DISPID)
  148. {
  149.   return ResultFromScode (E_NOTIMPL);
  150. }
  151.  
  152. HRESULT _IFUNC BOleControlSite::OnControlFocus (BOOL)
  153. {
  154.   return ResultFromScode (E_NOTIMPL);
  155. }
  156.  
  157. HRESULT _IFUNC BOleControlSite::TransformCoords (POINTL FAR* lpptlHimetric,
  158.                             TPOINTF FAR* lpptfContainer, DWORD flags)
  159. {
  160.   return ResultFromScode (E_NOTIMPL);
  161. }
  162.  
  163. //\\// IOleControl methods \\//\\
  164. HRESULT _IFUNC BOleControlSite::GetControlInfo (LPCONTROLINFO pCI)
  165. {
  166.   if (pControl)
  167.     return pControl->GetControlInfo (pCI);
  168.   else
  169.     return ResultFromScode (E_NOTIMPL);
  170. }
  171.  
  172. HRESULT _IFUNC BOleControlSite::OnMnemonic (LPMSG pMsg)
  173. {
  174.   if (pControl)
  175.     return pControl->OnMnemonic (pMsg);
  176.   else
  177.     return ResultFromScode (E_NOTIMPL);
  178. }
  179.  
  180. HRESULT _IFUNC BOleControlSite::OnAmbientPropertyChange (DISPID PropertyID)
  181. {
  182.   if (pControl)
  183.     return pControl->AmbientChanged (PropertyID);
  184.   else
  185.     return ResultFromScode (E_NOTIMPL);
  186. }
  187.  
  188. HRESULT _IFUNC BOleControlSite::FreezeEvents (BOOL bFreeze)
  189. {
  190.   if (pControl)  {
  191.         // here code to freeze events internally (no call to the user)
  192.     pEventList->FreezeAll (bFreeze);
  193.  
  194.         if (fRegConnPoint)  {
  195.         //\\// user must freeze events on his own 
  196.         //\\// registered connection point
  197.         return pControl->FreezeEvents (bFreeze); 
  198.         }
  199.     else {
  200.         return NOERROR;
  201.     }
  202.   }
  203.   else
  204.     return ResultFromScode (E_NOTIMPL);
  205. }
  206.  
  207. //**** IProvideClassInfo methods ****
  208. HRESULT _IFUNC BOleControlSite::GetClassInfo (LPTYPEINFO FAR* ppTypeInfo)
  209. {
  210.   if (pControl)
  211.     return pControl->GetClassInfo (ppTypeInfo);
  212.   else
  213.     return ResultFromScode (E_NOTIMPL);
  214. }
  215.  
  216. //**** IPersistStreamInit methods ****
  217. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  218. ////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
  219. // 
  220. // We need to duplicate IsDirty flag here since we need to acces it.
  221. // What will happen is that we have the dirty state in both BOleSite and
  222. // BOleControlSite and we will use one or the other depending if we are
  223. // using IPersistStreamInit or IPersistStorage. I don't like this but the 
  224. // only other chance is to create a specific interface to set isDirty flag
  225. // into the other side.
  226. // By the way, there is another solution, too: derive from BOleInProcServer
  227. // and forget about exe controls!!
  228. //
  229.  
  230. HRESULT _IFUNC BOleControlSite::GetClassID (LPCLSID pCId)
  231. {
  232.     if (pDataDirty)
  233.     return pDataDirty->GetClassID (pCId);
  234.   else
  235.       return ResultFromScode (E_FAIL);
  236. }
  237.  
  238. HRESULT _IFUNC BOleControlSite::IsDirty ()
  239. {
  240.     if (pDataDirty)
  241.     return pDataDirty->IsDirty ();
  242.   else
  243.       return ResultFromScode (E_FAIL);
  244. }
  245.  
  246. HRESULT _IFUNC BOleControlSite::Load (LPSTREAM pStream)
  247. {
  248.     HRESULT hr;
  249.   BOleInitInfo bi;
  250.  
  251.     // use this stream to embed
  252.   bi.Where = BOLE_STREAM; 
  253.   bi.How = BOLE_EMBED;
  254.   
  255.     // zero unused data
  256.   bi.pContainer = NULL;
  257.   bi.hIcon = NULL;
  258.   bi.pStorage = NULL;
  259.  
  260.     // load stream and pass down
  261.   bi.whereStream.pStream = pStream;
  262.   hr = pControl->Init (NULL, &bi);
  263.   pDataDirty->SetDirty (false);
  264.   
  265.   return hr;
  266. }
  267.  
  268. HRESULT _IFUNC BOleControlSite::Save (LPSTREAM pStream, BOOL fCleanIsDirty)
  269. {
  270.     HRESULT hr;
  271.   if (pControl)  {
  272.     if (SUCCEEDED (hr = pControl->Save (pStream)))
  273.         if (fCleanIsDirty)
  274.           pDataDirty->SetDirty (false);
  275.      
  276.     return hr;  
  277.   }
  278.   else
  279.     return ResultFromScode (E_NOTIMPL);
  280. }
  281.  
  282. HRESULT _IFUNC BOleControlSite::GetSizeMax (ULARGE_INTEGER FAR* maxSize)
  283. {
  284.   if (pControl)
  285.     return pControl->GetSizeMax (maxSize);
  286.   else
  287.     return ResultFromScode (E_NOTIMPL);
  288. }
  289.  
  290. HRESULT _IFUNC BOleControlSite::InitNew ()
  291. {
  292.   BOleInitInfo bi;
  293.  
  294.     // tell control to initialize any state it needs to
  295.   bi.Where = BOLE_NEW_OCX; 
  296.   
  297.     // zero unused data
  298.   bi.How = NULL;
  299.   bi.pContainer = NULL;
  300.   bi.hIcon = NULL;
  301.   bi.pStorage = NULL;
  302.  
  303.   pDataDirty->SetDirty (false);
  304.     // call init
  305.   return pControl->Init (NULL, &bi);
  306. }
  307.  
  308. //**** IBEventsHandler methods ****
  309. HRESULT _IFUNC BOleControlSite::RegisterEventsSet (REFIID iid, UINT nSize)
  310. {
  311.   if (pEventList)
  312.     return pEventList->AddEventsSet (iid, AsPIUnknown(this), nSize);
  313.   else
  314.     return ResultFromScode (E_NOTIMPL);
  315. }
  316.  
  317. HRESULT _IFUNC BOleControlSite::RegisterConnectionPoint (LPCONNECTIONPOINT pCP)
  318. {
  319.   if (pEventList)  {
  320.         fRegConnPoint = true;
  321.     return pEventList->Add (pCP);
  322.   }
  323.   else
  324.     return ResultFromScode (E_NOTIMPL);
  325. }
  326.  
  327. HRESULT _IFUNC BOleControlSite::GetSinkListForIID (REFIID iid, IBSinkList** ppSinkList)
  328. {
  329.   HRESULT hr;
  330.   LPCONNECTIONPOINT tempCP;
  331.   if (SUCCEEDED (hr = FindConnectionPoint (iid, (LPCONNECTIONPOINT FAR*)&tempCP))) { // find connectionpoint
  332.     IBEventClass* pEvClss; // ask for our implementation in order to get the list
  333.     if (SUCCEEDED(hr = tempCP->QueryInterface (IID_IBEventClass, (LPVOID FAR*)&pEvClss))) {
  334.       if (ppSinkList)
  335.         hr = pEvClss->GetSinkList (ppSinkList); // get list
  336.       else
  337.         hr = ResultFromScode (E_INVALIDARG);
  338.       pEvClss->Release(); // release event class (QueryInterface)
  339.     }
  340.     tempCP->Release(); // release connection point (FindConnectionPoint)
  341.   }
  342.  
  343.   return hr;
  344. }
  345.  
  346. //**** IConnectionPointContainer methods ****
  347. HRESULT _IFUNC BOleControlSite::EnumConnectionPoints (LPENUMCONNECTIONPOINTS FAR* ppEnum)
  348. {
  349.   // if at least one connection point is here, return the collection!
  350.   if (pEventList && (*pEventList)[0]) {
  351.     *ppEnum = (LPENUMCONNECTIONPOINTS)pEventList;
  352.     (*ppEnum)->AddRef();
  353.     return NOERROR;
  354.   }
  355.   else
  356.     return ResultFromScode (E_NOTIMPL);
  357. }
  358.  
  359. HRESULT _IFUNC BOleControlSite::FindConnectionPoint (REFIID iid, LPCONNECTIONPOINT FAR* ppCP)
  360. {
  361.   HRESULT hr = ResultFromScode (E_NOINTERFACE);
  362.   IID  TempIID;
  363.  
  364.   for (int i=0; (*pEventList)[i]; i++) {
  365.     (*pEventList)[i]->GetConnectionInterface(&TempIID); // get iid
  366.     if (TempIID == iid) {
  367.  
  368.       // according to specs if the same iid is supported more than once report an error
  369.       if (hr == NOERROR) {
  370.         *ppCP = NULL;
  371.         hr = ResultFromScode (S_FALSE);
  372.         break;
  373.       }
  374.       else { // GOT IT!
  375.         *ppCP = (*pEventList)[i];
  376.         hr = NOERROR; // it's ok but keep searching (multiple exposed iid)
  377.       }
  378.     }
  379.   } // end for
  380.  
  381.   if (hr == NOERROR)
  382.     (*ppCP)->AddRef();
  383.  
  384.   return hr;
  385. }
  386.  
  387. //************************************************************************
  388. //  class BEventList
  389. //
  390. //************************************************************************
  391. BEventList::BEventList (UINT nElemToAlloc):
  392.                         nCurrPos(0),
  393.                         nSize(nElemToAlloc),
  394.                         cRef (0)
  395. {
  396.   pConnectionPoints = (IConnectionPoint **) new char[sizeof(IConnectionPoint*)*nSize];
  397.  
  398.   if (pConnectionPoints)
  399.     memset (pConnectionPoints, 0, sizeof(IConnectionPoint *) * nSize);
  400. }
  401.  
  402. BEventList::~BEventList ()
  403. {
  404.   // release stored connection points
  405.   for (int i = 0; i < nSize && pConnectionPoints[i]; i++)
  406.     pConnectionPoints[i]->Release();
  407.  
  408.   delete [] pConnectionPoints;
  409. }
  410.  
  411. //**** IUnknown methods ****
  412. ULONG _IFUNC BEventList::AddRef ()
  413. {
  414.   return ++cRef;
  415. }
  416.  
  417. ULONG _IFUNC BEventList::Release ()
  418. {
  419.   DWORD tempRef = --cRef;
  420.  
  421.   if (!cRef)
  422.     delete this;
  423.  
  424.   return tempRef;
  425. }
  426.  
  427. HRESULT _IFUNC BEventList::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  428. {
  429.   HRESULT hr = ResultFromScode(E_NOINTERFACE);
  430.   *ppv = NULL;
  431.  
  432.   if (SUCCEEDED (hr = IEnumConnectionPoints_QueryInterface (this, iid, ppv))) {
  433.   }
  434.   return hr;
  435. }
  436.  
  437. //**** IEnumConnectionPoints methods ****
  438. HRESULT _IFUNC BEventList::Next (ULONG cConnections, LPCONNECTIONPOINT FAR* rgpcn,
  439.                         ULONG FAR* lpcFetched)
  440. {
  441.   HRESULT hr = S_OK;
  442.  
  443.   // check rgpcn (for fun);
  444.   // lpcFetched can only be NULL if one element is request (cConnections = 1)
  445.   if (rgpcn == NULL || (lpcFetched == NULL && cConnections != 1))
  446.     hr = ResultFromScode (E_INVALIDARG);
  447.   else {
  448.     int nElems;
  449.  
  450.     // copy elements
  451.     for (nElems = 0; cConnections && nElems < (nSize - nCurrPos) && 
  452.                                     pConnectionPoints[nElems]; nElems++) {
  453.       rgpcn[nElems] = pConnectionPoints[nCurrPos++];
  454.       rgpcn[nElems]->AddRef();
  455.       cConnections--;
  456.     }
  457.  
  458.     if (lpcFetched != NULL) *lpcFetched = nElems;
  459.     if (cConnections) hr = ResultFromScode (S_FALSE);
  460.   }
  461.  
  462.   return hr;
  463. }
  464.  
  465. HRESULT _IFUNC BEventList::Skip (ULONG cConnections)
  466. {
  467.   HRESULT hr = S_OK;
  468.   int nSkip;
  469.  
  470.   // find out how many elements to skip
  471.   for ( nSkip = 0; cConnections-- && nSkip < (nSize - nCurrPos) && 
  472.                                       pConnectionPoints[nSkip]; nSkip++);
  473.  
  474.   if (cConnections) hr = ResultFromScode (S_FALSE);
  475.  
  476.   nCurrPos += nSkip;  // update currPos
  477.  
  478.   return hr;
  479. }
  480.  
  481. HRESULT _IFUNC BEventList::Reset ()
  482. {
  483.   nCurrPos = 0;
  484.   return S_OK;
  485. }
  486.  
  487. HRESULT _IFUNC BEventList::Clone (LPENUMCONNECTIONPOINTS FAR* ppEnum)
  488. {
  489.   HRESULT hr = S_OK;
  490.  
  491.   // check ppEnum
  492.   if (ppEnum == NULL)  hr = ResultFromScode (E_INVALIDARG);
  493.  
  494.   *ppEnum = (LPENUMCONNECTIONPOINTS) new BEventList (this);
  495.  
  496.   // check ppEnum for out of memory
  497.   if (ppEnum == NULL)  hr = ResultFromScode (E_OUTOFMEMORY);
  498.  
  499.   (*ppEnum)->AddRef(); // user must release it
  500.  
  501.   return hr;
  502. }
  503.  
  504. HRESULT BEventList::AddEventsSet (REFIID iid, LPUNKNOWN pCPC, UINT nSize)
  505. {
  506.   HRESULT hr = NOERROR;
  507.   BEventHandler* newEventSet;
  508.   newEventSet = new BEventHandler (iid, pCPC, nSize);
  509.  
  510.   if (newEventSet) {
  511.     int nInsPos;
  512.  
  513.     for (nInsPos = 0; nInsPos < nSize && pConnectionPoints[nInsPos]; nInsPos++); // get insert position
  514.  
  515.     if (nInsPos < nSize || Expand()) {
  516.       IConnectionPoint *pCP;
  517.       newEventSet->QueryInterface (IID_IConnectionPoint, &(LPVOID)pCP);
  518.       pConnectionPoints[nInsPos] = pCP;
  519.     }
  520.     else
  521.       hr = ResultFromScode (E_OUTOFMEMORY);
  522.   }
  523.   else
  524.     hr = ResultFromScode (E_OUTOFMEMORY);
  525.  
  526.   return hr;
  527. }
  528.  
  529. HRESULT BEventList::Add (LPCONNECTIONPOINT pCP)
  530. {
  531.   HRESULT hr = NOERROR;
  532.   int nInsPos;
  533.  
  534.   for (nInsPos = 0; nInsPos < nSize && pConnectionPoints[nInsPos]; nInsPos++); // get insert position
  535.  
  536.   if (nInsPos < nSize || Expand()) {
  537.     pConnectionPoints[nInsPos] = pCP;
  538.     pCP->AddRef();
  539.   }
  540.   else
  541.     hr = ResultFromScode (E_OUTOFMEMORY);
  542.  
  543.   return hr;
  544. }
  545.  
  546. void BEventList::FreezeAll (bool fFreeze)
  547. {
  548.  
  549.   for (int nInsPos = 0; nInsPos < nSize && pConnectionPoints[nInsPos]; nInsPos++)  {
  550.       IBEventClass* eventCls;
  551.       if (SUCCEEDED (pConnectionPoints[nInsPos]->QueryInterface (IID_IBEventClass, (LPVOID FAR*)&eventCls)))  {
  552.           eventCls->FreezeEvents (fFreeze);
  553.       eventCls->Release ();
  554.       }
  555.   }
  556.  
  557.     return;
  558. }    
  559.  
  560. BEventList::BEventList (BEventList* copyList)
  561. {
  562.   // copy constructor for ::Clone method
  563.   nCurrPos = copyList->nCurrPos;
  564.   nSize = copyList->nSize;
  565.   pConnectionPoints = (IConnectionPoint **) new 
  566.                                   char[sizeof (IConnectionPoint*) * nSize];
  567.   for (int i = 0; i < nSize; i++) {
  568.     pConnectionPoints[i] = (*copyList)[i];
  569.     if (pConnectionPoints[i]) pConnectionPoints[i]->AddRef();
  570.   }
  571. }
  572.  
  573. int BEventList::Expand ()
  574. {
  575.   int newSize = nSize + nSize/2; // new dimension
  576.   // allocate
  577.   IConnectionPoint ** pNewList = (IConnectionPoint **) new char[sizeof(IConnectionPoint*)*newSize];
  578.   if (pNewList) {
  579.     // copy existing values
  580.     memcpy (pNewList, pConnectionPoints, sizeof(IConnectionPoint*)*nSize);
  581.     delete [] pConnectionPoints; // delete old array
  582.     pConnectionPoints = pNewList;
  583.     nSize = newSize;
  584.     return 1;
  585.   }
  586.   else
  587.     return 0;
  588. }
  589.  
  590.  
  591.  
  592.