Source code of Windows XP (NT5)
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.

2981 lines
70 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module COLEOBJ.CPP OLE Object management class implemenation |
  5. *
  6. * Author: alexgo 10/24/95
  7. *
  8. * Note: Much of this code is a port from RichEdit 1.0 sources
  9. * (cleaned up a bit, ported to C++, etc.) So if there's any
  10. * bit of strangeness, it's probably there for a reason.
  11. *
  12. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  13. */
  14. #include "_common.h"
  15. #include "_edit.h"
  16. #include "_coleobj.h"
  17. #include "_objmgr.h"
  18. #include "_select.h"
  19. #include "_rtext.h"
  20. #include "_disp.h"
  21. #include "_dispprt.h"
  22. #include "_antievt.h"
  23. #include "_dxfrobj.h"
  24. ASSERTDATA
  25. //
  26. // data private to this file
  27. //
  28. static const OLECHAR szSiteFlagsStm[] = OLESTR("RichEditFlags");
  29. //
  30. // EXCEL clsid's. We have to make some special purpose hacks
  31. // for XL.
  32. const CLSID rgclsidExcel[] =
  33. {
  34. { 0x00020810L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} }, // Excel Worksheet
  35. { 0x00020811L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} }, // Excel Chart
  36. { 0x00020812L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} }, // Excel App1
  37. { 0x00020841L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} }, // Excel App2
  38. };
  39. const INT cclsidExcel = sizeof(rgclsidExcel) / sizeof(rgclsidExcel[0]);
  40. //
  41. // WordArt CLSID for more special purpose hacks.
  42. //
  43. const GUID CLSID_WordArt =
  44. { 0x000212F0L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} };
  45. const GUID CLSID_PaintbrushPicture =
  46. { 0x0003000AL, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
  47. const GUID CLSID_BitmapImage =
  48. { 0xD3E34B21L, 0x9D75, 0x101A, { 0x8C, 0x3D, 0x00, 0xAA, 0x00, 0x1A, 0x16, 0x52 } };
  49. #define dxyHandle (6) // Object frame handle size
  50. #define dxyFrameDefault (1) // Object frame width
  51. //
  52. // utility functions
  53. //
  54. /*
  55. * IsExcelCLSID (clsid)
  56. *
  57. * @func checks to see if the given clsid is one of XL's
  58. *
  59. * @rdesc TRUE/FALSE
  60. */
  61. BOOL IsExcelCLSID(
  62. REFGUID clsid)
  63. {
  64. for(LONG i = 0; i < cclsidExcel; i++)
  65. {
  66. if(IsEqualCLSID(clsid, rgclsidExcel[i]))
  67. return TRUE;
  68. }
  69. return FALSE;
  70. }
  71. //
  72. // PUBLIC methods
  73. //
  74. /*
  75. * COleObject::QueryInterface(ridd, ppv)
  76. *
  77. * @mfunc the standard OLE QueryInterface
  78. *
  79. * @rdesc NOERROR <nl>
  80. * E_NOINTERFACE
  81. */
  82. STDMETHODIMP COleObject::QueryInterface(
  83. REFIID riid, //@parm Requested interface ID
  84. void ** ppv) //@parm Out parm for result
  85. {
  86. HRESULT hr = NOERROR;
  87. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::QueryInterface");
  88. if(IsZombie())
  89. return CO_E_RELEASED;
  90. if(!ppv)
  91. return E_INVALIDARG;
  92. else
  93. *ppv = NULL;
  94. if(IsEqualIID(riid, IID_IUnknown))
  95. *ppv = (IUnknown *)(IOleClientSite *)this;
  96. else if(IsEqualIID(riid, IID_IOleClientSite))
  97. *ppv = (IOleClientSite *)this;
  98. else if(IsEqualIID(riid, IID_IOleInPlaceSite))
  99. *ppv = (IOleInPlaceSite *)this;
  100. else if(IsEqualIID(riid, IID_IAdviseSink))
  101. *ppv = (IAdviseSink *)this;
  102. else if(IsEqualIID(riid, IID_IOleWindow))
  103. *ppv = (IOleWindow *)this;
  104. else if(IsEqualIID(riid, IID_IRichEditOleCallback))
  105. {
  106. // NB!! Returning this pointer in our QI is
  107. // phenomenally bogus; it breaks fundamental COM
  108. // identity rules (granted, not many understand them!).
  109. // Anyway, RichEdit 1.0 did this, so we better.
  110. TRACEWARNSZ("Returning IRichEditOleCallback interface, COM "
  111. "identity rules broken!");
  112. *ppv = _ped->GetRECallback();
  113. }
  114. else
  115. hr = E_NOINTERFACE;
  116. if(*ppv)
  117. (*(IUnknown **)ppv)->AddRef();
  118. return hr;
  119. }
  120. /*
  121. * COleObject::AddRef()
  122. *
  123. * @mfunc Increments reference count
  124. *
  125. * @rdesc New reference count
  126. */
  127. STDMETHODIMP_(ULONG) COleObject::AddRef()
  128. {
  129. ULONG cRef;
  130. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::AddRef");
  131. cRef = SafeAddRef();
  132. return cRef;
  133. }
  134. /*
  135. * COleObject::Release ()
  136. *
  137. * @mfunc Decrements reference count
  138. *
  139. * @rdesc New reference count
  140. */
  141. STDMETHODIMP_(ULONG) COleObject::Release()
  142. {
  143. ULONG cRef;
  144. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::Release");
  145. cRef = SafeRelease();
  146. return cRef;
  147. }
  148. /*
  149. * COleObject::SaveObject ()
  150. *
  151. * @mfunc implemtenation of IOleClientSite::SaveObject
  152. *
  153. * @rdesc HRESULT
  154. */
  155. STDMETHODIMP COleObject::SaveObject()
  156. {
  157. CCallMgr callmgr(_ped);
  158. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::SaveObject");
  159. return SafeSaveObject();
  160. }
  161. /*
  162. * COleObject::SafeSaveObject ()
  163. *
  164. * @mfunc implemtenation of IOleClientSite::SaveObject for internal consumption
  165. *
  166. * @rdesc HRESULT
  167. */
  168. STDMETHODIMP COleObject::SafeSaveObject()
  169. {
  170. IPersistStorage *pps;
  171. HRESULT hr;
  172. CStabilize stabilize(this);
  173. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::SafeSaveObject");
  174. if(!_punkobj || !_pstg)
  175. {
  176. TRACEWARNSZ("SaveObject called on invalid object");
  177. return E_UNEXPECTED;
  178. }
  179. if(IsZombie())
  180. return CO_E_RELEASED;
  181. hr = _punkobj->QueryInterface(IID_IPersistStorage, (void **)&pps);
  182. TESTANDTRACEHR(hr);
  183. if(hr == NOERROR)
  184. {
  185. if(IsZombie())
  186. return CO_E_RELEASED;
  187. SavePrivateState();
  188. if(IsZombie())
  189. return CO_E_RELEASED;
  190. hr = OleSave(pps, _pstg, TRUE);
  191. if(IsZombie())
  192. return CO_E_RELEASED;
  193. TESTANDTRACEHR(hr);
  194. // note that SaveCompleted is called even if OleSave fails.
  195. // If both OleSave and SaveCompleted succeed, then go ahead
  196. // and commit the changes
  197. if(pps->SaveCompleted(NULL) == NOERROR && hr == NOERROR)
  198. {
  199. if(IsZombie())
  200. return CO_E_RELEASED;
  201. hr = _pstg->Commit(STGC_DEFAULT);
  202. TESTANDTRACEHR(hr);
  203. }
  204. pps->Release();
  205. }
  206. return hr;
  207. }
  208. /*
  209. * COleObject::GetMoniker (dwAssign, dwWhichMoniker, ppmk)
  210. *
  211. * @mfunc implementation of IOleClientSite::GetMoniker
  212. *
  213. * @rdesc E_NOTIMPL
  214. */
  215. STDMETHODIMP COleObject::GetMoniker(
  216. DWORD dwAssign, //@parm Force an assignment?
  217. DWORD dwWhichMoniker, //@parm Kind of moniker to get
  218. IMoniker ** ppmk) //@parm Out parm for result
  219. {
  220. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::GetMoniker");
  221. TRACEWARNSZ("method not implemented!");
  222. if(ppmk)
  223. *ppmk = NULL;
  224. return E_NOTIMPL;
  225. }
  226. /*
  227. * COleObject::GetContainer(ppcont)
  228. *
  229. * @mfunc implementation of IOleClientSite::GetContainer
  230. *
  231. * @rdesc E_NOINTERFACE
  232. */
  233. STDMETHODIMP COleObject::GetContainer(
  234. IOleContainer **ppcont) //@parm Out parm for result
  235. {
  236. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::GetContainer");
  237. TRACEWARNSZ("method not implemented!");
  238. if(ppcont)
  239. *ppcont = NULL;
  240. // richedit 1.0 returns E_NOINTERFACE instead of E_NOTIMPL. Do
  241. // the same.
  242. return E_NOINTERFACE;
  243. }
  244. /*
  245. * COleObject::ShowObject()
  246. *
  247. * @mfunc Implementation of IOleClientSite::ShowObject.
  248. *
  249. * @rdesc E_NOTIMPL
  250. */
  251. STDMETHODIMP COleObject::ShowObject()
  252. {
  253. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::ShowObject");
  254. TRACEWARNSZ("method not implemented!");
  255. return E_NOTIMPL;
  256. }
  257. /*
  258. * COleObject::OnShowWindow (fShow)
  259. *
  260. * @mfunc
  261. * implementation of IOleClientSite::OnShowWindow -- notifies
  262. * the client site that the object is or is not being shown in its
  263. * own application window. This governs whether or not hatching
  264. * should appear around the object in richedit.
  265. *
  266. * @rdesc HRESULT
  267. */
  268. STDMETHODIMP COleObject::OnShowWindow(
  269. BOOL fShow) //@parm If TRUE, object is being drawn in its own window
  270. {
  271. DWORD dwFlags = _pi.dwFlags;
  272. CCallMgr callmgr(_ped);
  273. CStabilize stabilize(this);
  274. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnShowWindow");
  275. if(IsZombie())
  276. return CO_E_RELEASED;
  277. _pi.dwFlags &= ~REO_OPEN;
  278. if(fShow)
  279. _pi.dwFlags |= REO_OPEN;
  280. // If something changed, redraw object
  281. if(dwFlags != _pi.dwFlags)
  282. {
  283. // Invalidate rect that we're in.
  284. _ped->TxInvalidateRect(&_rcPos, FALSE);
  285. // We're not allowed to call invalidate rect by itself without
  286. // terminating it with a call to update window.However, we don't
  287. // care at this point if things are redrawn right away.
  288. _ped->TxUpdateWindow();
  289. // COMPATIBILITY ISSUE: (alexgo) the RE1.0 code did some funny
  290. // stuff with undo here. I don't believe it's necessary to
  291. // repeat that code with our multi-level undo model,
  292. }
  293. return NOERROR;
  294. }
  295. /*
  296. * COleObject::RequestNewObjectLayout ()
  297. *
  298. * @mfunc Implementation of IOleClientSite::RequestNewObjectLayout
  299. *
  300. * @rdesc E_NOTIMPL
  301. */
  302. STDMETHODIMP COleObject::RequestNewObjectLayout()
  303. {
  304. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN,
  305. "COleObject::RequestNewObjectLayout");
  306. TRACEWARNSZ("method not implemented!");
  307. return E_NOTIMPL;
  308. }
  309. /*
  310. * COleObject::GetWindow(phwnd)
  311. *
  312. * @mfunc Implementation of IOleInPlaceSite::GetWindow
  313. *
  314. * @rdesc HRESULT
  315. */
  316. STDMETHODIMP COleObject::GetWindow(
  317. HWND *phwnd) //@parm Where to put window
  318. {
  319. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::GetWindow");
  320. // NB! this method is not stabilized.
  321. if(IsZombie())
  322. return CO_E_RELEASED;
  323. if(phwnd)
  324. return _ped->TxGetWindow(phwnd);
  325. return E_INVALIDARG;
  326. }
  327. /*
  328. * COleObject::ContextSensitiveHelp(fEnterMode)
  329. *
  330. * @mfunc Implemenation of IOleInPlaceSite::ContextSensitiveHelp
  331. *
  332. * @rdesc HRESULT
  333. */
  334. STDMETHODIMP COleObject::ContextSensitiveHelp(
  335. BOOL fEnterMode) //@parm, If TRUE, then we're in help mode
  336. {
  337. IRichEditOleCallback *precall;
  338. CCallMgr callmgr(_ped);
  339. CStabilize stabilize(this);
  340. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN,
  341. "COleObject::ContextSensitiveHelp");
  342. if(IsZombie())
  343. return CO_E_RELEASED;
  344. // If the mode changes
  345. if(_ped->GetObjectMgr()->GetHelpMode() != fEnterMode)
  346. {
  347. _ped->GetObjectMgr()->SetHelpMode(fEnterMode);
  348. precall = _ped->GetRECallback();
  349. if(precall)
  350. return precall->ContextSensitiveHelp(fEnterMode);
  351. }
  352. return NOERROR;
  353. }
  354. /*
  355. * COleObject::CanInPlaceActivate()
  356. *
  357. * @mfunc implementation of IOleInPlaceSite::CanInPlaceActivate
  358. *
  359. * @rdesc NOERROR or S_FALSE
  360. */
  361. STDMETHODIMP COleObject::CanInPlaceActivate()
  362. {
  363. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN,
  364. "COleObject::CanInPlaceActivate");
  365. if(IsZombie())
  366. return CO_E_RELEASED;
  367. // If we have a callback && the object is willing to show
  368. // content, then we can in-place activate
  369. if(_ped->GetRECallback() && _pi.dvaspect == DVASPECT_CONTENT)
  370. return NOERROR;
  371. return S_FALSE;
  372. }
  373. /*
  374. * COleObject::OnInPlaceActivate()
  375. *
  376. * @mfunc implementation of IOleInPlaceSite::OnInPlaceActivate
  377. *
  378. * @rdesc noerror
  379. */
  380. STDMETHODIMP COleObject::OnInPlaceActivate()
  381. {
  382. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnInPlaceActivate");
  383. // assume that in-place objects can never be blank.
  384. _pi.dwFlags &= ~REO_BLANK;
  385. _fInPlaceActive = TRUE;
  386. return NOERROR;
  387. }
  388. /*
  389. * COleObject::OnUIActivate ()
  390. *
  391. * @mfunc implementation of IOleInPlaceSite::OnUIActivate. Notifies
  392. * the container that the object is about to be activated in
  393. * place with UI elements suchs as merged menus
  394. *
  395. * @rdesc HRESULT
  396. */
  397. STDMETHODIMP COleObject::OnUIActivate()
  398. {
  399. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnUIActivate");
  400. CCallMgr callmgr(_ped);
  401. CStabilize stabilize(this);
  402. if(IsZombie())
  403. return CO_E_RELEASED;
  404. CObjectMgr * pobjmgr = _ped->GetObjectMgr();
  405. IRichEditOleCallback *precall = pobjmgr->GetRECallback();
  406. if(precall)
  407. {
  408. // Force this object to be selected, if it isn't already
  409. // Update the selection before making the outgoing call
  410. if(!(_pi.dwFlags & REO_SELECTED))
  411. {
  412. CTxtSelection *psel = _ped->GetSel();
  413. if(psel)
  414. psel->SetSelection(_cp, _cp + 1);
  415. }
  416. precall->ShowContainerUI(FALSE);
  417. if(IsZombie())
  418. return CO_E_RELEASED;
  419. // This is an optimization for activating multiple
  420. pobjmgr->SetShowUIPending(FALSE);
  421. // RAID 7212
  422. // We don't want to set the in place active object if we are already in the process of activating the pbject.
  423. // Otherwise, there will be bad interactions with the code in TxDraw for out of process servers.
  424. // Note : it may be possible to always set this in ActivateObj but I left this here for those cases wher
  425. // OnUIActivate may be called directly.
  426. if (!_fActivateCalled)
  427. {
  428. Assert(!pobjmgr->GetInPlaceActiveObject());
  429. pobjmgr->SetInPlaceActiveObject(this);
  430. _pi.dwFlags |= REO_INPLACEACTIVE;
  431. }
  432. return NOERROR;
  433. }
  434. return E_UNEXPECTED;
  435. }
  436. /*
  437. * COleObject::GetWindowContext(ppipframe, ppipuidoc, prcPos, prcClip, pipfinfo)
  438. *
  439. * @mfunc Implementation of IOleInPlaceSite::GetWindowContext.
  440. * Enables the in-place object to retrieve the window
  441. * interfaces that form the window object hierarchy.
  442. *
  443. * @rdesc HRESULT
  444. */
  445. STDMETHODIMP COleObject::GetWindowContext(
  446. IOleInPlaceFrame **ppipframe, //@parm Where to put in-place frame
  447. IOleInPlaceUIWindow **ppipuidoc,//@parm Where to put ui window
  448. LPRECT prcPos, //@parm Position rect
  449. LPRECT prcClip, //@parm Clipping rect
  450. LPOLEINPLACEFRAMEINFO pipfinfo) //@parm Accelerator information
  451. {
  452. CCallMgr callmgr(_ped);
  453. CStabilize stabilize(this);
  454. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::GetWindowContext");
  455. if(IsZombie())
  456. return CO_E_RELEASED;
  457. // Let container verify other parameters; we don't use them
  458. if(!prcPos || !prcClip)
  459. return E_INVALIDARG;
  460. IRichEditOleCallback *precall = _ped->GetRECallback();
  461. if(precall)
  462. {
  463. // Recall that there are two rects here in client coordiantes:
  464. // the rect for this object (_rcPos) and the rect for
  465. // our main display;
  466. *prcPos = _rcPos;
  467. // FUTURE (alexgo); we may need to get this from the
  468. // display instead to handle the inactive state if we ever
  469. // want to support embedded objects with the inactive state.
  470. _ped->TxGetClientRect(prcClip);
  471. return precall->GetInPlaceContext(ppipframe, ppipuidoc, pipfinfo);
  472. }
  473. return E_UNEXPECTED;
  474. }
  475. /*
  476. * COleObject::Scroll(sizeScroll)
  477. *
  478. * @mfunc implementation of IOleInPlaceSite::Scroll
  479. *
  480. * @rdesc E_NOTIMPL;
  481. */
  482. STDMETHODIMP COleObject::Scroll(
  483. SIZE sizeScroll) //@parm Amount to scroll
  484. {
  485. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::Scroll");
  486. TRACEWARNSZ("method not implemented!");
  487. return E_NOTIMPL;
  488. }
  489. /*
  490. * COleObject::OnUIDeactivate (fUndoable)
  491. *
  492. * @mfunc implementation of IOleInPlaceSite::OnUIDeactivate. Notifies
  493. * the container that it should re-install its user interface
  494. *
  495. * @rdesc HRESULT
  496. */
  497. STDMETHODIMP COleObject::OnUIDeactivate(
  498. BOOL fUndoable) //@parm Whether you can undo anything here
  499. {
  500. CCallMgr callmgr(_ped);
  501. CStabilize stabilize(this);
  502. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnUIDeactivate");
  503. if(IsZombie())
  504. return CO_E_RELEASED;
  505. CObjectMgr *pobjmgr = _ped->GetObjectMgr();
  506. IRichEditOleCallback *precall = _ped->GetRECallback();
  507. if(_fIsPaintBrush)
  508. {
  509. // Hack for RAID 3293. Bitmap object disappears after editing.
  510. // Apparently paint only triggers OnUIDeactivate and not OnInPlaceDeactivate
  511. // assume that in-place objects can never be blank.
  512. _fInPlaceActive = FALSE;
  513. // Reset REO_INPLACEACTIVE
  514. _pi.dwFlags &= ~REO_INPLACEACTIVE;
  515. }
  516. if(!precall)
  517. return E_UNEXPECTED;
  518. if(_ped->TxIsDoubleClickPending())
  519. _ped->GetObjectMgr()->SetShowUIPending(TRUE);
  520. else
  521. {
  522. // Ignore any errors; the old code did.
  523. precall->ShowContainerUI(TRUE);
  524. if(IsZombie())
  525. return CO_E_RELEASED;
  526. }
  527. pobjmgr->SetInPlaceActiveObject(NULL);
  528. if (!_fDeactivateCalled)
  529. {
  530. // We got here without DeActiveObj. Since to shutdown correctly
  531. // we need to call this, we do so here.
  532. DeActivateObj();
  533. }
  534. // Get focus back
  535. _ped->TxSetFocus();
  536. #ifdef DEBUG
  537. // the OLE undo model is not very compatible with multi-level undo.
  538. // For simplicity, just ignore stuff.
  539. if(fUndoable)
  540. {
  541. TRACEWARNSZ("Ignoring a request to keep undo from an OLE object");
  542. }
  543. #endif
  544. // Some objects draw outside the
  545. // areas they are supposed to. So we need to
  546. // just invalidate everything and redraw.
  547. _ped->TxInvalidateRect(NULL, TRUE);
  548. return NOERROR;
  549. }
  550. /*
  551. * COleObject::OnInPlaceDeactivate ()
  552. *
  553. * @mfunc implementation of IOleInPlaceSite::OnInPlaceDeactivate
  554. *
  555. * @rdesc NOERROR
  556. */
  557. STDMETHODIMP COleObject::OnInPlaceDeactivate()
  558. {
  559. CCallMgr callmgr(_ped);
  560. CStabilize stabilize(this);
  561. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN,
  562. "COleObject::OnInPlaceDeactivate");
  563. _fInPlaceActive = FALSE;
  564. //Reset REO_INPLACEACTIVE
  565. _pi.dwFlags &= ~REO_INPLACEACTIVE;
  566. if(!_punkobj)
  567. return E_UNEXPECTED;
  568. if(IsZombie())
  569. return CO_E_RELEASED;
  570. // Apparently, WordArt 2.0 had some sizing problems. The original
  571. // code has this call to GetExtent-->SetExtent, so I've kept it here.
  572. if(_fIsWordArt2)
  573. {
  574. // Ignore errors. If anything fails, too bad.
  575. FetchObjectExtents(); // this will reset _sizel
  576. SetExtent(SE_NOTACTIVATING);
  577. }
  578. // Some objects draw outside the
  579. // areas they are supposed to. So we need to
  580. // just invalidate everything and redraw.
  581. // Note that we do this in UIDeactivate as well; however, the
  582. // double invalidation is necessary to cover some re-entrancy
  583. // cases where we might be painted before everything is ready.
  584. _ped->TxInvalidateRect(NULL, TRUE);
  585. return NOERROR;
  586. }
  587. /*
  588. * COleObject::DiscardUndoState ()
  589. *
  590. * @mfunc implementation of IOleInPlaceSite::DiscardUndoState.
  591. *
  592. * @rdesc NOERROR
  593. */
  594. STDMETHODIMP COleObject::DiscardUndoState()
  595. {
  596. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN,
  597. "COleObject::DiscardUndoState");
  598. // Nothing to do here; we don't keep any OLE-undo state as it's
  599. // not very compatible with multi-level undo.
  600. return NOERROR;
  601. }
  602. /*
  603. * COleObject::DeactivateAndUndo ()
  604. *
  605. * @mfunc implementation of IOleInPlaceSite::DeactivateAndUndo--
  606. * called by an active object when the user invokes undo
  607. * in the active object
  608. *
  609. * @rdesc NOERROR (yep, richedit1.0 ignored all the errors here)
  610. */
  611. STDMETHODIMP COleObject::DeactivateAndUndo()
  612. {
  613. CStabilize stabilize(this);
  614. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::DeactivateAndUndo");
  615. if(IsZombie())
  616. return CO_E_RELEASED;
  617. // Ignore error
  618. _ped->InPlaceDeactivate();
  619. // COMPATIBILITY ISSUE: we don't bother doing any undo here, as
  620. // a multi-level undo model is incompatible with OLE undo.
  621. return NOERROR;
  622. }
  623. /*
  624. * COleObject::OnPosRectChange (prcPos)
  625. *
  626. * @mfunc implementation of IOleInPlaceSite::OnPosRectChange. This
  627. * method is called by an in-place object when its extents have
  628. * changed
  629. *
  630. * @rdesc HRESULT
  631. */
  632. STDMETHODIMP COleObject::OnPosRectChange(
  633. LPCRECT prcPos)
  634. {
  635. IOleInPlaceObject *pipo;
  636. RECT rcClip;
  637. RECT rcNewPos;
  638. CCallMgr callmgr(_ped);
  639. CStabilize stabilize(this);
  640. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnPosRectChange");
  641. if(!prcPos)
  642. return E_INVALIDARG;
  643. if(!_punkobj)
  644. return E_UNEXPECTED;
  645. if(IsZombie())
  646. return CO_E_RELEASED;
  647. if(!_ped->fInplaceActive())
  648. return E_UNEXPECTED;
  649. // Check to see if the rect moved; we don't allow this, but
  650. // do allow the object to keep the new size
  651. rcNewPos = *prcPos;
  652. if(prcPos->left != _rcPos.left || prcPos->top != _rcPos.top)
  653. {
  654. rcNewPos.right = rcNewPos.left + (prcPos->right - prcPos->left);
  655. rcNewPos.bottom = rcNewPos.top + (prcPos->bottom - prcPos->top);
  656. }
  657. _ped->TxGetClientRect(&rcClip);
  658. HRESULT hr = _punkobj->QueryInterface(IID_IOleInPlaceObject, (void **)&pipo);
  659. if(hr == NOERROR)
  660. {
  661. hr = pipo->SetObjectRects(&rcNewPos, &rcClip);
  662. pipo->Release();
  663. // bug fix 6073
  664. // Need to set viewchange flag so we resize the ole object properly on ITextServices::TxDraw
  665. CObjectMgr * pobjmgr = _ped->GetObjectMgr();
  666. if (pobjmgr && pobjmgr->GetInPlaceActiveObject() == this)
  667. _fViewChange = TRUE;
  668. }
  669. return hr;
  670. }
  671. /*
  672. * COleObject::OnDataChange (pformatetc, pmedium)
  673. *
  674. * @mfunc implementation of IAdviseSink::OnDataChange
  675. *
  676. * @rdesc NOERROR
  677. */
  678. STDMETHODIMP_(void) COleObject::OnDataChange(
  679. FORMATETC *pformatetc, //@parm Format of data that changed
  680. STGMEDIUM *pmedium) //@parm Data that changed
  681. {
  682. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnDataChange");
  683. CCallMgr callmgr(_ped);
  684. if(IsZombie())
  685. return;
  686. _pi.dwFlags &= ~REO_BLANK;
  687. // this will also set the modified flag
  688. _ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
  689. return;
  690. }
  691. /*
  692. * COleObject::OnViewChange(dwAspect, lindex)
  693. *
  694. * @mfunc implementation of IAdviseSink::OnViewChange. Notifies
  695. * us that the object's view has changed.
  696. *
  697. * @rdesc HRESULT
  698. */
  699. STDMETHODIMP_(void) COleObject::OnViewChange(
  700. DWORD dwAspect, //@parm Aspect that has changed
  701. LONG lindex) //@parm unused
  702. {
  703. CStabilize stabilize(this);
  704. CCallMgr callmgr(_ped);
  705. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnViewChange");
  706. if(!_punkobj)
  707. return; // E_UNEXPECTED
  708. if(IsZombie())
  709. return;
  710. if (_fInUndo) // This object has been deleted, forget view change
  711. return;
  712. _pi.dwFlags &= ~REO_BLANK;
  713. // Richedit 1.0 ignored errors on getting object extents
  714. FetchObjectExtents();
  715. // bug fix 6073
  716. // Need to set viewchange flag so we resize the ole object properly on ITextServices::TxDraw
  717. CObjectMgr * pobjmgr = _ped->GetObjectMgr();
  718. if (pobjmgr && pobjmgr->GetInPlaceActiveObject() == this)
  719. _fViewChange = TRUE;
  720. CDisplay *pdp = _ped->_pdp;
  721. if(pdp)
  722. pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, _cp, _cp + 1);
  723. _ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
  724. return;
  725. }
  726. /*
  727. * COleObject::OnRename (pmk)
  728. *
  729. * @mfunc implementation of IAdviseSink::OnRename. Notifies the container
  730. * that the object has been renamed
  731. *
  732. * @rdesc E_NOTIMPL
  733. */
  734. STDMETHODIMP_(void) COleObject::OnRename(
  735. IMoniker *pmk) //@parm Object's new name
  736. {
  737. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnRename");
  738. TRACEWARNSZ("IAdviseSink::OnRename not implemented!");
  739. return; // E_NOTIMPL;
  740. }
  741. /*
  742. * COleObject::OnSave ()
  743. *
  744. * @mfunc implementation of IAdviseSink::OnSave. Notifies the container
  745. * that an object has been saved
  746. *
  747. * @rdesc NOERROR
  748. */
  749. STDMETHODIMP_(void) COleObject::OnSave()
  750. {
  751. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnSave");
  752. _pi.dwFlags &= ~REO_BLANK;
  753. }
  754. /*
  755. * COleObject::OnClose ()
  756. *
  757. * @mfunc implementation of IAdviseSink::OnClose. Notifies the container
  758. * that an object has been closed.
  759. *
  760. * @rdesc NOERROR
  761. */
  762. STDMETHODIMP_(void) COleObject::OnClose()
  763. {
  764. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::OnClose");
  765. if(IsZombie())
  766. return;
  767. // If the object is blank (i.e. no data in it), we don't want to leave
  768. // it in the backing store--there is nothing for us to draw && therefore
  769. // nothing for the user to click on! So just delete the object with
  770. // a space. Note that 1.0 actually deleted the object; we'll just
  771. // replace it with a space to make everything work out right.
  772. if(_pi.dwFlags & REO_BLANK)
  773. {
  774. CCallMgr callmgr(_ped);
  775. CStabilize stabilize(this);
  776. CRchTxtPtr rtp(_ped, _cp);
  777. // We don't want the delete of this object to go on the undo
  778. // stack. We use a space so that cp's will work out right for
  779. // other undo actions.
  780. rtp.ReplaceRange(1, 1, L" ", NULL, -1);
  781. }
  782. _ped->TxSetForegroundWindow();
  783. }
  784. /*
  785. * COleObject::OnPreReplaceRange
  786. *
  787. * @mfunc implementation of ITxNotify::OnPreReplaceRange
  788. * called before changes are made to the backing store
  789. */
  790. void COleObject::OnPreReplaceRange(
  791. LONG cp, //@parm cp of the changes
  792. LONG cchDel, //@parm #of chars deleted
  793. LONG cchNew, //@parm # of chars added
  794. LONG cpFormatMin, //@parm min cp of formatting changes
  795. LONG cpFormatMax) //@parm max cp of formatting changes
  796. {
  797. Assert(_fInUndo == FALSE);
  798. }
  799. /*
  800. * COleObject::OnPostReplaceRange
  801. *
  802. * @mfunc implementation of ITxNotify::OnPostReplaceRange
  803. * called after changes are made to the backing store
  804. *
  805. * @comm we use this method to keep our cp's up-to-date
  806. */
  807. void COleObject::OnPostReplaceRange(
  808. LONG cp, //@parm cp of the changes
  809. LONG cchDel, //@parm #of chars deleted
  810. LONG cchNew, //@parm # of chars added
  811. LONG cpFormatMin, //@parm min cp of formatting changes
  812. LONG cpFormatMax) //@parm max cp of formatting changes
  813. {
  814. // The only case we need to worry about is when changes
  815. // come before our object
  816. Assert(_fInUndo == FALSE);
  817. _fDraw = TRUE;
  818. if(cp <= _cp)
  819. {
  820. if(cp + cchDel > _cp)
  821. {
  822. _fDraw = FALSE;
  823. return;
  824. }
  825. _cp += (cchNew - cchDel);
  826. }
  827. }
  828. /*
  829. * COleObject::Zombie ()
  830. *
  831. * @mfunc
  832. * Turn this object into a zombie
  833. *
  834. */
  835. void COleObject::Zombie ()
  836. {
  837. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::Zombie");
  838. _ped = NULL;
  839. }
  840. /*
  841. * COleObject::COleObject(ped)
  842. *
  843. * @mfunc constructor
  844. */
  845. COleObject::COleObject(
  846. CTxtEdit *ped) //@parm context for this object
  847. {
  848. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::COleObject");
  849. AddRef();
  850. // Most values will be NULL by virtue of the allocator
  851. _ped = ped;
  852. CNotifyMgr *pnm = ped->GetNotifyMgr();
  853. if(pnm)
  854. pnm->Add((ITxNotify *)this);
  855. }
  856. /*
  857. * COleObject::GetObjectData(preobj, dwFlags)
  858. *
  859. * @mfunc fills out an REOBJECT structure with information relevant
  860. * to this object
  861. *
  862. * @rdesc HRESULT
  863. */
  864. HRESULT COleObject::GetObjectData(
  865. REOBJECT *preobj, //@parm Struct to fill out
  866. DWORD dwFlags) //@parm Indicate what data is requested
  867. {
  868. IOleObject *poo = NULL;
  869. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::GetObjectData");
  870. Assert(preobj);
  871. Assert(_punkobj);
  872. preobj->cp = _cp;
  873. if(_punkobj->QueryInterface(IID_IOleObject, (void **)&poo) == NOERROR)
  874. {
  875. // Don't worry about failures here
  876. poo->GetUserClassID(&(preobj->clsid));
  877. }
  878. preobj->dwFlags = _pi.dwFlags;
  879. preobj->dvaspect = _pi.dvaspect;
  880. preobj->dwUser = _pi.dwUser;
  881. preobj->sizel = _sizel;
  882. if(dwFlags & REO_GETOBJ_POLEOBJ)
  883. {
  884. preobj->poleobj = poo;
  885. if(poo)
  886. poo->AddRef();
  887. }
  888. else
  889. preobj->poleobj = NULL;
  890. if(poo)
  891. poo->Release();
  892. if(IsZombie())
  893. return CO_E_RELEASED;
  894. if(dwFlags & REO_GETOBJ_PSTG)
  895. {
  896. preobj->pstg = _pstg;
  897. if(_pstg)
  898. _pstg->AddRef();
  899. }
  900. else
  901. preobj->pstg = NULL;
  902. if(dwFlags & REO_GETOBJ_POLESITE)
  903. {
  904. // COMPATIBILITY HACK!! Note that we don't 'release' any pointer that
  905. // may already be in the stored in the site. RichEdit1.0 always sets
  906. // the value, consequently several apps pass in garbage for the site.
  907. //
  908. // If the site was previously set, we will get a reference counting
  909. // bug, so be sure that doesn't happen!
  910. preobj->polesite = (IOleClientSite *)this;
  911. AddRef();
  912. }
  913. else
  914. preobj->polesite = NULL;
  915. return NOERROR;
  916. }
  917. /*
  918. * COleObject::IsLink()
  919. *
  920. * @mfunc returns TRUE if the object is a link
  921. *
  922. * @rdesc BOOL
  923. */
  924. BOOL COleObject::IsLink()
  925. {
  926. return !!(_pi.dwFlags & REO_LINK);
  927. }
  928. /*
  929. * COleObject::InitFromREOBJECT(cp, preobj)
  930. *
  931. * @mfunc initializes this object's state from the given
  932. * REOBJECT data structure
  933. *
  934. * @rdesc HRESULT
  935. */
  936. HRESULT COleObject::InitFromREOBJECT(
  937. LONG cp, //@parm cp for the object
  938. REOBJECT *preobj) //@parm Data to use for initialization
  939. {
  940. IOleLink *plink;
  941. HRESULT hr = E_INVALIDARG;
  942. CRchTxtPtr rtp(_ped, 0);
  943. POINT pt;
  944. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::InitFromREOBJECT");
  945. Assert(_punkobj == NULL);
  946. if(IsZombie())
  947. return CO_E_RELEASED;
  948. _cp = cp;
  949. if(preobj->poleobj)
  950. hr = preobj->poleobj->QueryInterface(IID_IUnknown, (void **)&_punkobj);
  951. else
  952. {
  953. _punkobj = (IOleClientSite *) this;
  954. AddRef();
  955. hr = NOERROR;
  956. }
  957. if(hr != NOERROR)
  958. return hr;
  959. _pstg = preobj->pstg;
  960. if(_pstg)
  961. _pstg->AddRef();
  962. _pi.dwFlags = preobj->dwFlags & REO_READWRITEMASK;
  963. _pi.dwUser = preobj->dwUser;
  964. _pi.dvaspect = preobj->dvaspect;
  965. _sizel = preobj->sizel; // COMPATIBILITY ISSUE: the RE 1.0 code had
  966. // some stuff to deal with REO_DYNAMICSIZE
  967. // here. We do not currently support that.
  968. if(_punkobj->QueryInterface(IID_IOleLink, (void **)&plink) == NOERROR)
  969. {
  970. _pi.dwFlags |= REO_LINK | REO_LINKAVAILABLE;
  971. plink->Release();
  972. }
  973. if(IsZombie())
  974. return CO_E_RELEASED;
  975. if (IsEqualCLSID(preobj->clsid, CLSID_StaticMetafile) ||
  976. IsEqualCLSID(preobj->clsid, CLSID_StaticDib) ||
  977. IsEqualCLSID(preobj->clsid, CLSID_Picture_EnhMetafile))
  978. {
  979. _pi.dwFlags |= REO_STATIC;
  980. }
  981. else if(IsExcelCLSID(preobj->clsid))
  982. _pi.dwFlags |= REO_GETMETAFILE;
  983. else if(IsEqualCLSID(preobj->clsid, CLSID_WordArt))
  984. _fIsWordArt2 = TRUE;
  985. else if(IsEqualCLSID(preobj->clsid, CLSID_PaintbrushPicture) ||
  986. IsEqualCLSID(preobj->clsid, CLSID_BitmapImage))
  987. {
  988. _fIsPaintBrush = TRUE;
  989. // These calls will initialize the flag, _fPBUseLocalSizel, which
  990. // indicates that for this PB object, SetExtent calls are not
  991. // acknowledged by the object, and we are to use our local value
  992. // of _sizel as the object extents.
  993. FetchObjectExtents();
  994. SetExtent(SE_NOTACTIVATING);
  995. }
  996. hr = ConnectObject();
  997. if(IsZombie())
  998. return CO_E_RELEASED;
  999. // This is a bit non-intuitive, but we need to figure out
  1000. // where the object would be so that it can inplace activate correctly.
  1001. if(cp)
  1002. cp--;
  1003. rtp.SetCp(cp);
  1004. pt.x = pt.y = 0;
  1005. if (!_ped->_pdp->IsFrozen())
  1006. _ped->_pdp->PointFromTp(rtp, NULL, FALSE, pt, NULL, TA_TOP);
  1007. _rcPos.top = _rcPos.bottom = pt.y; //bottom will be set below in
  1008. // FetchExtents
  1009. _rcPos.left = _rcPos.right = pt.x;
  1010. if(preobj->sizel.cx || preobj->sizel.cy)
  1011. _sizel = preobj->sizel;
  1012. else
  1013. FetchObjectExtents();
  1014. if (!_ped->_pdp->IsFrozen())
  1015. ResetPosRect();
  1016. if(IsZombie())
  1017. return CO_E_RELEASED;
  1018. // We don't do the following anymore although it was originally spec'd as the correct
  1019. // behavior for applications in OLE 2.01. The reason is that no one else seems to and
  1020. // it seems to result in some odd behavior.
  1021. #if 0
  1022. // Finally, lock down Link objects so they we don't try to refetch their
  1023. // extents from the server. After initialization, link object size is
  1024. // entirely determined by the container.
  1025. if(_pi.dwFlags & REO_LINK)
  1026. {
  1027. // so we don't call GetExtents on remeasuring.
  1028. _fSetExtent = TRUE;
  1029. }
  1030. #endif
  1031. return NOERROR;
  1032. }
  1033. /*
  1034. * COleObject::MeasureObj(dypInch, dxpInch, xWidth, yHeight, yDescent)
  1035. *
  1036. * Review: (keithcu) Should yDescentFont be descent of font
  1037. * or descent of entire line? LS does one thing, old measurer
  1038. * does another. I'm hoping that this feature is only used on
  1039. * lines with one font..
  1040. * @mfunc calculates the size of this object in device units
  1041. */
  1042. void COleObject::MeasureObj(
  1043. long dypInch, //@parm resolution of device
  1044. long dxpInch,
  1045. LONG & xWidth, //@parm Object width
  1046. LONG & yAscent, //@parm Object ascent
  1047. LONG & yDescent, //@parm Object descent
  1048. SHORT yDescentFont) //@parm object's font descent
  1049. {
  1050. xWidth = W32->HimetricXtoDX(_sizel.cx, dxpInch);
  1051. LONG yHeight = W32->HimetricYtoDY(_sizel.cy, dypInch);
  1052. if (_pi.dwFlags & REO_BELOWBASELINE)
  1053. {
  1054. yDescent = yDescentFont;
  1055. yAscent = max(0, yHeight - yDescent);
  1056. }
  1057. else //The normal case
  1058. {
  1059. yAscent = yHeight;
  1060. yDescent = 0;
  1061. }
  1062. }
  1063. /*
  1064. * COleObject::InHandle(x, y, &pt)
  1065. *
  1066. * @mfunc See if a point is in the rectangle defined by the handle at
  1067. * the given coordinates.
  1068. *
  1069. * @rdesc True if point is in handle.
  1070. */
  1071. BOOL COleObject::InHandle(
  1072. int x, //@parm Upper left corner x coordinate of handle box
  1073. int y, //@parm Upper left corner y coordinate of handle box
  1074. const POINT &pt)//@parm Point to check
  1075. {
  1076. RECT rc;
  1077. rc.left = x;
  1078. rc.top = y;
  1079. // Add one to bottom right because PtInRect does not consider
  1080. // points on bottom or right to be in rect.
  1081. rc.right = x + dxyHandle + 1;
  1082. rc.bottom = y + dxyHandle + 1;
  1083. return PtInRect(&rc, pt);
  1084. }
  1085. /*
  1086. * COleObject::CheckForHandleHit(&pt)
  1087. *
  1088. * @mfunc Check for a hit on any of the frame handles.
  1089. *
  1090. * @rdesc NULL if no hit, cursor resource ID if there is a hit.
  1091. */
  1092. LPTSTR COleObject::CheckForHandleHit(
  1093. const POINT &pt) //@parm POINT containing client coord. of the cursor.
  1094. {
  1095. RECT rc;
  1096. // If object is not resizeable, no chance of hitting a resize handle!
  1097. if(!(_pi.dwFlags & REO_RESIZABLE))
  1098. return NULL;
  1099. CopyRect(&rc, &_rcPos);
  1100. if(!_dxyFrame)
  1101. _dxyFrame = dxyFrameDefault;
  1102. // Check to see if point is farther into the interior of the
  1103. // object than the handles extent. If it is we can just bail.
  1104. InflateRect(&rc, -(_dxyFrame + dxyHandle), -(_dxyFrame + dxyHandle));
  1105. if(PtInRect(&rc, pt))
  1106. return NULL;
  1107. // Check to see if point is in any of the handles and
  1108. // return the proper cursor ID if it is.
  1109. InflateRect(&rc, dxyHandle, dxyHandle);
  1110. if(InHandle(rc.left, rc.top, pt) ||
  1111. InHandle(rc.right-dxyHandle, rc.bottom-dxyHandle, pt))
  1112. {
  1113. return IDC_SIZENWSE;
  1114. }
  1115. if(InHandle(rc.left, rc.top+(rc.bottom-rc.top-dxyHandle)/2, pt) ||
  1116. InHandle(rc.right-dxyHandle,
  1117. rc.top+(rc.bottom-rc.top-dxyHandle)/2, pt))
  1118. {
  1119. return IDC_SIZEWE;
  1120. }
  1121. if(InHandle(rc.left, rc.bottom-dxyHandle, pt) ||
  1122. InHandle(rc.right-dxyHandle, rc.top, pt))
  1123. {
  1124. return IDC_SIZENESW;
  1125. }
  1126. if(InHandle(rc.left+(rc.right-rc.left-dxyHandle)/2, rc.top, pt) ||
  1127. InHandle(rc.left+(rc.right-rc.left-dxyHandle)/2,
  1128. rc.bottom-dxyHandle, pt))
  1129. {
  1130. return IDC_SIZENS;
  1131. }
  1132. return NULL;
  1133. }
  1134. /*
  1135. * COleObject::DrawHandle(hdc, x, y)
  1136. *
  1137. * @mfunc Draw a handle on the object frame at the specified coordinate
  1138. */
  1139. void COleObject::DrawHandle(
  1140. HDC hdc, //@parm HDC to be drawn into
  1141. int x, //@parm x coordinate of upper-left corner of handle box
  1142. int y) //@parm y coordinate of upper-left corner of handle box
  1143. {
  1144. RECT rc;
  1145. // Draw handle by inverting
  1146. rc.left = x;
  1147. rc.top = y;
  1148. rc.right = x + dxyHandle;
  1149. rc.bottom = y + dxyHandle;
  1150. InvertRect(hdc, (LPRECT)&rc);
  1151. }
  1152. /*
  1153. * COleObject::DrawFrame(pdp, hdc, prc)
  1154. *
  1155. * @mfunc Draw a frame around the object. Invert if required and
  1156. * include handles if required.
  1157. */
  1158. void COleObject::DrawFrame(
  1159. const CDisplay *pdp, //@parm the display to draw to
  1160. HDC hdc, //@parm the device context
  1161. RECT *prc) //@parm the rect around which to draw
  1162. {
  1163. if(_pi.dwFlags & REO_OWNERDRAWSELECT)
  1164. return;
  1165. RECT rc;
  1166. CopyRect(&rc, prc);
  1167. if(_pi.dwFlags & REO_INVERTEDSELECT)
  1168. InvertRect(hdc, &rc); //Invert entire object
  1169. else
  1170. {
  1171. // Just the border, so use a null brush
  1172. SaveDC(hdc);
  1173. SetROP2(hdc, R2_NOT);
  1174. SelectObject(hdc, GetStockObject(NULL_BRUSH));
  1175. Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
  1176. RestoreDC(hdc, -1);
  1177. }
  1178. if(_pi.dwFlags & REO_RESIZABLE)
  1179. {
  1180. int bkmodeOld;
  1181. HPEN hpen;
  1182. LOGPEN logpen;
  1183. bkmodeOld = SetBkMode(hdc, TRANSPARENT);
  1184. // Get frame width
  1185. _dxyFrame = dxyFrameDefault;
  1186. hpen = (HPEN)GetCurrentObject(hdc, OBJ_PEN);
  1187. if(W32->GetObject(hpen, sizeof(LOGPEN), &logpen))
  1188. {
  1189. if(logpen.lopnWidth.x)
  1190. _dxyFrame = (SHORT)logpen.lopnWidth.x;
  1191. }
  1192. // Draw handles inside rectangle boundary
  1193. InflateRect(&rc, -_dxyFrame, -_dxyFrame);
  1194. LONG x = rc.left;
  1195. DrawHandle(hdc, x, rc.top);
  1196. DrawHandle(hdc, x, rc.top + (rc.bottom - rc.top - dxyHandle)/2);
  1197. DrawHandle(hdc, x, rc.bottom - dxyHandle);
  1198. x = rc.left + (rc.right - rc.left - dxyHandle)/2;
  1199. DrawHandle(hdc, x, rc.top);
  1200. DrawHandle(hdc, x, rc.bottom - dxyHandle);
  1201. x = rc.right - dxyHandle;
  1202. DrawHandle(hdc, x, rc.top);
  1203. DrawHandle(hdc, x, rc.top + (rc.bottom - rc.top - dxyHandle)/2);
  1204. DrawHandle(hdc, x, rc.bottom - dxyHandle);
  1205. SetBkMode(hdc, bkmodeOld);
  1206. }
  1207. }
  1208. /*
  1209. * COleObject::CreateDib (hdc)
  1210. *
  1211. * @mfunc Create DIB for Windows CE display
  1212. */
  1213. void COleObject::CreateDib(
  1214. HDC hdc)
  1215. {
  1216. int nCol = 0;
  1217. BYTE *pbDib;
  1218. HGLOBAL hnew = NULL;
  1219. BYTE *pbSrcBits;
  1220. LPBITMAPINFO pbmi = (LPBITMAPINFO) GlobalLock(_hdata);
  1221. DWORD dwPixelsPerRow = 0;
  1222. DWORD dwPixels = 0;
  1223. if(pbmi->bmiHeader.biBitCount <= 8)
  1224. {
  1225. nCol = 1 << pbmi->bmiHeader.biBitCount;
  1226. // Calculate the number of pixels. Account for DWORD alignment
  1227. DWORD dwPixelsPerByte = 8 / pbmi->bmiHeader.biBitCount;
  1228. DWORD dwBitsPerRow = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biBitCount;
  1229. dwBitsPerRow = (dwBitsPerRow + 7) & ~7; // Round up to byte boundary
  1230. DWORD dwBytesPerRow = dwBitsPerRow / 8;
  1231. dwBytesPerRow = (dwBytesPerRow + 3) & ~3; // Round up to DWORD
  1232. dwPixelsPerRow = dwBytesPerRow * dwPixelsPerByte;
  1233. // Double check with original
  1234. #ifdef DEBUG
  1235. DWORD dwBlockSize = GlobalSize(_hdata);
  1236. DWORD dwBitMapBytes = dwBlockSize - sizeof(BITMAPINFOHEADER) - (nCol * sizeof(RGBQUAD));
  1237. DWORD dwBitMapPixels = dwBitMapBytes * dwPixelsPerByte;
  1238. dwPixels = dwPixelsPerRow * pbmi->bmiHeader.biHeight;
  1239. Assert(dwPixels == dwBitMapPixels);
  1240. #endif
  1241. }
  1242. else
  1243. dwPixelsPerRow = pbmi->bmiHeader.biWidth;
  1244. dwPixels = dwPixelsPerRow * pbmi->bmiHeader.biHeight;
  1245. pbSrcBits = (BYTE*)(pbmi) + sizeof(BITMAPINFOHEADER) + (nCol * sizeof(RGBQUAD));
  1246. #ifdef TARGET_NT
  1247. // For NT viewing convert four color bitmaps to 16 color bitmap
  1248. if(nCol == 4)
  1249. {
  1250. // First let's figure out how big the new memory block needs to be.
  1251. DWORD cb = sizeof(BITMAPINFOHEADER) + (16 * sizeof(RGBQUAD));
  1252. cb += dwPixels / 2;
  1253. hnew = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, cb);
  1254. // Now locate the interesting places
  1255. LPBITMAPINFO pNewBmi = (LPBITMAPINFO) GlobalLock(hnew);
  1256. BYTE *pNewBits = (BYTE*)(pNewBmi) + sizeof(BITMAPINFOHEADER) + (16 * sizeof(RGBQUAD));
  1257. // Modify the header
  1258. pNewBmi->bmiHeader = pbmi->bmiHeader;
  1259. pNewBmi->bmiHeader.biBitCount = 4;
  1260. pNewBmi->bmiHeader.biClrUsed = 4;
  1261. // Set up the DIB RGB Colors.
  1262. for (int i = 0; i < 16; i++)
  1263. {
  1264. BYTE data = 0;
  1265. switch (i % 4)
  1266. {
  1267. case 0:
  1268. break;
  1269. case 1:
  1270. data = 0x55;
  1271. break;
  1272. case 2:
  1273. data = 0xAA;
  1274. break;
  1275. case 3:
  1276. data = 0xFF;
  1277. break;
  1278. }
  1279. pNewBmi->bmiColors[i].rgbBlue = data;
  1280. pNewBmi->bmiColors[i].rgbGreen = data;
  1281. pNewBmi->bmiColors[i].rgbRed = data;
  1282. pNewBmi->bmiColors[i].rgbReserved = 0;
  1283. }
  1284. // Convert the byte array.
  1285. for (DWORD j = 0; j < dwPixels; j++)
  1286. {
  1287. int iSrcByte = j / 4;
  1288. BYTE bits = pbSrcBits[iSrcByte];
  1289. bits >>= 6 - (j%4) * 2;
  1290. bits &= 0x3;
  1291. int iDstByte = j / 2;
  1292. bits <<= 4 - (j%2) * 4;
  1293. pNewBits[iDstByte] |= bits;
  1294. }
  1295. GlobalUnlock(pbmi);
  1296. pbmi = pNewBmi;
  1297. pbSrcBits = pNewBits;
  1298. }
  1299. #endif
  1300. _hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&pbDib, NULL, 0);
  1301. if(_hdib == NULL)
  1302. {
  1303. _ped->GetCallMgr()->SetOutOfMemory();
  1304. // V-GUYB:
  1305. // Do not attempt to repaint this picture until the user starts typing in the
  1306. // control. This allows the user to dismiss the oom that will appear and then
  1307. // save the document, and then free up some space. If we don't do this here,
  1308. // every time the oom msg is dismissed it will appear again. This doesn't allow
  1309. // the user to save the document unless they can find some memory to free.
  1310. _fDraw = FALSE;
  1311. TRACEWARNSZ("Out of memory creating DIB");
  1312. return;
  1313. }
  1314. DWORD nBytes;
  1315. if(nCol)
  1316. {
  1317. DWORD nPixelsPerByte = 8 / pbmi->bmiHeader.biBitCount;
  1318. nBytes = dwPixels / nPixelsPerByte;
  1319. }
  1320. else
  1321. nBytes = dwPixels * 4; // Each pixel occupies 4 bytes in DIB
  1322. CopyMemory(pbDib, pbSrcBits, nBytes);
  1323. GlobalUnlock(pbmi);
  1324. GlobalFree(hnew);
  1325. }
  1326. /*
  1327. * COleObject::DrawDib (hdc, prc)
  1328. *
  1329. * @mfunc Auxiliary function that draws the dib in the given dc
  1330. */
  1331. void COleObject::DrawDib(
  1332. HDC hdc,
  1333. RECT *prc)
  1334. {
  1335. if(!_hdib)
  1336. CreateDib(hdc);
  1337. // If _hdib is still NULL, just return. Maybe out of memory.
  1338. if(!_hdib)
  1339. return;
  1340. HDC hdcMem = CreateCompatibleDC(hdc);
  1341. LPBITMAPINFO pbmi = (LPBITMAPINFO) LocalLock(_hdata);
  1342. SelectObject(hdcMem, _hdib);
  1343. StretchBlt(hdc, prc->left, prc->top,
  1344. prc->right - prc->left, prc->bottom - prc->top,
  1345. hdcMem, 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, SRCCOPY);
  1346. GlobalUnlock(pbmi);
  1347. DeleteDC(hdcMem);
  1348. }
  1349. /*
  1350. * COleObject::DrawObj (pdp, hdc, fMetafile, ppt, prcRender)
  1351. *
  1352. * @mfunc draws the object
  1353. */
  1354. void COleObject::DrawObj(
  1355. const CDisplay *pdp, //@parm Display object for the view
  1356. LONG dypInch, //@parm Resolution of device
  1357. LONG dxpInch,
  1358. HDC hdc, //@parm Drawing HDC (can differ from display's)
  1359. BOOL fMetafile, //@parm Whether the HDC is a metafile
  1360. POINT * ppt, //@parm Top left corner of where to draw
  1361. RECT * prcRender, //@parm Pointer to render rectangle
  1362. LONG yBaselineLine,
  1363. LONG yDescentMaxCur)
  1364. {
  1365. LONG adjust = 0;
  1366. BOOL fMultipleSelect = FALSE;
  1367. CObjectMgr * pobjmgr = _ped->GetObjectMgr();
  1368. IViewObject * pvo;
  1369. CDisplayPrinter *pdpPrint;
  1370. RECT rc, rc1;
  1371. LONG cpMin, cpMost;
  1372. _ped->GetSelRangeForRender(&cpMin, &cpMost);
  1373. BOOL fSelected = _cp >= cpMin && _cp < cpMost;
  1374. SaveDC(hdc);
  1375. if (fSelected)
  1376. SetBkMode(hdc, OPAQUE);
  1377. if(pdp->IsMain() && !(_pi.dwFlags & REO_OWNERDRAWSELECT))
  1378. {
  1379. if(fSelected)
  1380. {
  1381. if(cpMost - cpMin > 1)
  1382. fMultipleSelect = TRUE;
  1383. // The following overwrites the selection colors currently
  1384. // selected into the hdc. We do this for RE 2.0 compatibility,
  1385. // e.g., else selected name links in Outlook appear yellow
  1386. // after the InvertRect() in DrawFrame() (altho the semicolon
  1387. // blanks appear in selection colors). Note: we could define
  1388. // REO_OWNERDRAWSELECT, which would bypass the following 2 lines
  1389. // and suppress the InvertRect below and in DrawFrame(). Then
  1390. // Outlook's From:, To:, and CC: would have correct selection
  1391. // colors throughout.
  1392. ::SetTextColor(hdc, _ped->TxGetForeColor());
  1393. ::SetBkColor (hdc, _ped->TxGetBackColor());
  1394. }
  1395. }
  1396. if(_fInPlaceActive || !_fDraw)
  1397. {
  1398. // If we're inplace active, don't do anything; the server is
  1399. // drawing for us. We also don't do anything prior to the fDraw
  1400. // property being set
  1401. return;
  1402. }
  1403. //REVIEW (keithcu) Do we need this?
  1404. //Worse case, update only if pdp->IsMain(). This whole thing is ugly.
  1405. if (pdp->IsMain())
  1406. ResetPosRect(&adjust); // Update position rectangle
  1407. // Draw object where we are asked within rendering rectangle
  1408. rc.left = ppt->x;
  1409. rc.right = rc.left + W32->HimetricXtoDX(_sizel.cx, dxpInch);
  1410. rc.bottom = ppt->y + yBaselineLine;
  1411. rc.top = rc.bottom - W32->HimetricYtoDY(_sizel.cy, dypInch);
  1412. if (_pi.dwFlags & REO_BELOWBASELINE)
  1413. OffsetRect(&rc, 0, yDescentMaxCur);
  1414. SetTextAlign(hdc, TA_TOP);
  1415. SaveDC(hdc); // calls to OLE object (IViewObject::Draw or OleDraw) might change HDC
  1416. //Do clipping because OLE doesn't know where to draw
  1417. IntersectClipRect(hdc, prcRender->left, prcRender->top,
  1418. prcRender->right, prcRender->bottom);
  1419. if(_hdata)
  1420. {
  1421. // This is some Windows CE Dib, let's try the direct approach
  1422. DrawDib(hdc, &rc);
  1423. }
  1424. else if(fMetafile)
  1425. {
  1426. if(_punkobj->QueryInterface(IID_IViewObject, (void **)&pvo)
  1427. == NOERROR)
  1428. {
  1429. pdpPrint = (CDisplayPrinter *)pdp;
  1430. rc1 = pdpPrint->GetPrintPage();
  1431. // Fix up rc for Draw()
  1432. rc1.bottom = rc1.bottom - rc1.top;
  1433. rc1.right = rc1.right - rc1.left;
  1434. pvo->Draw(_pi.dvaspect, -1, NULL, NULL, 0, hdc, (RECTL *)&rc,
  1435. (RECTL *)&rc1, NULL, 0);
  1436. pvo->Release();
  1437. }
  1438. }
  1439. else
  1440. OleDraw(_punkobj, _pi.dvaspect, hdc, &rc);
  1441. RestoreDC(hdc, -1);
  1442. // Do selection stuff if this is for the main (screen) view.
  1443. if(pdp->IsMain())
  1444. {
  1445. if(_pi.dwFlags & REO_OPEN)
  1446. OleUIDrawShading(&rc, hdc);
  1447. // If the object has been selected by clicking on it, draw
  1448. // a frame and handles around it. Otherwise, if we are selected
  1449. // as part of a range, invert ourselves.
  1450. if(!fMetafile && pobjmgr->GetSingleSelect() == this)
  1451. DrawFrame(pdp, hdc, &rc);
  1452. else if(fMultipleSelect)
  1453. InvertRect(hdc, &rc);
  1454. }
  1455. RestoreDC(hdc, -1);
  1456. }
  1457. /*
  1458. * COleObject::Delete (publdr)
  1459. *
  1460. * @mfunc deletes this object from the backing store _without_
  1461. * making outgoing calls. The commit on generated anti-events
  1462. * will handle the outgoing calls
  1463. */
  1464. void COleObject::Delete(
  1465. IUndoBuilder *publdr)
  1466. {
  1467. Assert(_fInUndo == FALSE);
  1468. _fInUndo = TRUE;
  1469. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  1470. if(pnm)
  1471. pnm->Remove((ITxNotify *)this);
  1472. if(publdr)
  1473. {
  1474. // The anti-event will take care of calling IOO::Close for us
  1475. IAntiEvent *pae = gAEDispenser.CreateReplaceObjectAE(_ped, this);
  1476. if(pae)
  1477. publdr->AddAntiEvent(pae);
  1478. }
  1479. else
  1480. {
  1481. Close(OLECLOSE_NOSAVE);
  1482. MakeZombie();
  1483. }
  1484. // If we're being deleted, we can't be selected anymore
  1485. _pi.dwFlags &= ~REO_SELECTED;
  1486. _fDraw = 0;
  1487. }
  1488. /*
  1489. * COleObject::Restore()
  1490. *
  1491. * @mfunc restores the object from the undo state back into the
  1492. * backing store
  1493. *
  1494. * No outgoing calls will be made
  1495. */
  1496. void COleObject::Restore()
  1497. {
  1498. Assert(_fInUndo);
  1499. _fInUndo = FALSE;
  1500. _fDraw = TRUE;
  1501. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  1502. if(pnm)
  1503. pnm->Add((ITxNotify *)this);
  1504. }
  1505. /*
  1506. * COleObject::SetREOSELECTED (fSelect)
  1507. *
  1508. * @mfunc cmember set REO_SELECTED state
  1509. */
  1510. void COleObject::SetREOSELECTED(
  1511. BOOL fSelect)
  1512. {
  1513. _pi.dwFlags &= ~REO_SELECTED;
  1514. if(fSelect)
  1515. _pi.dwFlags |= REO_SELECTED;
  1516. }
  1517. /*
  1518. * COleObject::Close(dwSave)
  1519. *
  1520. * @mfunc closes this object
  1521. */
  1522. void COleObject::Close(
  1523. DWORD dwSave) //same as IOleObject::Close
  1524. {
  1525. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::Close");
  1526. if(!_punkobj)
  1527. return;
  1528. IOleObject *poo;
  1529. if(_punkobj->QueryInterface(IID_IOleObject, (void **)&poo) == NOERROR)
  1530. {
  1531. poo->Close(dwSave);
  1532. poo->Release();
  1533. }
  1534. }
  1535. /*
  1536. * COleObject::ScrollObject(dx, dy, prcScroll)
  1537. *
  1538. * @mfunc updates _rcPos if we were scrolled
  1539. */
  1540. void COleObject::ScrollObject(
  1541. LONG dx, //@parm Change in the x direction
  1542. LONG dy, //@parm Change in the y direction
  1543. LPCRECT prcScroll) //@parm Rect that is being scrolled
  1544. {
  1545. RECT rcInter;
  1546. // If we're inplace active, OnReposition will handle the scrolling
  1547. if(!_fInPlaceActive && !_fGuardPosRect &&
  1548. IntersectRect(&rcInter, &_rcPos, prcScroll))
  1549. {
  1550. OffsetRect(&_rcPos, dx, dy);
  1551. }
  1552. }
  1553. //
  1554. // PRIVATE methods
  1555. //
  1556. /*
  1557. * COleObject::~COleObject()
  1558. *
  1559. * @mfunc destructor
  1560. */
  1561. COleObject::~COleObject()
  1562. {
  1563. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::~COleObject");
  1564. CleanupState();
  1565. }
  1566. /*
  1567. * COleObject::SavePrivateState()
  1568. *
  1569. * @mfunc Saves information such as the aspect and various flags
  1570. * into the object's storage.
  1571. *
  1572. * @devnote This method is used mostly for compatibility with
  1573. * richedit 1.0--we save the same information they did.
  1574. *
  1575. * Also note that this method returns void--even if any particular
  1576. * call failes, we should be able to "recover" and limp along.
  1577. * Richedit 1.0 also had this behavior.
  1578. */
  1579. void COleObject::SavePrivateState()
  1580. {
  1581. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::SavePrivateState");
  1582. Assert(_pstg);
  1583. IStream * pstm;
  1584. HRESULT hr = _pstg->CreateStream(szSiteFlagsStm, STGM_READWRITE |
  1585. STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm);
  1586. if(IsZombie())
  1587. return;
  1588. if(hr == NOERROR)
  1589. {
  1590. pstm->Write(&_pi, sizeof(PersistedInfo), NULL);
  1591. pstm->Release();
  1592. }
  1593. }
  1594. /*
  1595. * COleObject::FetchObjectExtents()
  1596. *
  1597. * @mfunc determines the object's size in himetric. Typically, this
  1598. * is achieved via IOleObject::GetExtent, but some error
  1599. * recovery is implemented
  1600. *
  1601. * @rdesc void. _sizel is updated
  1602. */
  1603. void COleObject::FetchObjectExtents()
  1604. {
  1605. HRESULT hr = NOERROR;
  1606. IOleObject *poo;
  1607. IViewObject2 *pvo;
  1608. CDisplay *pdp;
  1609. if(IsZombie())
  1610. return;
  1611. // We _don't_ want to make calls to GetExtent if:
  1612. // (1) We have outstanding updates to _sizel for which we
  1613. // haven't successfully called SetExtent
  1614. // (2) This is a PaintBrush object and the most recent call
  1615. // to SetExtent for this PB object failed
  1616. if(_fAspectChanged || !(_fSetExtent || (_fIsPaintBrush && _fPBUseLocalSizel)))
  1617. {
  1618. // try IOleObject::GetExtent as long as we shouldn't try for
  1619. // the metafile first.
  1620. // If this flag was set, it has done its job so turn it off.
  1621. _fAspectChanged = FALSE;
  1622. if(!(_pi.dwFlags & REO_GETMETAFILE))
  1623. {
  1624. hr = _punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  1625. if(hr == NOERROR)
  1626. {
  1627. hr = poo->GetExtent(_pi.dvaspect, &_sizel);
  1628. poo->Release();
  1629. }
  1630. if(IsZombie())
  1631. return;
  1632. }
  1633. else
  1634. hr = E_FAIL;
  1635. if(hr != NOERROR)
  1636. {
  1637. if(_punkobj->QueryInterface(IID_IViewObject2, (void **)&pvo) == NOERROR)
  1638. {
  1639. hr = pvo->GetExtent(_pi.dvaspect, -1, NULL, &_sizel);
  1640. pvo->Release();
  1641. }
  1642. }
  1643. if(IsZombie())
  1644. return;
  1645. if(hr != NOERROR || _sizel.cx == 0 || _sizel.cy == 0)
  1646. _sizel.cx = _sizel.cy = 2000;
  1647. }
  1648. // If _fSetExtent==TRUE, we've made a change to _sizel for which
  1649. // we haven't called IOleObject::SetExtent successfully. Therefore
  1650. // fall through with existing _sizel.
  1651. // Update our position rectangle
  1652. pdp = _ped->_pdp;
  1653. _rcPos.right = _rcPos.left + pdp->HimetricXtoDX(_sizel.cx);
  1654. _rcPos.bottom = _rcPos.top + pdp->HimetricYtoDY(_sizel.cy);
  1655. }
  1656. /*
  1657. * COleObject::ConnectObject()
  1658. *
  1659. * @mfunc setup the necessary advises to the embedded object.
  1660. *
  1661. * @rdesc HRESULT
  1662. *
  1663. * @comm This code is similar to ole2ui's OleStdSetupAdvises
  1664. */
  1665. HRESULT COleObject::ConnectObject()
  1666. {
  1667. IViewObject *pvo;
  1668. IOleObject *poo;
  1669. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::ConnectObject");
  1670. if(IsZombie())
  1671. return CO_E_RELEASED;
  1672. Assert(_punkobj);
  1673. if(_punkobj->QueryInterface(IID_IViewObject, (void **)&pvo) == NOERROR)
  1674. {
  1675. pvo->SetAdvise(_pi.dvaspect, ADVF_PRIMEFIRST, (IAdviseSink *)this);
  1676. pvo->Release();
  1677. }
  1678. if(IsZombie())
  1679. return CO_E_RELEASED;
  1680. HRESULT hr = _punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  1681. if(hr == NOERROR)
  1682. {
  1683. hr = poo->Advise((IAdviseSink *)this, &_dwConn);
  1684. CObjectMgr *pobjmgr = _ped->GetObjectMgr();
  1685. Assert(pobjmgr);
  1686. // The doc may be NULL, but not the app. Don't do anything
  1687. // if the app name is NULL
  1688. if(pobjmgr->GetAppName())
  1689. {
  1690. hr = poo->SetHostNames(pobjmgr->GetAppName(),
  1691. pobjmgr->GetDocName());
  1692. }
  1693. poo->Release();
  1694. }
  1695. if(IsZombie())
  1696. return CO_E_RELEASED;
  1697. OleSetContainedObject(_punkobj, TRUE);
  1698. return hr;
  1699. }
  1700. /*
  1701. * COleObject::DisconnectObject
  1702. *
  1703. * @mfunc reverses the connections made in ConnectObject and releases
  1704. * the object. Note that the object's storage is _NOT_
  1705. * released.
  1706. */
  1707. void COleObject::DisconnectObject()
  1708. {
  1709. IOleObject * poo = NULL;
  1710. IViewObject *pvo = NULL;
  1711. if(IsZombie())
  1712. return; // Already Disconnected.
  1713. if(_punkobj->QueryInterface(IID_IOleObject, (void **)&poo) == NOERROR)
  1714. {
  1715. poo->SetClientSite(NULL);
  1716. if(_dwConn)
  1717. poo->Unadvise(_dwConn);
  1718. poo->Release();
  1719. }
  1720. if(_punkobj->QueryInterface(IID_IViewObject, (void **)&pvo) == NOERROR)
  1721. {
  1722. pvo->SetAdvise(_pi.dvaspect, ADVF_PRIMEFIRST, NULL);
  1723. pvo->Release();
  1724. }
  1725. CoDisconnectObject(_punkobj, NULL);
  1726. SafeReleaseAndNULL(&_punkobj);
  1727. }
  1728. /*
  1729. * COleObject::MakeZombie()
  1730. *
  1731. * @mfunc Force this object to enter a zombie state. This
  1732. * is called when we should be gone but aren't. It cleans
  1733. * up our state and flags us so we don't do nasty things
  1734. * between now and the time were are deleted.
  1735. *
  1736. */
  1737. void COleObject::MakeZombie()
  1738. {
  1739. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::MakeZombie");
  1740. CleanupState();
  1741. Zombie();
  1742. }
  1743. /*
  1744. * COleObject::CleanupState()
  1745. *
  1746. * @mfunc Called on delete and when we become zombied. It cleans
  1747. * up our member data and any other dependencies that need to
  1748. * be resolved.
  1749. */
  1750. void COleObject::CleanupState()
  1751. {
  1752. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::CleanupState");
  1753. if(_ped && !_fInUndo)
  1754. {
  1755. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  1756. if(pnm)
  1757. pnm->Remove((ITxNotify *)this);
  1758. _ped = NULL;
  1759. }
  1760. DisconnectObject();
  1761. if(_pstg)
  1762. SafeReleaseAndNULL((IUnknown**)&_pstg);
  1763. if(_hdib)
  1764. {
  1765. ::DeleteObject(_hdib);
  1766. _hdib = NULL;
  1767. }
  1768. GlobalFree(_hdata);
  1769. _hdata = NULL;
  1770. if(_pimageinfo)
  1771. {
  1772. delete _pimageinfo;
  1773. _pimageinfo = NULL;
  1774. }
  1775. }
  1776. /*
  1777. * COleObject::ActivateObj (uiMsg, wParam, lParam)
  1778. *
  1779. * @mfunc Activates the object.
  1780. *
  1781. * @rdesc
  1782. * BOOL Whether object has been activated.
  1783. */
  1784. BOOL COleObject::ActivateObj(
  1785. UINT uiMsg,
  1786. WPARAM wParam,
  1787. LPARAM lParam)
  1788. {
  1789. LPOLEOBJECT poo;
  1790. HWND hwnd;
  1791. MSG msg;
  1792. DWORD dwPos;
  1793. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::AcitvateObj");
  1794. if(_ped->TxGetWindow(&hwnd) != NOERROR)
  1795. return FALSE;
  1796. ResetPosRect();
  1797. // Fill in message structure
  1798. msg.hwnd = hwnd;
  1799. msg.message = uiMsg;
  1800. msg.wParam = wParam;
  1801. msg.lParam = lParam;
  1802. msg.time = GetMessageTime();
  1803. dwPos = GetMessagePos();
  1804. msg.pt.x = (LONG) LOWORD(dwPos);
  1805. msg.pt.y = (LONG) HIWORD(dwPos);
  1806. // Force this object to be selected, if it isn't already
  1807. // Update the selection before making the outgoing call
  1808. if(!(_pi.dwFlags & REO_SELECTED))
  1809. {
  1810. CTxtSelection *psel = _ped->GetSel();
  1811. if(psel)
  1812. psel->SetSelection(_cp, _cp + 1);
  1813. }
  1814. // Execute the primary verb
  1815. if(_punkobj->QueryInterface(IID_IOleObject, (void **)&poo) == NOERROR)
  1816. {
  1817. _fActivateCalled = TRUE;
  1818. // Make sure we tell the object its size has changed if we haven't
  1819. // already notified it.
  1820. if(_fSetExtent)
  1821. SetExtent(SE_ACTIVATING);
  1822. HRESULT hr;
  1823. hr = poo->DoVerb(OLEIVERB_PRIMARY, &msg, (LPOLECLIENTSITE)this, 0, hwnd, &_rcPos);
  1824. #ifndef MACPORT
  1825. if(FAILED(hr))
  1826. {
  1827. ENOLEOPFAILED enoleopfailed;
  1828. enoleopfailed.iob = _ped->_pobjmgr->FindIndexForCp(GetCp());
  1829. enoleopfailed.lOper = OLEOP_DOVERB;
  1830. enoleopfailed.hr = hr;
  1831. _ped->TxNotify(EN_OLEOPFAILED, &enoleopfailed);
  1832. }
  1833. #endif
  1834. poo->Release();
  1835. if(_fInPlaceActive && !(_pi.dwFlags & REO_INPLACEACTIVE))
  1836. {
  1837. CObjectMgr *pobjmgr = _ped->GetObjectMgr();
  1838. Assert(!pobjmgr->GetInPlaceActiveObject());
  1839. pobjmgr->SetInPlaceActiveObject(this);
  1840. _pi.dwFlags |= REO_INPLACEACTIVE;
  1841. }
  1842. _fActivateCalled = FALSE;
  1843. }
  1844. else
  1845. return FALSE;
  1846. return TRUE;
  1847. }
  1848. /*
  1849. * COleObject::DeActivateObj
  1850. *
  1851. * @mfunc Deactivates the object.
  1852. *
  1853. */
  1854. HRESULT COleObject::DeActivateObj(void)
  1855. {
  1856. IOleInPlaceObject * pipo;
  1857. IOleObject *poo;
  1858. MSG msg;
  1859. HRESULT hr = NOERROR;
  1860. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "COleObject::DeActivateObj");
  1861. if (_fDeactivateCalled)
  1862. {
  1863. // There are multiple paths through the deactive code. The assumption
  1864. // with this logic is that it is more disconcerting for an app to
  1865. // get multiple deactivate calls than the opposite. This might
  1866. // prove to be an incorrect assumption. This go put in because I
  1867. // added a DeActivateObj call in DeActivateObj where there wasn't
  1868. // one before and I was afraid that this could cause problems because
  1869. // apps might get a call that they didn't have before. It is important
  1870. // to note that the opposite might be the case. (a-rsail).
  1871. return NOERROR;
  1872. }
  1873. _fDeactivateCalled = TRUE;
  1874. ResetPosRect();
  1875. if(_punkobj->QueryInterface(IID_IOleInPlaceObject, (void **)&pipo)
  1876. == NOERROR)
  1877. {
  1878. hr =_punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  1879. if(hr == NOERROR)
  1880. {
  1881. // This code is a bit different from 1.0, but seems to
  1882. // make things work a bit better. Basically, we've taken a leaf
  1883. // from various sample apps and do the most brute force "de-activate"
  1884. // possible (you'd think just one call would be enough ;-)
  1885. // Don't bother with the error return here.
  1886. pipo->UIDeactivate();
  1887. // Fake something
  1888. ZeroMemory(&msg, sizeof(MSG));
  1889. msg.message = WM_LBUTTONDOWN;
  1890. _ped->TxGetWindow(&msg.hwnd);
  1891. // Again, don't bother checking for errors; we need to
  1892. // plow through and get rid of stuff as much as possible.
  1893. poo->DoVerb(OLEIVERB_HIDE, &msg, (IOleClientSite *)this,
  1894. -1, msg.hwnd, &_rcPos);
  1895. // COMPATIBILITY ISSUE (alexgo): the RE1.0 code did some funny
  1896. // stuff with undo here, but I don't think it's necessary now
  1897. // with our multi-level undo model.
  1898. hr = pipo->InPlaceDeactivate();
  1899. poo->Release();
  1900. }
  1901. pipo->Release();
  1902. }
  1903. _fDeactivateCalled = FALSE;
  1904. return hr;
  1905. }
  1906. /*
  1907. * COleObject::Convert (rclsidNew, lpstrUserTypeNew)
  1908. *
  1909. * @mfunc Converts the object to the specified class. Does reload
  1910. * the object but does NOT force an update (caller must do this).
  1911. *
  1912. * @rdesc
  1913. * HRESULT Success code.
  1914. */
  1915. HRESULT COleObject::Convert(
  1916. REFCLSID rclsidNew, //@parm Destination clsid
  1917. LPCSTR lpstrUserTypeNew) //@parm New user type name
  1918. {
  1919. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::Convert");
  1920. CLIPFORMAT cfOld;
  1921. CLSID clsidOld;
  1922. LPOLESTR szUserTypeOld = NULL;
  1923. HRESULT hr;
  1924. HRESULT hrLatest;
  1925. UsesMakeOLESTR;
  1926. // If object has no storage, return
  1927. if(!_pstg)
  1928. return ResultFromScode(E_INVALIDARG);
  1929. // Read the old class, format, and user type in
  1930. if ((hr = ReadClassStg(_pstg, &clsidOld)) ||
  1931. (hr = ReadFmtUserTypeStg(_pstg, &cfOld, &szUserTypeOld)))
  1932. {
  1933. return hr;
  1934. }
  1935. // Unload object
  1936. Close(OLECLOSE_SAVEIFDIRTY);
  1937. _punkobj->Release();
  1938. if(IsZombie())
  1939. return CO_E_RELEASED;
  1940. // Write new class and user type, but old format, into storage
  1941. if ((hr = WriteClassStg(_pstg, rclsidNew)) ||
  1942. (hr = WriteFmtUserTypeStg(_pstg, cfOld,
  1943. (LPOLESTR) MakeOLESTR(lpstrUserTypeNew))) ||
  1944. (hr = SetConvertStg(_pstg, TRUE)) ||
  1945. ((hr = _pstg->Commit(0)) && (hr = _pstg->Commit(STGC_OVERWRITE))))
  1946. {
  1947. // Uh oh, we're in a bad state; rewrite the original info
  1948. (VOID) WriteClassStg(_pstg, clsidOld);
  1949. (VOID) WriteFmtUserTypeStg(_pstg, cfOld, szUserTypeOld);
  1950. }
  1951. if(IsZombie())
  1952. return CO_E_RELEASED;
  1953. // Reload the object and connect. If we can't reload it, delete it.
  1954. hrLatest = OleLoad(_pstg, IID_IOleObject, (LPOLECLIENTSITE) this,
  1955. (void **)&_punkobj);
  1956. if(hrLatest != NOERROR)
  1957. {
  1958. CRchTxtPtr rtp(_ped, _cp);
  1959. // we don't want the delete of this object to go on the undo
  1960. // stack. We use a space so that cp's will work out right for
  1961. // other undo actions.
  1962. rtp.ReplaceRange(1, 1, L" ", NULL, -1);
  1963. }
  1964. else
  1965. ConnectObject();
  1966. // Free the old
  1967. CoTaskMemFree(szUserTypeOld);
  1968. return hr ? hr : hrLatest;
  1969. }
  1970. /*
  1971. * COleObject::ActivateAs (rclsid, rclsidAs)
  1972. *
  1973. * @mfunc Handles a request by the user to activate all objects of a particular
  1974. * class as objects of another class.
  1975. *
  1976. * @rdesc
  1977. * HRESULT Success code.
  1978. */
  1979. HRESULT COleObject::ActivateAs(
  1980. REFCLSID rclsid,
  1981. REFCLSID rclsidAs)
  1982. {
  1983. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::ActivateAs");
  1984. IOleObject * poo = NULL;
  1985. CLSID clsid;
  1986. // Get clsid of object
  1987. HRESULT hr = _punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  1988. if(hr == NOERROR)
  1989. {
  1990. // NOTE: We are depending on the behavior of GetUserClassID to
  1991. // return the current clsid of the object (not the TreatAs id).
  1992. // This should hold true as long as long as we haven't reloaded
  1993. // it yet. If there are problems with ActivateAs in the future,
  1994. // this might be a suspect.
  1995. hr = poo->GetUserClassID(&clsid);
  1996. poo->Release();
  1997. }
  1998. if(hr != NOERROR)
  1999. return hr;
  2000. if(IsZombie())
  2001. return CO_E_RELEASED;
  2002. // Check to see if object clsid matches clsid to be treated as something
  2003. // else. If it is we need to unload and reload the object.
  2004. if(IsEqualCLSID(clsid, rclsid))
  2005. {
  2006. // Unload object
  2007. Close(OLECLOSE_SAVEIFDIRTY);
  2008. _punkobj->Release();
  2009. if(IsZombie())
  2010. return CO_E_RELEASED;
  2011. // Reload object and connect. If we can't reload it, delete it.
  2012. hr = OleLoad(_pstg, IID_IOleObject, (LPOLECLIENTSITE) this,
  2013. (void **)&_punkobj);
  2014. if(hr != NOERROR)
  2015. {
  2016. CRchTxtPtr rtp(_ped, _cp);
  2017. // We don't want the delete of this object to go on the undo
  2018. // stack. We use a space so that cp's will work out right for
  2019. // other undo actions.
  2020. rtp.ReplaceRange(1, 1, L" ", NULL, -1);
  2021. }
  2022. else
  2023. ConnectObject();
  2024. }
  2025. return hr;
  2026. }
  2027. /*
  2028. * COleObject::SetLinkAvailable(fAvailable)
  2029. *
  2030. * @mfunc
  2031. * Allows client to tell us whether the link is available or not.
  2032. *
  2033. * @rdesc
  2034. * HRESULT Success code.
  2035. */
  2036. HRESULT COleObject::SetLinkAvailable(
  2037. BOOL fAvailable) //@parm if TRUE, make object linkable
  2038. {
  2039. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::SetLinkAvailable");
  2040. // If this is not a link, return
  2041. if(!(_pi.dwFlags & REO_LINK))
  2042. return E_INVALIDARG;
  2043. // Set flag as appropriate
  2044. _pi.dwFlags &= ~REO_LINKAVAILABLE;
  2045. if(fAvailable)
  2046. _pi.dwFlags |= REO_LINKAVAILABLE;
  2047. return NOERROR;
  2048. }
  2049. /*
  2050. * COleObject::WriteTextInfoToEditStream(pes)
  2051. *
  2052. * @mfunc
  2053. * Used for textize support, Tries to determine the text
  2054. * representation for an object and then writes that info
  2055. * to the given stream. The only thing this is particularly useful
  2056. * for is to support richedit1.0's TEXTIZED data format.
  2057. *
  2058. * @rdesc
  2059. * LONG Number of chras written..
  2060. */
  2061. LONG COleObject::WriteTextInfoToEditStream(
  2062. EDITSTREAM *pes)
  2063. {
  2064. LONG cch;
  2065. LONG cbWritten = 0;
  2066. IOleObject *poo;
  2067. IDataObject *pdataobj = NULL;
  2068. STGMEDIUM med;
  2069. char *pch; //we only deal with ANSI data here
  2070. HANDLE hGlobal;
  2071. HRESULT hr = _punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  2072. if(hr == NOERROR)
  2073. {
  2074. hr = poo->GetClipboardData(0, &pdataobj);
  2075. poo->Release();
  2076. }
  2077. if(FAILED(hr))
  2078. {
  2079. hr = _punkobj->QueryInterface(IID_IDataObject, (void **)&pdataobj);
  2080. if(FAILED(hr))
  2081. {
  2082. pes->dwError = (DWORD) E_FAIL;
  2083. goto Default;
  2084. }
  2085. }
  2086. med.tymed = TYMED_HGLOBAL;
  2087. med.pUnkForRelease = NULL;
  2088. med.hGlobal = NULL;
  2089. hr = pdataobj->GetData(&g_rgFETC[iAnsiFETC], &med);
  2090. if(FAILED(hr))
  2091. pes->dwError = (DWORD)hr;
  2092. else
  2093. {
  2094. hGlobal = med.hGlobal;
  2095. pch = (char *)GlobalLock(hGlobal);
  2096. if(pch)
  2097. {
  2098. for (cch = 0; pch[cch]; cch++);
  2099. pes->dwError = pes->pfnCallback(pes->dwCookie, (BYTE *)pch, cch,
  2100. &cbWritten);
  2101. GlobalUnlock(hGlobal);
  2102. }
  2103. ReleaseStgMedium(&med);
  2104. }
  2105. Default:
  2106. if(cbWritten <= 0)
  2107. {
  2108. char ch = ' ';
  2109. pes->pfnCallback(pes->dwCookie, (BYTE *)&ch, sizeof(char), &cbWritten);
  2110. pes->dwError = 0;
  2111. }
  2112. pdataobj->Release();
  2113. return cbWritten;
  2114. }
  2115. /*
  2116. * COleObject::SetDvaspect (dvaspect)
  2117. *
  2118. * @mfunc Allows client to tell us which aspect to use and force us
  2119. * to recompute positioning and redraw.
  2120. */
  2121. void COleObject::SetDvaspect(
  2122. DWORD dvaspect) //@parm the aspect to use
  2123. {
  2124. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::SetDvaspect");
  2125. _pi.dvaspect = dvaspect;
  2126. // Force FetchObjectExtents to call through
  2127. _fAspectChanged = TRUE;
  2128. // Cause ourselves to redraw and update
  2129. OnViewChange(dvaspect, (DWORD) -1);
  2130. }
  2131. /*
  2132. * COleObject::HandsOffStorage
  2133. *
  2134. * @mfunc See IPersistStore::HandsOffStorage.
  2135. *
  2136. */
  2137. void COleObject::HandsOffStorage(void)
  2138. {
  2139. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::HandsOffStorage");
  2140. // Free storage we currently have, if we have one.
  2141. SafeReleaseAndNULL((IUnknown**)&_pstg);
  2142. }
  2143. /*
  2144. * COleObject::SaveCompleted
  2145. *
  2146. * @mfunc See IPersistStore::SaveCompleted.
  2147. */
  2148. void COleObject::SaveCompleted(
  2149. LPSTORAGE lpstg) //@parm new storage
  2150. {
  2151. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "COleObject::SaveCompleted");
  2152. // Did our caller give us a new storage to remember?
  2153. if(lpstg)
  2154. {
  2155. // Free storage we currently have, if we have one
  2156. if(_pstg)
  2157. SafeReleaseAndNULL((IUnknown**)&_pstg);
  2158. // Remember storage we are given, since we are given one
  2159. lpstg->AddRef();
  2160. _pstg = lpstg;
  2161. }
  2162. }
  2163. /*
  2164. * SetAllowedResizeDirections
  2165. *
  2166. * @func Resizing helper function
  2167. *
  2168. */
  2169. static void SetAllowedResizeDirections(
  2170. const POINT & pt,
  2171. const RECT & rc,
  2172. LPTSTR lphand,
  2173. BOOL & fTop,
  2174. BOOL & fBottom,
  2175. BOOL & fLeft,
  2176. BOOL & fRight)
  2177. {
  2178. fTop = abs(pt.y - rc.top) < abs(pt.y - rc.bottom);
  2179. fBottom = !fTop;
  2180. fLeft = abs(pt.x - rc.left) < abs(pt.x - rc.right);
  2181. fRight = !fLeft;
  2182. if(lphand == IDC_SIZENS)
  2183. fLeft = fRight = FALSE;
  2184. else if(lphand == IDC_SIZEWE)
  2185. fTop = fBottom = FALSE;
  2186. }
  2187. /*
  2188. * SetRestriction.
  2189. *
  2190. * @func Resizing helper function determines bounding rectangle for resizing.
  2191. */
  2192. static void SetRestriction(
  2193. RECT & rc,
  2194. HWND hwnd,
  2195. DWORD dwScroll)
  2196. {
  2197. GetClientRect(hwnd, &rc);
  2198. InflateRect(&rc, -1, -1); // So rectangle is visible
  2199. // Allow objects to grow larger than the window in the
  2200. // directions which have scrollbars
  2201. if(dwScroll & WS_HSCROLL)
  2202. rc.right = MAXLONG;
  2203. if(dwScroll & WS_VSCROLL)
  2204. rc.bottom = MAXLONG;
  2205. }
  2206. /*
  2207. * Restrict (&pt, &rc)
  2208. *
  2209. * @func Resizing helper function bounds a point within a rectangle
  2210. */
  2211. static void Restrict(
  2212. POINT &pt,
  2213. RECT &rc)
  2214. {
  2215. if(pt.x < rc.left)
  2216. pt.x = rc.left;
  2217. else if(pt.x > rc.right)
  2218. pt.x = rc.right;
  2219. if(pt.y < rc.top)
  2220. pt.y = rc.top;
  2221. else if(pt.y > rc.bottom)
  2222. pt.y = rc.bottom;
  2223. }
  2224. /*
  2225. * COleObject::HandleResize (&pt)
  2226. *
  2227. * @mfunc Deal with object resizing.
  2228. *
  2229. * @rdesc BOOL
  2230. */
  2231. BOOL COleObject::HandleResize(
  2232. const POINT &pt)
  2233. {
  2234. LPTSTR lphand;
  2235. DWORD dwFlags = _pi.dwFlags;
  2236. HWND hwnd;
  2237. RECT rcOld;
  2238. RECT rcRestrict;
  2239. BOOL fTop, fBottom, fLeft, fRight;
  2240. BOOL fEscape;
  2241. CDisplay *pdp = _ped->_pdp;
  2242. if(!(dwFlags & REO_SELECTED) ||
  2243. !(dwFlags & REO_RESIZABLE) ||
  2244. (lphand = CheckForHandleHit(pt)) == NULL || !pdp)
  2245. {
  2246. return FALSE;
  2247. }
  2248. HDC hdc = pdp->GetDC();
  2249. rcOld = _rcPos; // Save old size
  2250. _ped->TxGetWindow(&hwnd);
  2251. SetCapture(hwnd);
  2252. SetRestriction(rcRestrict, hwnd, _ped->TxGetScrollBars());
  2253. SetAllowedResizeDirections(pt, _rcPos, lphand,
  2254. fTop, fBottom, fLeft, fRight);
  2255. // Erase and redraw frame without handles.
  2256. DrawFrame(pdp, hdc, &_rcPos);
  2257. _pi.dwFlags = REO_NULL;
  2258. DrawFrame(pdp, hdc, &_rcPos);
  2259. fEscape = FALSE;
  2260. const INT vkey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
  2261. while (GetAsyncKeyState(vkey) & 0x8000)
  2262. {
  2263. POINT ptLast = pt;
  2264. POINT ptCur;
  2265. MSG msg;
  2266. // Stop if the ESC key has been pressed
  2267. if(GetAsyncKeyState(VK_ESCAPE) & 0x0001)
  2268. {
  2269. fEscape = TRUE;
  2270. break;
  2271. }
  2272. GetCursorPos(&ptCur);
  2273. ScreenToClient(hwnd, &ptCur);
  2274. // GetCursorPos() isn't supported on WinCE. We have it hacked to
  2275. // be GetMessagePos() which unfortunately in this case will cause
  2276. // ptCur to never change. By removing this check we end up drawing
  2277. // multiple times when the user pauses during a resize.
  2278. #ifndef UNDER_CE
  2279. // If mouse hasn't moved, try again
  2280. if((ptCur.x == ptLast.x) && (ptCur.y == ptLast.y))
  2281. continue;
  2282. #endif
  2283. ptLast = ptCur;
  2284. Restrict(ptCur, rcRestrict);
  2285. // Erase old rectangle, update rectangle, and redraw
  2286. DrawFrame(pdp, hdc, &_rcPos);
  2287. if(fLeft) _rcPos.left = ptCur.x;
  2288. if(fRight) _rcPos.right = ptCur.x;
  2289. if(fTop) _rcPos.top = ptCur.y;
  2290. if(fBottom) _rcPos.bottom = ptCur.y;
  2291. // Keep a minimun width and height
  2292. INT xWidthSys = pdp->GetXWidthSys();
  2293. INT yHeightSys = pdp->GetYHeightSys();
  2294. if(_rcPos.right - _rcPos.left < xWidthSys)
  2295. {
  2296. if(fLeft) _rcPos.left = _rcPos.right - xWidthSys;
  2297. if(fRight) _rcPos.right = _rcPos.left + xWidthSys;
  2298. }
  2299. if(_rcPos.bottom - _rcPos.top < yHeightSys)
  2300. {
  2301. if(fTop) _rcPos.top = _rcPos.bottom - yHeightSys;
  2302. if(fBottom) _rcPos.bottom = _rcPos.top + yHeightSys;
  2303. }
  2304. DrawFrame(pdp, hdc, &_rcPos);
  2305. // FUTURE: (joseogl): It would be cool if we could do something
  2306. // bettter here, but for now, it appears to be necessary.
  2307. Sleep(100);
  2308. // Eat input messages
  2309. if (PeekMessage(&msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) ||
  2310. PeekMessage(&msg, 0, WM_MOUSEFIRST,
  2311. WM_MOUSELAST, PM_REMOVE | PM_NOYIELD) ||
  2312. PeekMessage(&msg, 0, WM_NCMOUSEFIRST,
  2313. WM_NCMOUSELAST, PM_REMOVE | PM_NOYIELD))
  2314. {
  2315. // Break out of the loop if the Escape key was pressed
  2316. if(msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
  2317. {
  2318. fEscape = TRUE;
  2319. break;
  2320. }
  2321. }
  2322. }
  2323. DrawFrame(pdp, hdc, &_rcPos);
  2324. ReleaseCapture();
  2325. RECT rcNew = _rcPos;
  2326. _rcPos = rcOld;
  2327. _pi.dwFlags = dwFlags;
  2328. // If user aborted, then we skip the resizing stuff
  2329. if(fEscape)
  2330. DrawFrame(pdp, hdc, &_rcPos);
  2331. else
  2332. {
  2333. EnableGuardPosRect();
  2334. Resize(rcNew);
  2335. DrawFrame(pdp, hdc, &_rcPos);
  2336. DisableGuardPosRect();
  2337. }
  2338. pdp->ReleaseDC(hdc);
  2339. return TRUE;
  2340. }
  2341. /*
  2342. * COleObject::Resize(rcNew)
  2343. *
  2344. * @mfunc Set new object size. Handle undo details.
  2345. */
  2346. void COleObject::Resize(
  2347. const RECT &rcNew)
  2348. {
  2349. CDisplay * pdp = _ped->_pdp;
  2350. SIZEL sizelold = _sizel;
  2351. // Change the size of our internal representation.
  2352. _sizel.cx = pdp->DXtoHimetricX(rcNew.right - rcNew.left);
  2353. _sizel.cy = pdp->DYtoHimetricY(rcNew.bottom - rcNew.top);
  2354. //If size didn't really change, don't do anything else.
  2355. if(_sizel.cx != sizelold.cx || _sizel.cy != sizelold.cy)
  2356. {
  2357. if(_ped->_fUseUndo)
  2358. {
  2359. CGenUndoBuilder undobldr(_ped, UB_AUTOCOMMIT);
  2360. IAntiEvent *pae;
  2361. pae = gAEDispenser.CreateResizeObjectAE(_ped, this, _rcPos);
  2362. if(pae)
  2363. undobldr.AddAntiEvent(pae);
  2364. }
  2365. _rcPos.bottom = _rcPos.top + pdp->HimetricYtoDY(_sizel.cy);
  2366. _rcPos.right = _rcPos.left + pdp->HimetricXtoDX(_sizel.cx);
  2367. SetExtent(SE_NOTACTIVATING);
  2368. // Force a redraw that will stretch the object.
  2369. pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, _cp, _cp + 1);
  2370. _ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
  2371. }
  2372. }
  2373. /*
  2374. * COleObject::OnReposition (dx, dy)
  2375. *
  2376. * @mfunc Set object's new position. May have changed as a result of scrolling.
  2377. */
  2378. void COleObject::OnReposition(
  2379. LONG dx,
  2380. LONG dy)
  2381. {
  2382. IOleInPlaceObject *pipo;
  2383. RECT rcClip;
  2384. if(!_fInPlaceActive)
  2385. {
  2386. // If we're not inplace active, don't do anything
  2387. return;
  2388. }
  2389. _ped->_pdp->GetViewRect(rcClip);
  2390. _rcPos.left += dx;
  2391. _rcPos.right += dx;
  2392. _rcPos.top += dy;
  2393. _rcPos.bottom += dy;
  2394. if(_punkobj->QueryInterface(IID_IOleInPlaceObject, (void **)&pipo)
  2395. == NOERROR)
  2396. {
  2397. pipo->SetObjectRects(&_rcPos, &rcClip);
  2398. pipo->Release();
  2399. }
  2400. }
  2401. /*
  2402. * COleObject::ResetPosRect(pAdjust)
  2403. *
  2404. * @mfunc Recompute the object's position rectangle from its cp.
  2405. */
  2406. void COleObject::ResetPosRect(
  2407. LONG *pAdjust) //@parm output adjustment needed for positioning below baseline
  2408. {
  2409. CRchTxtPtr rtp(_ped, 0);
  2410. POINT pt, pt1;
  2411. LONG yHeight = _ped->_pdp->HimetricYtoDY(_sizel.cy);
  2412. rtp.SetCp(_cp);
  2413. if(_ped->_pdp->PointFromTp(rtp, NULL, FALSE, pt, NULL, TA_TOP) == -1)
  2414. return;
  2415. _rcPos.top = pt.y;
  2416. _ped->_pdp->PointFromTp(rtp, NULL, FALSE, pt1, NULL,
  2417. (_pi.dwFlags & REO_BELOWBASELINE) ? TA_BOTTOM : TA_BASELINE);
  2418. if(pAdjust)
  2419. *pAdjust = 0;
  2420. if(pt1.y - pt.y > yHeight)
  2421. {
  2422. // If line is bigger than object move object down.
  2423. _rcPos.top += pt1.y - pt.y - yHeight;
  2424. if(pAdjust)
  2425. *pAdjust = pt1.y - pt.y - yHeight;
  2426. }
  2427. _rcPos.bottom = _rcPos.top + yHeight;
  2428. _rcPos.left = pt.x;
  2429. _rcPos.right = _rcPos.left + _ped->_pdp->HimetricXtoDX(_sizel.cx);
  2430. }
  2431. #ifdef DEBUG
  2432. void COleObject::DbgDump(DWORD id){
  2433. Tracef(TRCSEVNONE, "Object #%d %X: cp = %d , rect = (%d, %d, %d, %d)",id,this,_cp,_rcPos.top,_rcPos.left,_rcPos.bottom,_rcPos.right);
  2434. }
  2435. #endif
  2436. /*
  2437. * COleObject:SetExtent(iActivating)
  2438. *
  2439. * @mfunc A wrapper around IOleObject::SetExtent which makes some additional
  2440. * checks if the first call to IOleObject::SetExtent fails.
  2441. *
  2442. * @rdesc HRESULT
  2443. */
  2444. HRESULT COleObject::SetExtent(
  2445. int iActivating) //@parm indicates if object is currently being activated
  2446. {
  2447. LPOLEOBJECT poo;
  2448. // If we are connected to a link object, the native extent can't be change,
  2449. // so don't bother doing anything here.
  2450. if(_pi.dwFlags & REO_LINK)
  2451. {
  2452. // So we don't call GetExtents on remeasuring.
  2453. _fSetExtent = TRUE;
  2454. return NOERROR;
  2455. }
  2456. HRESULT hr = _punkobj->QueryInterface(IID_IOleObject, (void **)&poo);
  2457. if(hr != NOERROR)
  2458. return hr;
  2459. // If we are about to activate the object, fall through and OleRun the
  2460. // object prior to attempting to SetExtent. Otherwise, attempt a SetExtent
  2461. // directly.
  2462. if(iActivating == SE_NOTACTIVATING)
  2463. {
  2464. // By default, we will call SetExtent when the object is next activated.
  2465. _fSetExtent = TRUE;
  2466. hr = poo->SetExtent(_pi.dvaspect, &_sizel);
  2467. DWORD dwStatus;
  2468. // If the server is not running we need to to some additional
  2469. // checking. If it was, we do not need to call SetExtent again.
  2470. // Find out if OLEMISC_RECOMPOSEONRESIZE is set. If it is, we should
  2471. // run the object and call setextent. If not, we defer calling set
  2472. // extent until we are ready to activate the object.
  2473. if(!(hr == OLE_E_NOTRUNNING &&
  2474. poo->GetMiscStatus(_pi.dvaspect, &dwStatus) == NOERROR &&
  2475. (dwStatus & OLEMISC_RECOMPOSEONRESIZE)))
  2476. {
  2477. goto DontRunAndSetAgain;
  2478. }
  2479. // Fall through and attempt the SetExtent again after running the object
  2480. }
  2481. {
  2482. SIZEL sizelsave = _sizel;
  2483. OleRun(_punkobj); // This call causes _sizel to be reset
  2484. // via OLE and FetchObjectExtents.
  2485. _sizel = sizelsave;
  2486. }
  2487. poo->SetExtent(_pi.dvaspect, &_sizel);
  2488. DontRunAndSetAgain:
  2489. if((hr == NOERROR) ||
  2490. (iActivating == SE_NOTACTIVATING && hr != OLE_E_NOTRUNNING))
  2491. {
  2492. _fSetExtent = FALSE;
  2493. }
  2494. // If the server is still not running, we try again at
  2495. // activation time. Otherwise the server has either
  2496. // done its thing or it doesn't do resize. Either way
  2497. // we don't bother trying again at activation time.
  2498. if(hr == NOERROR && _fIsPaintBrush)
  2499. {
  2500. SIZEL sizelChk;
  2501. poo->GetExtent(_pi.dvaspect, &sizelChk);
  2502. _fPBUseLocalSizel = !(sizelChk.cx == _sizel.cx &&
  2503. sizelChk.cy == _sizel.cy);
  2504. // HACK: Calls to SetExtent on PaintBrush objects may not
  2505. // actually change the object extents. In such cases,
  2506. // we will rely on local _sizel for PaintBrush object extents.
  2507. }
  2508. poo->Release();
  2509. return hr;
  2510. }