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.

3018 lines
72 KiB

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