Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

839 lines
20 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module objmgr.cpp. Object manager implementation | manages a
  5. * collection of OLE embedded objects
  6. *
  7. * Author: alexgo 11/5/95
  8. *
  9. * Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
  10. */
  11. #include "_common.h"
  12. #include "_objmgr.h"
  13. #include "_edit.h"
  14. #include "_disp.h"
  15. #include "_select.h"
  16. ASSERTDATA
  17. //
  18. // PUBLIC methods
  19. //
  20. /*
  21. * CObjectMgr::GetObjectCount
  22. *
  23. * @mfunc returns the number of embedded objects currently in
  24. * the document.
  25. *
  26. * @rdesc LONG, the count
  27. */
  28. LONG CObjectMgr::GetObjectCount()
  29. {
  30. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetObjectCount");
  31. return _objarray.Count();
  32. }
  33. /*
  34. * CObjectMgr::GetLinkCount()
  35. *
  36. * @mfunc returns the number of embedded objects which are links
  37. *
  38. * @rdesc LONG, the count
  39. */
  40. LONG CObjectMgr::GetLinkCount()
  41. {
  42. LONG count = 0;
  43. COleObject *pobj;
  44. LONG i;
  45. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetLinkCount");
  46. for(i = 0; i < _objarray.Count(); i++)
  47. {
  48. pobj = *_objarray.Elem(i);
  49. if(pobj && pobj->IsLink())
  50. count++;
  51. }
  52. return count;
  53. }
  54. /*
  55. * CObjectMgr::GetObjectFromCp()
  56. *
  57. * @mfunc fetches an object corresponding to the given cp
  58. *
  59. * @rdesc the object @ a cp; NULL if nothing found
  60. *
  61. * @comm the algorithm is a modified binary search. Since the
  62. * "typical" access pattern will be to linearly access the
  63. * objects, we used the cached index to guess first. If
  64. * that doesn't work, we resort to a binary search.
  65. */
  66. COleObject *CObjectMgr::GetObjectFromCp(
  67. LONG cp) //@parm the cp for the object
  68. {
  69. COleObject *pobj = NULL;
  70. LONG i = 0;
  71. // No tracing on this method as it's too noisy.
  72. if(_objarray.Count() > 0)
  73. {
  74. if(_lastindex < _objarray.Count())
  75. {
  76. pobj = *_objarray.Elem(_lastindex);
  77. if(pobj && pobj->GetCp() == cp)
  78. return pobj;
  79. }
  80. // The quick lookup failed; try a binary search.
  81. i = FindIndexForCp(cp);
  82. // Because of the insert at end case, i may be equal
  83. // to the count of objects().
  84. pobj = NULL;
  85. if(i < _objarray.Count())
  86. pobj = *_objarray.Elem(i);
  87. }
  88. // FindIndex will return a matching or _near_ index.
  89. // In this case, we only want a matching index
  90. if(pobj)
  91. {
  92. if(pobj->GetCp() != cp)
  93. pobj = NULL;
  94. else
  95. {
  96. // Set the cached index to be the next one,
  97. // so that somebody walking through objects in
  98. // cp order will always get immediate hits.
  99. _lastindex = i + 1;
  100. }
  101. }
  102. #ifdef DEBUG
  103. // Make sure the binary search found the right thing
  104. for( i = 0 ; i < _objarray.Count(); i++ )
  105. {
  106. COleObject *pobj2 = *_objarray.Elem(i);
  107. if( pobj2 )
  108. {
  109. if(*_objarray.Elem(i) == pobj)
  110. {
  111. Assert((*_objarray.Elem(i))->GetCp() == cp);
  112. }
  113. else
  114. Assert((*_objarray.Elem(i))->GetCp() != cp);
  115. }
  116. }
  117. #endif //DEBUG
  118. return pobj;
  119. }
  120. /*
  121. * CObjectMgr::CountObjects (cObjects, cp)
  122. *
  123. * @mfunc Count char counts upto <p cObjects> objects away The direction of
  124. * counting is determined by the sign of <p cObjects>.
  125. *
  126. * @rdesc Return the signed cch counted and set <p cObjects> to count of
  127. * objects actually counted. If <p cobject> <gt> 0 and cp is at
  128. * the last object, no change is made and 0 is returned.
  129. *
  130. * @devnote This is called from TOM, which uses LONGs for cp's (because VB
  131. * can't use unsigned quantities)
  132. */
  133. LONG CObjectMgr::CountObjects (
  134. LONG& cObjects, //@parm Count of objects to get cch for
  135. LONG cp) //@parm cp to start counting from
  136. {
  137. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::CountObjects");
  138. LONG iStart, iEnd;
  139. LONG iMaxEnd = (LONG)_objarray.Count() - 1;
  140. if(!cObjects || !_objarray.Count())
  141. {
  142. cObjects = 0;
  143. return 0;
  144. }
  145. iStart = (LONG)FindIndexForCp(cp);
  146. // if we are looking past either end, return 0
  147. if (iStart > iMaxEnd && cObjects > 0 ||
  148. iStart == 0 && cObjects < 0 )
  149. {
  150. cObjects = 0;
  151. return 0;
  152. }
  153. // If the index that we found is on an object and
  154. // we are looking forward, it should be skipped.
  155. if( iStart < (LONG)_objarray.Count() &&
  156. (LONG)(*_objarray.Elem(iStart))->GetCp() == cp &&
  157. cObjects > 0)
  158. {
  159. iStart++;
  160. }
  161. if(cObjects < 0)
  162. {
  163. if(-cObjects > iStart) // Going past the beginning
  164. {
  165. iEnd = 0;
  166. cObjects = -iStart;
  167. }
  168. else
  169. iEnd = iStart + cObjects;
  170. }
  171. else
  172. {
  173. if(cObjects > iMaxEnd - iStart) //Going past the end
  174. {
  175. iEnd = iMaxEnd;
  176. cObjects = iMaxEnd - iStart + 1;
  177. }
  178. else
  179. iEnd = iStart + cObjects - 1;
  180. }
  181. Assert(iEnd >= 0 && iEnd < (LONG)_objarray.Count() );
  182. return (*_objarray.Elem(iEnd))->GetCp() - cp;
  183. }
  184. /*
  185. * CObjectMgr::CountObjectsInRange (cpMin, cpMost)
  186. *
  187. * @mfunc Count the number of objects in the given range.
  188. *
  189. * @rdesc Return the number of objects.
  190. */
  191. LONG CObjectMgr::CountObjectsInRange (
  192. LONG cpMin, //@parm Beginning of range
  193. LONG cpMost) //@parm End of range
  194. {
  195. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::CountObjectsInRange");
  196. //Get the indexes for the objects at or after cpMin and cpMost
  197. //respectively.
  198. return FindIndexForCp(cpMost) - FindIndexForCp(cpMin);
  199. }
  200. /*
  201. * CObjectMgr::GetFirstObjectInRange (cpMin, cpMost)
  202. *
  203. * @mfunc Get the first object in the given range.
  204. *
  205. * @rdesc Pointer to first object in range, or NULL if none.
  206. */
  207. COleObject * CObjectMgr::GetFirstObjectInRange (
  208. LONG cpMin, //@parm Beginning of range
  209. LONG cpMost) //@parm End of range
  210. {
  211. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetFirstObjectInRange");
  212. if (cpMin == cpMost)
  213. // degenerate range no object selected
  214. return NULL;
  215. LONG iLast = (LONG)_objarray.Count() - 1; // Index for next object
  216. LONG iObj = FindIndexForCp(cpMin); // at or after cpMin
  217. //Make sure this is an existing object.
  218. if(iObj <= iLast)
  219. {
  220. //Make sure it is within the range
  221. COleObject * pObj = *_objarray.Elem(iObj);
  222. if(pObj && pObj->GetCp() <= cpMost)
  223. return pObj;
  224. }
  225. return NULL;
  226. }
  227. /*
  228. * CObjectMgr::GetObjectFromIndex(index)
  229. *
  230. * @mfunc retrieves the object at the indicated index
  231. *
  232. * @rdesc a pointer to the object, if found, NULL otherwise
  233. */
  234. COleObject *CObjectMgr::GetObjectFromIndex(
  235. LONG index) //@parm Index to use
  236. {
  237. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetObjectFromIndex");
  238. if( index < _objarray.Count() )
  239. return *_objarray.Elem(index);
  240. return NULL;
  241. }
  242. /*
  243. * CObjectMgr::InsertObject(cp, preobj, publdr)
  244. *
  245. * @mfunc inserts an object at the indicated index. It is the
  246. * caller's responsibility to handle inserting any data
  247. * (such as WCH_EMBEDDING) into the text stream.
  248. *
  249. * @rdesc HRESULT
  250. */
  251. HRESULT CObjectMgr::InsertObject(
  252. LONG cp, //@parm cp to use
  253. REOBJECT * preobj, //@parm Object to insert
  254. IUndoBuilder *publdr) //@parm Undo context
  255. {
  256. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::InsertObject");
  257. HRESULT hr;
  258. COleObject *pobj = (COleObject *)(preobj->polesite);
  259. // Let the client know what we're up to
  260. if (_precall)
  261. {
  262. hr = _precall->QueryInsertObject(&preobj->clsid, preobj->pstg,
  263. REO_CP_SELECTION);
  264. if( hr != NOERROR )
  265. return hr;
  266. }
  267. // Set some stuff up first; since we may make outgoing calls, don't
  268. // change our internal state yet.
  269. hr = pobj->InitFromREOBJECT(cp, preobj);
  270. if( hr != NOERROR )
  271. return hr;
  272. return RestoreObject(pobj);
  273. }
  274. /*
  275. * CObjectMgr::RestoreObject(pobj)
  276. *
  277. * @mfunc [re-]inserts the given object into the list of objects
  278. * in the backing store
  279. *
  280. * @rdesc HRESULT
  281. */
  282. HRESULT CObjectMgr::RestoreObject(
  283. COleObject *pobj) //@parm Object to insert
  284. {
  285. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::RestoreObject");
  286. COleObject **ppobj = _objarray.Insert(FindIndexForCp(pobj->GetCp()), 1);
  287. if( ppobj == NULL )
  288. return E_OUTOFMEMORY;
  289. *ppobj = pobj;
  290. pobj->AddRef();
  291. return NOERROR;
  292. }
  293. /*
  294. * CObjectMgr::SetRECallback(precall)
  295. *
  296. * @mfunc sets the callback interface
  297. *
  298. * @rdesc void
  299. */
  300. void CObjectMgr::SetRECallback(
  301. IRichEditOleCallback *precall) //@parm Callback interface pointer
  302. {
  303. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::SetRECallback");
  304. if( _precall )
  305. SafeReleaseAndNULL((IUnknown**)&_precall);
  306. _precall = precall;
  307. if( _precall )
  308. _precall->AddRef();
  309. }
  310. /*
  311. * CObjectMgr::SetHostNames(pszApp, pszDoc)
  312. *
  313. * @mfunc set host names for this edit instance
  314. *
  315. * @rdesc NOERROR or E_OUTOFMEMORY
  316. */
  317. HRESULT CObjectMgr::SetHostNames(
  318. LPWSTR pszApp, //@parm app name
  319. LPWSTR pszDoc) //@parm doc name
  320. {
  321. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::SetHostNames");
  322. HRESULT hr = NOERROR;
  323. if( _pszApp )
  324. {
  325. delete _pszApp;
  326. _pszApp = NULL;
  327. }
  328. if( _pszDoc )
  329. {
  330. delete _pszDoc;
  331. _pszDoc = NULL;
  332. }
  333. if( pszApp )
  334. {
  335. _pszApp = new WCHAR[wcslen(pszApp) + 1];
  336. if( _pszApp )
  337. wcscpy(_pszApp, pszApp);
  338. else
  339. hr = E_OUTOFMEMORY;
  340. }
  341. if( pszDoc )
  342. {
  343. _pszDoc = new WCHAR[wcslen(pszDoc) + 1];
  344. if( _pszDoc )
  345. wcscpy(_pszDoc, pszDoc);
  346. else
  347. hr = E_OUTOFMEMORY;
  348. }
  349. return hr;
  350. }
  351. /*
  352. * CObjectMgr::CObjectMgr
  353. *
  354. * @mfunc constructor
  355. */
  356. CObjectMgr::CObjectMgr()
  357. {
  358. _pobjselect = NULL;
  359. _pobjactive = NULL;
  360. }
  361. /*
  362. * CObjectMgr::~CObjectMgr
  363. *
  364. * @mfunc destructor
  365. */
  366. CObjectMgr::~CObjectMgr()
  367. {
  368. LONG i, count;
  369. COleObject *pobj;
  370. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::~CObjectMgr");
  371. count = _objarray.Count();
  372. for( i = 0; i < count; i++ )
  373. {
  374. pobj = *_objarray.Elem(i);
  375. // We NULL stuff here to try to protect ourselves
  376. // better in re-entrancy cases.
  377. *_objarray.Elem(i) = NULL;
  378. if( pobj )
  379. {
  380. pobj->Close(OLECLOSE_NOSAVE);
  381. pobj->MakeZombie();
  382. SafeReleaseAndNULL((IUnknown**)&pobj);
  383. }
  384. }
  385. if( _precall )
  386. SafeReleaseAndNULL((IUnknown**)&_precall);
  387. if( _pszApp )
  388. delete _pszApp;
  389. if( _pszDoc )
  390. delete _pszDoc;
  391. }
  392. /*
  393. * CObjectMgr::ReplaceRange (cp, cchDel, publdr)
  394. *
  395. * @mfunc handles the deletion of objects from a given range. This
  396. * method _must_ be called before any floating range notifications
  397. * are sent.
  398. *
  399. * @rdesc void
  400. */
  401. void CObjectMgr::ReplaceRange(
  402. LONG cp, //@parm cp starting the deletion
  403. LONG cchDel, //@parm Count of characters deleted
  404. IUndoBuilder *publdr) //@parm Undo builder for this actions
  405. {
  406. LONG i;
  407. LONG iDel = -1,
  408. cDel = 0; // index at which to delete && number of objects
  409. // to delete.
  410. COleObject *pobj;
  411. // nothing deleted, don't bother doing anything.
  412. if( !cchDel )
  413. return;
  414. // Basically, we loop through all of the objects within the
  415. // range of deleted text and ask them to delete themselves.
  416. // We remember the range of objects deleted (the starting index
  417. // and # of objects deleted) so that we can remove them from
  418. // the array all at once.
  419. i = FindIndexForCp(cp);
  420. while( i < _objarray.Count() )
  421. {
  422. pobj = *_objarray.Elem(i);
  423. if( pobj && pobj->GetCp() >= cp)
  424. {
  425. if( pobj->GetCp() < (cp + cchDel) )
  426. {
  427. if( _pobjactive == pobj )
  428. {
  429. // Deactivate the object just to be on the safe side.
  430. _pobjactive->DeActivateObj();
  431. _pobjactive = NULL;
  432. }
  433. if(iDel == -1)
  434. iDel = i;
  435. cDel++;
  436. if (_precall)
  437. {
  438. IOleObject *poo;
  439. if (pobj->GetIUnknown()->QueryInterface(IID_IOleObject,
  440. (void **)&poo) == NOERROR)
  441. {
  442. _precall->DeleteObject(poo);
  443. poo->Release();
  444. }
  445. }
  446. // if the object was selected, then it obviously
  447. // can't be anymore!
  448. if( _pobjselect == pobj )
  449. {
  450. _pobjselect = NULL;
  451. }
  452. pobj->Delete(publdr);
  453. *_objarray.Elem(i) = NULL;
  454. pobj->Release();
  455. }
  456. else
  457. break;
  458. }
  459. i++;
  460. }
  461. if(cDel)
  462. _objarray.Remove(iDel, cDel);
  463. return;
  464. }
  465. /*
  466. * CObjectMgr::ScrollObjects(dx, dy, prcScroll)
  467. *
  468. * @mfunc informs all objects that scrolling has occured so they can
  469. * update if necessary
  470. *
  471. * @rdesc void
  472. */
  473. void CObjectMgr::ScrollObjects(
  474. LONG dx, //@parm change in the x direction
  475. LONG dy, //@parm change in the y direction
  476. LPCRECT prcScroll) //@parm rect that is being scrolled
  477. {
  478. LONG count = _objarray.Count();
  479. for(LONG i = 0; i < count; i++ )
  480. {
  481. COleObject *pobj = *_objarray.Elem(i);
  482. if(pobj)
  483. pobj->ScrollObject(dx, dy, prcScroll);
  484. }
  485. }
  486. //
  487. // PRIVATE methods
  488. //
  489. /*
  490. * CObjectMgr::FindIndexForCp(cp)
  491. *
  492. * @mfunc does a binary search to find the index at which an object
  493. * at the given cp exists or should be inserted.
  494. *
  495. * @rdesc LONG, an index
  496. */
  497. LONG CObjectMgr::FindIndexForCp(
  498. LONG cp)
  499. {
  500. LONG l, r;
  501. COleObject *pobj = NULL;
  502. LONG i = 0;
  503. l = 0;
  504. r = _objarray.Count() - 1;
  505. while( r >= l )
  506. {
  507. i = (l + r)/2;
  508. pobj = *_objarray.Elem(i);
  509. if( !pobj )
  510. {
  511. TRACEWARNSZ("null entry in object table. Recovering...");
  512. for( i = 0 ; i < _objarray.Count() -1; i++ )
  513. {
  514. pobj = *_objarray.Elem(i);
  515. if( pobj && pobj->GetCp() >= cp )
  516. return i;
  517. }
  518. return i;
  519. }
  520. if( pobj->GetCp() == cp )
  521. return i;
  522. else if( pobj->GetCp() < cp )
  523. l = i + 1;
  524. else
  525. r = i - 1;
  526. }
  527. // Yikes! nothing was found. Fixup i so that
  528. // it points to the correct index for insertion.
  529. Assert(pobj || (!pobj && i == 0));
  530. if(pobj)
  531. {
  532. Assert(pobj->GetCp() != cp);
  533. if( pobj->GetCp() < cp )
  534. i++;
  535. }
  536. return i;
  537. }
  538. /*
  539. * CObjectMgr::HandleDoubleClick(ped, &pt, flags)
  540. *
  541. * @mfunc Handles a double click message, potentially activating
  542. * an object.
  543. *
  544. * @rdesc BOOL-- TRUE if double click-processing is completely
  545. * finished.
  546. */
  547. BOOL CObjectMgr::HandleDoubleClick(
  548. CTxtEdit *ped, //@parm edit context
  549. const POINT &pt,//@parm point of click (WM_LBUTTONDBLCLK wparam)
  550. DWORD flags) //@parm flags (lparam)
  551. {
  552. LONG cp;
  553. COleObject *pobj;
  554. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN,
  555. "CObjectMgr::HandleDoubleClick");
  556. ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, NULL, NULL, &cp);
  557. pobj = GetObjectFromCp(cp);
  558. if (!pobj)
  559. return FALSE;
  560. if (_pobjactive != pobj)
  561. {
  562. //Deactivate currently active object if any.
  563. if (_pobjactive)
  564. _pobjactive->DeActivateObj();
  565. return pobj->ActivateObj(WM_LBUTTONDBLCLK, flags, MAKELONG(pt.x, pt.y));
  566. }
  567. return TRUE;
  568. }
  569. /*
  570. * CObjectMgr::HandleClick(ped, &pt)
  571. *
  572. * @mfunc
  573. * The position of the caret is changing. We need to
  574. * Deactivate the active object, if any. If the change is
  575. * because of a mouse click and there is an object at this
  576. * cp, we set a new individually selected object. Otherwise
  577. * we set the individually selected object to NULL.
  578. *
  579. * @rdesc returns TRUE if this method set the selection. Otherwise,
  580. * returns FALSE;
  581. */
  582. ClickStatus CObjectMgr::HandleClick(
  583. CTxtEdit *ped, //@parm the edit context
  584. const POINT &pt)//@parm the point of the mouse click
  585. {
  586. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleClick");
  587. COleObject * pobjnew;//, * pobjold;
  588. CTxtSelection * psel;
  589. LONG cp;
  590. LONG cpMin, cpMost;
  591. if( _pobjactive )
  592. {
  593. _pobjactive->DeActivateObj();
  594. return CLICK_OBJDEACTIVATED;
  595. }
  596. ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, NULL, NULL, &cp);
  597. pobjnew = GetObjectFromCp(cp);
  598. //If we clicked on an object, set the selection to this object.
  599. //CTxtSelection::UpdateSelection will be called as a result of this
  600. //and will determine the highlighting.
  601. if( pobjnew )
  602. {
  603. cp = pobjnew->GetCp();
  604. psel = ped->GetSel();
  605. if (psel->GetRange(cpMin, cpMost) > 1 &&
  606. cpMin <= (LONG) cp &&
  607. (LONG) cp <= cpMost)
  608. {
  609. // There is more than one character in the selection
  610. // And the object is part of the selection.
  611. // Do not change the selection
  612. return CLICK_SHOULDDRAG;
  613. }
  614. // don't reset the selection if the object is already selected
  615. if( pobjnew != _pobjselect )
  616. {
  617. // Freeze the Display while we handle this click
  618. CFreezeDisplay fd(ped->_pdp);
  619. psel->SetSelection(cp, cp+1);
  620. if (GetSingleSelect())
  621. {
  622. // Note thate the call to SetSelection may have set selected object to NULL !!!!
  623. // This can happen in some strange scenarios where our state is out of whack
  624. AssertSz(GetSingleSelect() == pobjnew, "Object NOT Selected!!");
  625. return CLICK_OBJSELECTED;
  626. }
  627. return CLICK_IGNORED;
  628. }
  629. return CLICK_OBJSELECTED;
  630. }
  631. return CLICK_IGNORED;
  632. }
  633. /*
  634. * CObjectMgr::HandleSingleSelect(ped, cp, fHiLite)
  635. *
  636. * @mfunc
  637. * When an object is selected and it is the only thing selected, we do
  638. * not highlight it by inverting it. We Draw a frame and handles around
  639. * it. This function is called either because an object has been
  640. * selected and it is the only thing selected, or because we need to
  641. * check for an object that used to be in this state but may no longer be.
  642. */
  643. void CObjectMgr::HandleSingleSelect(
  644. CTxtEdit *ped, //@parm edit context
  645. LONG cp, //@parm cp of object
  646. BOOL fHiLite) //@parm is this a call for hding the selection
  647. {
  648. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleSingleSelect");
  649. COleObject* pobjnew = GetObjectFromCp(cp);
  650. //This should only be called when we know we have a singley selected
  651. //object. However, there are boundary cases (such as inserting an object)
  652. //where WCH_EMBEDDING is the backing store yet no object exists. These
  653. //cases are OK; thus, we check for NULL on pobjnew.
  654. if(pobjnew)
  655. {
  656. //The object is the same as the currently selected object (if any)
  657. //we are deselecting it. This works like a toggle unless state is messed up.
  658. //If the object is different, we are replacing the current selected
  659. //object (if any).
  660. if(!fHiLite && _pobjselect)
  661. {
  662. // This covers _pobjselct == pobjnew Normal case
  663. // and _pobjselect != pobjnew Degenerate case.
  664. _pobjselect->SetREOSELECTED(FALSE);
  665. _pobjselect = NULL;
  666. //Remove frame/handles from currently selected object.
  667. ped->_pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, cp, cp + 1);
  668. }
  669. else if(fHiLite && pobjnew != _pobjselect)
  670. {
  671. // Only do this if we are setting a new selection.
  672. _pobjselect = pobjnew;
  673. _pobjselect->SetREOSELECTED(TRUE);
  674. //Draw frame/handles on newly selected object.
  675. ped->_pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, cp, cp + 1);
  676. }
  677. else
  678. {
  679. // We want to hilite the selection but the object is already selected.
  680. // Or we want to undo hilite on the selection but the selected object is NULL.
  681. // Do nothing.
  682. }
  683. }
  684. }
  685. /*
  686. * CObjectMgr::ActivateObjectsAs (rclsid, rclsidAs)
  687. *
  688. * @mfunc Handles a request by the user to activate all objects of a particular
  689. * class as objects of another class.
  690. *
  691. * @rdesc
  692. * HRESULT Success code.
  693. */
  694. HRESULT CObjectMgr::ActivateObjectsAs(
  695. REFCLSID rclsid,
  696. REFCLSID rclsidAs)
  697. {
  698. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CObjectMgr::ActivateObjectsAs");
  699. COleObject * pobj;
  700. HRESULT hr, hrLatest;
  701. // Tell the system to treat all rclsid objects as rclsidAs
  702. hr = CoTreatAsClass(rclsid, rclsidAs);
  703. if( hr != NOERROR )
  704. return hr;
  705. LONG cobj = GetObjectCount();
  706. // Go through objects, letting them decide if
  707. // they have anything to do for this.
  708. for (LONG iobj = 0; iobj < cobj; iobj++)
  709. {
  710. pobj = GetObjectFromIndex(iobj);
  711. hrLatest = pobj->ActivateAs(rclsid, rclsidAs);
  712. // Make hr the latest hresult unless we have previously had an error.
  713. if(hr == NOERROR)
  714. hr = hrLatest;
  715. }
  716. return hr;
  717. }
  718. #ifdef DEBUG
  719. void CObjectMgr::DbgDump(void)
  720. {
  721. Tracef(TRCSEVNONE, "Object Manager %d objects", _objarray.Count());
  722. for(LONG i = 0 ; i < _objarray.Count(); i++)
  723. {
  724. COleObject *pobj = *_objarray.Elem(i);
  725. if(pobj)
  726. pobj->DbgDump(i);
  727. }
  728. }
  729. #endif