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.

3540 lines
106 KiB

  1. /*************************************************************************
  2. **
  3. ** OLE 2 Container Sample Code
  4. **
  5. ** cntrline.c
  6. **
  7. ** This file contains ContainerLine methods.
  8. **
  9. ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
  10. **
  11. *************************************************************************/
  12. #include "outline.h"
  13. OLEDBGDATA
  14. extern LPOUTLINEAPP g_lpApp;
  15. extern IUnknownVtbl g_CntrLine_UnknownVtbl;
  16. extern IOleClientSiteVtbl g_CntrLine_OleClientSiteVtbl;
  17. extern IAdviseSinkVtbl g_CntrLine_AdviseSinkVtbl;
  18. #if defined( INPLACE_CNTR )
  19. extern IOleInPlaceSiteVtbl g_CntrLine_OleInPlaceSiteVtbl;
  20. extern BOOL g_fInsideOutContainer;
  21. #endif // INPLACE_CNTR
  22. // REVIEW: should use string resource for messages
  23. char ErrMsgDoVerb[] = "OLE object action failed!";
  24. /* prototype for static functions */
  25. static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC);
  26. /*************************************************************************
  27. ** ContainerLine
  28. ** This object represents the location within the container where
  29. ** the embedded/linked object lives. It exposes interfaces to the
  30. ** object that allow the object to get information about its
  31. ** embedding site and to announce notifications of important events
  32. ** (changed, closed, saved)
  33. **
  34. ** The ContainerLine exposes the following interfaces:
  35. ** IUnknown
  36. ** IOleClientSite
  37. ** IAdviseSink
  38. *************************************************************************/
  39. /*************************************************************************
  40. ** ContainerLine::IUnknown interface implementation
  41. *************************************************************************/
  42. // IUnknown::QueryInterface
  43. STDMETHODIMP CntrLine_Unk_QueryInterface(
  44. LPUNKNOWN lpThis,
  45. REFIID riid,
  46. LPVOID FAR* lplpvObj
  47. )
  48. {
  49. LPCONTAINERLINE lpContainerLine =
  50. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  51. return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);
  52. }
  53. // IUnknown::AddRef
  54. STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis)
  55. {
  56. LPCONTAINERLINE lpContainerLine =
  57. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  58. OleDbgAddRefMethod(lpThis, "IUnknown");
  59. return ContainerLine_AddRef(lpContainerLine);
  60. }
  61. // IUnknown::Release
  62. STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis)
  63. {
  64. LPCONTAINERLINE lpContainerLine =
  65. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  66. OleDbgReleaseMethod(lpThis, "IUnknown");
  67. return ContainerLine_Release(lpContainerLine);
  68. }
  69. /*************************************************************************
  70. ** ContainerLine::IOleClientSite interface implementation
  71. *************************************************************************/
  72. // IOleClientSite::QueryInterface
  73. STDMETHODIMP CntrLine_CliSite_QueryInterface(
  74. LPOLECLIENTSITE lpThis,
  75. REFIID riid,
  76. LPVOID FAR* lplpvObj
  77. )
  78. {
  79. LPCONTAINERLINE lpContainerLine =
  80. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  81. return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);
  82. }
  83. // IOleClientSite::AddRef
  84. STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis)
  85. {
  86. LPCONTAINERLINE lpContainerLine =
  87. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  88. OleDbgAddRefMethod(lpThis, "IOleClientSite");
  89. return ContainerLine_AddRef(lpContainerLine);
  90. }
  91. // IOleClientSite::Release
  92. STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis)
  93. {
  94. LPCONTAINERLINE lpContainerLine =
  95. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  96. OleDbgReleaseMethod(lpThis, "IOleClientSite");
  97. return ContainerLine_Release(lpContainerLine);
  98. }
  99. // IOleClientSite::SaveObject
  100. STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis)
  101. {
  102. LPCONTAINERLINE lpContainerLine =
  103. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  104. LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;
  105. SCODE sc = S_OK;
  106. HRESULT hrErr;
  107. OLEDBG_BEGIN2("CntrLine_CliSite_SaveObject\r\n")
  108. if (! lpPersistStg) {
  109. /* OLE2NOTE: The object is NOT loaded. a container must be
  110. ** prepared for the fact that an object that it thinks it
  111. ** has unloaded may still call IOleClientSite::SaveObject.
  112. ** in this case the container should fail the save call and
  113. ** NOT try to reload the object. this scenario arises if you
  114. ** have a in-process server (DLL object) which has a
  115. ** connected linking client. even after the embedding
  116. ** container unloads the DLL object, the link connection
  117. ** keeps the object alive. it may then as part of its
  118. ** shutdown try to call IOCS::SaveObject, but then it is too
  119. ** late.
  120. */
  121. OLEDBG_END2
  122. return ResultFromScode(E_FAIL);
  123. }
  124. // mark ContainerDoc as now dirty
  125. OutlineDoc_SetModified(
  126. (LPOUTLINEDOC)lpContainerLine->m_lpDoc, TRUE, TRUE, FALSE);
  127. /* Tell OLE object to save itself
  128. ** OLE2NOTE: it is NOT sufficient to ONLY call
  129. ** IPersistStorage::Save method. it is also necessary to call
  130. ** WriteClassStg. the helper API OleSave does this automatically.
  131. */
  132. OLEDBG_BEGIN2("OleSave called\r\n")
  133. hrErr=OleSave(lpPersistStg,lpContainerLine->m_lpStg, TRUE/*fSameAsLoad*/);
  134. OLEDBG_END2
  135. if (hrErr != NOERROR) {
  136. OleDbgOutHResult("WARNING: OleSave returned", hrErr);
  137. sc = GetScode(hrErr);
  138. }
  139. // OLE2NOTE: even if OleSave fails, SaveCompleted must be called.
  140. OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")
  141. hrErr = lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg, NULL);
  142. OLEDBG_END2
  143. if (hrErr != NOERROR) {
  144. OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);
  145. if (sc == S_OK)
  146. sc = GetScode(hrErr);
  147. }
  148. OLEDBG_END2
  149. return ResultFromScode(sc);
  150. }
  151. // IOleClientSite::GetMoniker
  152. STDMETHODIMP CntrLine_CliSite_GetMoniker(
  153. LPOLECLIENTSITE lpThis,
  154. DWORD dwAssign,
  155. DWORD dwWhichMoniker,
  156. LPMONIKER FAR* lplpmk
  157. )
  158. {
  159. LPCONTAINERLINE lpContainerLine;
  160. lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  161. OLEDBG_BEGIN2("CntrLine_CliSite_GetMoniker\r\n")
  162. // OLE2NOTE: we must make sure to set output pointer parameters to NULL
  163. *lplpmk = NULL;
  164. switch (dwWhichMoniker) {
  165. case OLEWHICHMK_CONTAINER:
  166. /* OLE2NOTE: create a FileMoniker which identifies the
  167. ** entire container document.
  168. */
  169. *lplpmk = OleDoc_GetFullMoniker(
  170. (LPOLEDOC)lpContainerLine->m_lpDoc,
  171. dwAssign
  172. );
  173. break;
  174. case OLEWHICHMK_OBJREL:
  175. /* OLE2NOTE: create an ItemMoniker which identifies the
  176. ** OLE object relative to the container document.
  177. */
  178. *lplpmk = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign);
  179. break;
  180. case OLEWHICHMK_OBJFULL:
  181. {
  182. /* OLE2NOTE: create an absolute moniker which identifies the
  183. ** OLE object in the container document. this moniker is
  184. ** created as a composite of the absolute moniker for the
  185. ** entire document appended with an item moniker which
  186. ** identifies the OLE object relative to the document.
  187. */
  188. *lplpmk = ContainerLine_GetFullMoniker(lpContainerLine, dwAssign);
  189. break;
  190. }
  191. }
  192. OLEDBG_END2
  193. if (*lplpmk != NULL)
  194. return NOERROR;
  195. else
  196. return ResultFromScode(E_FAIL);
  197. }
  198. // IOleClientSite::GetContainer
  199. STDMETHODIMP CntrLine_CliSite_GetContainer(
  200. LPOLECLIENTSITE lpThis,
  201. LPOLECONTAINER FAR* lplpContainer
  202. )
  203. {
  204. LPCONTAINERLINE lpContainerLine;
  205. HRESULT hrErr;
  206. OLEDBG_BEGIN2("CntrLine_CliSite_GetContainer\r\n")
  207. lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  208. hrErr = OleDoc_QueryInterface(
  209. (LPOLEDOC)lpContainerLine->m_lpDoc,
  210. &IID_IOleContainer,
  211. (LPVOID FAR*)lplpContainer
  212. );
  213. OLEDBG_END2
  214. return hrErr;
  215. }
  216. // IOleClientSite::ShowObject
  217. STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis)
  218. {
  219. LPCONTAINERLINE lpContainerLine =
  220. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  221. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  222. LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
  223. int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
  224. HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp);
  225. OLEDBG_BEGIN2("CntrLine_CliSite_ShowObject\r\n")
  226. /* make sure our doc window is visible and not minimized.
  227. ** the OutlineDoc_ShowWindow function will cause the app window
  228. ** to show itself SW_SHOWNORMAL.
  229. */
  230. if (! IsWindowVisible(hWndFrame) || IsIconic(hWndFrame))
  231. OutlineDoc_ShowWindow(lpOutlineDoc);
  232. BringWindowToTop(hWndFrame);
  233. /* make sure that the OLE object is currently in view. if necessary
  234. ** scroll the document in order to bring it into view.
  235. */
  236. LineList_ScrollLineIntoView(lpLL, nIndex);
  237. #if defined( INPLACE_CNTR )
  238. /* after the in-place object is scrolled into view, we need to ask
  239. ** it to update its rect for the new clip rect coordinates
  240. */
  241. ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0);
  242. #endif
  243. OLEDBG_END2
  244. return NOERROR;
  245. }
  246. // IOleClientSite::OnShowWindow
  247. STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis, BOOL fShow)
  248. {
  249. LPCONTAINERLINE lpContainerLine =
  250. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  251. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  252. LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
  253. int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
  254. if (fShow) {
  255. OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(TRUE)\r\n")
  256. /* OLE2NOTE: we need to hatch out the OLE object now; it has
  257. ** just been opened in a window elsewhere (open editing as
  258. ** opposed to in-place activation).
  259. ** force the line to re-draw with the hatch.
  260. */
  261. lpContainerLine->m_fObjWinOpen = TRUE;
  262. LineList_ForceLineRedraw(lpLL, nIndex, FALSE /*fErase*/);
  263. } else {
  264. OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(FALSE)\r\n")
  265. /* OLE2NOTE: the object associated with this container site has
  266. ** just closed its server window. we should now remove the
  267. ** hatching that indicates that the object is open
  268. ** elsewhere. also our window should now come to the top.
  269. ** force the line to re-draw without the hatch.
  270. */
  271. lpContainerLine->m_fObjWinOpen = FALSE;
  272. LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/);
  273. BringWindowToTop(lpOutlineDoc->m_hWndDoc);
  274. SetFocus(lpOutlineDoc->m_hWndDoc);
  275. }
  276. OLEDBG_END2
  277. return NOERROR;
  278. }
  279. // IOleClientSite::RequestNewObjectLayout
  280. STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis)
  281. {
  282. OleDbgOut2("CntrLine_CliSite_RequestNewObjectLayout\r\n");
  283. /* OLE2NOTE: this method is NOT yet used. it is for future layout
  284. ** negotiation support.
  285. */
  286. return ResultFromScode(E_NOTIMPL);
  287. }
  288. /*************************************************************************
  289. ** ContainerLine::IAdviseSink interface implementation
  290. *************************************************************************/
  291. // IAdviseSink::QueryInterface
  292. STDMETHODIMP CntrLine_AdvSink_QueryInterface(
  293. LPADVISESINK lpThis,
  294. REFIID riid,
  295. LPVOID FAR* lplpvObj
  296. )
  297. {
  298. LPCONTAINERLINE lpContainerLine =
  299. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  300. return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);
  301. }
  302. // IAdviseSink::AddRef
  303. STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis)
  304. {
  305. LPCONTAINERLINE lpContainerLine =
  306. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  307. OleDbgAddRefMethod(lpThis, "IAdviseSink");
  308. return ContainerLine_AddRef(lpContainerLine);
  309. }
  310. // IAdviseSink::Release
  311. STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis)
  312. {
  313. LPCONTAINERLINE lpContainerLine =
  314. ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;
  315. OleDbgReleaseMethod(lpThis, "IAdviseSink");
  316. return ContainerLine_Release(lpContainerLine);
  317. }
  318. // IAdviseSink::OnDataChange
  319. STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange(
  320. LPADVISESINK lpThis,
  321. FORMATETC FAR* lpFormatetc,
  322. STGMEDIUM FAR* lpStgmed
  323. )
  324. {
  325. OleDbgOut2("CntrLine_AdvSink_OnDataChange\r\n");
  326. // We are not interested in data changes (only view changes)
  327. // (ie. nothing to do)
  328. }
  329. STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange(
  330. LPADVISESINK lpThis,
  331. DWORD aspects,
  332. LONG lindex
  333. )
  334. {
  335. LPCONTAINERLINE lpContainerLine;
  336. LPOUTLINEDOC lpOutlineDoc;
  337. HWND hWndDoc;
  338. LPLINELIST lpLL;
  339. MSG msg;
  340. int nIndex;
  341. OLEDBG_BEGIN2("CntrLine_AdvSink_OnViewChange\r\n")
  342. lpContainerLine = ((struct CAdviseSinkImpl FAR*)lpThis)->lpContainerLine;
  343. lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  344. /* OLE2NOTE: at this point we simply invalidate the rectangle of
  345. ** the object to force a repaint in the future, we mark
  346. ** that the extents of the object may have changed
  347. ** (m_fDoGetExtent=TRUE), and we post a message
  348. ** (WM_U_UPDATEOBJECTEXTENT) to our document that one or more
  349. ** OLE objects may need to have their extents updated. later
  350. ** when this message is processed, the document loops through
  351. ** all lines to see if any are marked as needing an extent update.
  352. ** if infact the extents did change. this can be done by calling
  353. ** IViewObject2::GetExtent to retreive the object's current
  354. ** extents and comparing with the last known extents for the
  355. ** object. if the extents changed, then relayout space for the
  356. ** object before drawing. we postpone the check to get
  357. ** the extents now because OnViewChange is an asyncronis method,
  358. ** and we have to careful not to call any syncronis methods back
  359. ** to the object. while it WOULD be OK to call the
  360. ** IViewObject2::GetExtent method within the asyncronis
  361. ** OnViewChange method (because this method is handled by the
  362. ** object handler and never remoted), it is good practise to not
  363. ** call any object methods from within an asyncronis
  364. ** notification method.
  365. ** if there is already WM_U_UPDATEOBJECTEXTENT message waiting
  366. ** in our message queue, there is no need to post another one.
  367. ** in this way, if the server is updating quicker than we can
  368. ** keep up, we do not make unneccsary GetExtent calls. also if
  369. ** drawing is disabled, we postpone updating the extents of any
  370. ** objects until drawing is re-enabled.
  371. */
  372. lpContainerLine->m_fDoGetExtent = TRUE;
  373. hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc);
  374. if (lpOutlineDoc->m_nDisableDraw == 0 &&
  375. ! PeekMessage(&msg, hWndDoc,
  376. WM_U_UPDATEOBJECTEXTENT, WM_U_UPDATEOBJECTEXTENT,
  377. PM_NOREMOVE | PM_NOYIELD)) {
  378. PostMessage(hWndDoc, WM_U_UPDATEOBJECTEXTENT, 0, 0L);
  379. }
  380. // force the modified line to redraw.
  381. lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
  382. nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
  383. LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/);
  384. OLEDBG_END2
  385. }
  386. // IAdviseSink::OnRename
  387. STDMETHODIMP_(void) CntrLine_AdvSink_OnRename(
  388. LPADVISESINK lpThis,
  389. LPMONIKER lpmk
  390. )
  391. {
  392. OleDbgOut2("CntrLine_AdvSink_OnRename\r\n");
  393. /* OLE2NOTE: the Embedding Container has nothing to do here. this
  394. ** notification is important for linking situations. it tells
  395. ** the OleLink objects to update their moniker because the
  396. ** source object has been renamed (track the link source).
  397. */
  398. }
  399. // IAdviseSink::OnSave
  400. STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis)
  401. {
  402. OleDbgOut2("CntrLine_AdvSink_OnSave\r\n");
  403. /* OLE2NOTE: the Embedding Container has nothing to do here. this
  404. ** notification is only useful to clients which have set up a
  405. ** data cache with the ADVFCACHE_ONSAVE flag.
  406. */
  407. }
  408. // IAdviseSink::OnClose
  409. STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis)
  410. {
  411. OleDbgOut2("CntrLine_AdvSink_OnClose\r\n");
  412. /* OLE2NOTE: the Embedding Container has nothing to do here. this
  413. ** notification is important for the OLE's default object handler
  414. ** and the OleLink object. it tells them the remote object is
  415. ** shutting down.
  416. */
  417. }
  418. /*************************************************************************
  419. ** ContainerLine Support Functions
  420. *************************************************************************/
  421. /* ContainerLine_Init
  422. ** ------------------
  423. ** Initialize fields in a newly constructed ContainerLine line object.
  424. ** NOTE: ref cnt of ContainerLine initialized to 0
  425. */
  426. void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC)
  427. {
  428. Line_Init((LPLINE)lpContainerLine, nTab, hDC); // init base class fields
  429. ((LPLINE)lpContainerLine)->m_lineType = CONTAINERLINETYPE;
  430. ((LPLINE)lpContainerLine)->m_nWidthInHimetric = DEFOBJWIDTH;
  431. ((LPLINE)lpContainerLine)->m_nHeightInHimetric = DEFOBJHEIGHT;
  432. lpContainerLine->m_cRef = 0;
  433. lpContainerLine->m_szStgName[0] = '\0';
  434. lpContainerLine->m_fObjWinOpen = FALSE;
  435. lpContainerLine->m_fMonikerAssigned = FALSE;
  436. lpContainerLine->m_dwDrawAspect = DVASPECT_CONTENT;
  437. lpContainerLine->m_fGuardObj = FALSE;
  438. lpContainerLine->m_fDoGetExtent = FALSE;
  439. lpContainerLine->m_fDoSetExtent = FALSE;
  440. lpContainerLine->m_sizeInHimetric.cx = -1;
  441. lpContainerLine->m_sizeInHimetric.cy = -1;
  442. lpContainerLine->m_lpStg = NULL;
  443. lpContainerLine->m_lpDoc = NULL;
  444. lpContainerLine->m_lpOleObj = NULL;
  445. lpContainerLine->m_lpViewObj2 = NULL;
  446. lpContainerLine->m_lpPersistStg = NULL;
  447. lpContainerLine->m_lpOleLink = NULL;
  448. lpContainerLine->m_dwLinkType = 0;
  449. lpContainerLine->m_fLinkUnavailable = FALSE;
  450. lpContainerLine->m_lpszShortType = NULL;
  451. #if defined( INPLACE_CNTR )
  452. lpContainerLine->m_fIpActive = FALSE;
  453. lpContainerLine->m_fUIActive = FALSE;
  454. lpContainerLine->m_fIpVisible = FALSE;
  455. lpContainerLine->m_lpOleIPObj = NULL;
  456. lpContainerLine->m_fInsideOutObj = FALSE;
  457. lpContainerLine->m_fIpChangesUndoable = FALSE;
  458. lpContainerLine->m_fIpServerRunning = FALSE;
  459. lpContainerLine->m_hWndIpObject = NULL;
  460. lpContainerLine->m_nHorizScrollShift = 0;
  461. #endif // INPLACE_CNTR
  462. INIT_INTERFACEIMPL(
  463. &lpContainerLine->m_Unknown,
  464. &g_CntrLine_UnknownVtbl,
  465. lpContainerLine
  466. );
  467. INIT_INTERFACEIMPL(
  468. &lpContainerLine->m_OleClientSite,
  469. &g_CntrLine_OleClientSiteVtbl,
  470. lpContainerLine
  471. );
  472. INIT_INTERFACEIMPL(
  473. &lpContainerLine->m_AdviseSink,
  474. &g_CntrLine_AdviseSinkVtbl,
  475. lpContainerLine
  476. );
  477. #if defined( INPLACE_CNTR )
  478. INIT_INTERFACEIMPL(
  479. &lpContainerLine->m_OleInPlaceSite,
  480. &g_CntrLine_OleInPlaceSiteVtbl,
  481. lpContainerLine
  482. );
  483. #endif // INPLACE_CNTR
  484. }
  485. /* Setup the OLE object associated with the ContainerLine */
  486. BOOL ContainerLine_SetupOleObject(
  487. LPCONTAINERLINE lpContainerLine,
  488. BOOL fDisplayAsIcon,
  489. HGLOBAL hMetaPict
  490. )
  491. {
  492. DWORD dwDrawAspect = (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);
  493. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  494. /* Cache a pointer to the IViewObject2* interface. *Required*
  495. ** we need this everytime we draw the object.
  496. **
  497. ** OLE2NOTE: We require the object to support IViewObject2
  498. ** interface. this is an extension to the IViewObject interface
  499. ** that was added with the OLE 2.01 release. This interface must
  500. ** be supported by all object handlers and DLL-based objects.
  501. */
  502. lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(
  503. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2);
  504. if (! lpContainerLine->m_lpViewObj2) {
  505. #if defined( _DEBUG )
  506. OleDbgAssertSz(
  507. lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n");
  508. #endif
  509. return FALSE;
  510. }
  511. // Cache a pointer to the IPersistStorage* interface. *Required*
  512. // we need this everytime we save the object.
  513. lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface(
  514. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage);
  515. if (! lpContainerLine->m_lpPersistStg) {
  516. OleDbgAssert(lpContainerLine->m_lpPersistStg);
  517. return FALSE;
  518. }
  519. // Cache a pointer to the IOleLink* interface if supported. *Optional*
  520. // if supported the object is a link. we need this to manage the link
  521. lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface(
  522. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink);
  523. if (lpContainerLine->m_lpOleLink) {
  524. OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n")
  525. lpContainerLine->m_lpOleLink->lpVtbl->GetUpdateOptions(
  526. lpContainerLine->m_lpOleLink, &lpContainerLine->m_dwLinkType);
  527. OLEDBG_END2
  528. } else
  529. lpContainerLine->m_dwLinkType = 0; // NOT a link
  530. /* get the short user type name of the object. this
  531. ** is used all the time when we have to build the object
  532. ** verb menu. we will cache this information to make it
  533. ** quicker to build the verb menu.
  534. */
  535. OleDbgAssert(lpContainerLine->m_lpszShortType == NULL);
  536. OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")
  537. CallIOleObjectGetUserTypeA(
  538. lpContainerLine->m_lpOleObj,
  539. USERCLASSTYPE_SHORT,
  540. &lpContainerLine->m_lpszShortType
  541. );
  542. OLEDBG_END2
  543. /* Perform that standard setup for the OLE object. this includes:
  544. ** setup View advise
  545. ** Call IOleObject::SetHostNames
  546. ** Call OleSetContainedObject
  547. */
  548. OleStdSetupAdvises(
  549. lpContainerLine->m_lpOleObj,
  550. dwDrawAspect,
  551. (LPSTR)APPNAME,
  552. lpOutlineDoc->m_lpszDocTitle,
  553. (LPADVISESINK)&lpContainerLine->m_AdviseSink,
  554. TRUE /*fCreate*/
  555. );
  556. #if defined( INPLACE_CNTR )
  557. /* OLE2NOTE: (INSIDE-OUT CONTAINER) An inside-out container should
  558. ** check if the object is an inside-out and prefers to be
  559. ** activated when visible type of object. if not the object
  560. ** should not be allowed to keep its window up after it gets
  561. ** UIDeactivated.
  562. */
  563. if (g_fInsideOutContainer) {
  564. DWORD mstat;
  565. OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")
  566. lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(
  567. lpContainerLine->m_lpOleObj,
  568. DVASPECT_CONTENT,
  569. (DWORD FAR*)&mstat
  570. );
  571. OLEDBG_END2
  572. lpContainerLine->m_fInsideOutObj = (BOOL)
  573. (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE));
  574. }
  575. #endif // INPLACE_CNTR
  576. if (fDisplayAsIcon) {
  577. /* user has requested to display icon aspect instead of content
  578. ** aspect.
  579. ** NOTE: we do not have to delete the previous aspect cache
  580. ** because one did not get set up.
  581. */
  582. OleStdSwitchDisplayAspect(
  583. lpContainerLine->m_lpOleObj,
  584. &lpContainerLine->m_dwDrawAspect,
  585. dwDrawAspect,
  586. hMetaPict,
  587. FALSE, /* fDeleteOldAspect */
  588. TRUE, /* fSetupViewAdvise */
  589. (LPADVISESINK)&lpContainerLine->m_AdviseSink,
  590. NULL /*fMustUpdate*/ // this can be ignored; update
  591. // for switch to icon not req'd
  592. );
  593. }
  594. return TRUE;
  595. }
  596. /* Create an ContainerLine object and return the pointer */
  597. LPCONTAINERLINE ContainerLine_Create(
  598. DWORD dwOleCreateType,
  599. HDC hDC,
  600. UINT nTab,
  601. LPCONTAINERDOC lpContainerDoc,
  602. LPCLSID lpclsid,
  603. LPSTR lpszFileName,
  604. BOOL fDisplayAsIcon,
  605. HGLOBAL hMetaPict,
  606. LPSTR lpszStgName
  607. )
  608. {
  609. LPCONTAINERLINE lpContainerLine = NULL;
  610. LPOLEOBJECT lpObj = NULL;
  611. LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc);
  612. DWORD dwDrawAspect =
  613. (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);
  614. DWORD dwOleRenderOpt =
  615. (fDisplayAsIcon ? OLERENDER_NONE : OLERENDER_DRAW);
  616. HRESULT hrErr;
  617. OLEDBG_BEGIN3("ContainerLine_Create\r\n")
  618. if (lpDocStg == NULL) {
  619. OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL");
  620. goto error;
  621. }
  622. lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));
  623. if (lpContainerLine == NULL) {
  624. OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");
  625. goto error;
  626. }
  627. ContainerLine_Init(lpContainerLine, nTab, hDC);
  628. /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to
  629. ** guard our object. if this guard is set, then the object is
  630. ** not ready to have any OLE interface methods called. it is
  631. ** necessary to guard the object this way while it is being
  632. ** created or loaded.
  633. */
  634. lpContainerLine->m_fGuardObj = TRUE;
  635. /* OLE2NOTE: In order to have a stable ContainerLine object we must
  636. ** AddRef the object's refcnt. this will be later released when
  637. ** the ContainerLine is deleted.
  638. */
  639. ContainerLine_AddRef(lpContainerLine);
  640. lstrcpy(lpContainerLine->m_szStgName, lpszStgName);
  641. lpContainerLine->m_lpDoc = lpContainerDoc;
  642. /* Create a new storage for the object inside the doc's storage */
  643. lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName);
  644. if (lpContainerLine->m_lpStg == NULL) {
  645. OleDbgAssert(lpContainerLine->m_lpStg != NULL);
  646. goto error;
  647. }
  648. lpContainerLine->m_dwLinkType = 0;
  649. switch (dwOleCreateType) {
  650. case IOF_SELECTCREATENEW:
  651. OLEDBG_BEGIN2("OleCreate called\r\n")
  652. hrErr = OleCreate (
  653. lpclsid,
  654. &IID_IOleObject,
  655. dwOleRenderOpt,
  656. NULL,
  657. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  658. lpContainerLine->m_lpStg,
  659. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  660. );
  661. OLEDBG_END2
  662. #if defined( _DEBUG )
  663. if (hrErr != NOERROR)
  664. OleDbgOutHResult("OleCreate returned", hrErr);
  665. #endif
  666. break;
  667. case IOF_SELECTCREATEFROMFILE:
  668. OLEDBG_BEGIN2("OleCreateFromFile called\r\n")
  669. hrErr = OleCreateFromFileA(
  670. &CLSID_NULL,
  671. lpszFileName,
  672. &IID_IOleObject,
  673. dwOleRenderOpt,
  674. NULL,
  675. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  676. lpContainerLine->m_lpStg,
  677. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  678. );
  679. OLEDBG_END2
  680. #if defined( _DEBUG )
  681. if (hrErr != NOERROR)
  682. OleDbgOutHResult("OleCreateFromFile returned", hrErr);
  683. #endif
  684. break;
  685. case IOF_CHECKLINK:
  686. OLEDBG_BEGIN2("OleCreateLinkToFile called\r\n")
  687. hrErr = OleCreateLinkToFileA(
  688. lpszFileName,
  689. &IID_IOleObject,
  690. dwOleRenderOpt,
  691. NULL,
  692. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  693. lpContainerLine->m_lpStg,
  694. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  695. );
  696. OLEDBG_END2
  697. #if defined( _DEBUG )
  698. if (hrErr != NOERROR)
  699. OleDbgOutHResult("OleCreateLinkToFile returned", hrErr);
  700. #endif
  701. break;
  702. }
  703. if (hrErr != NOERROR)
  704. goto error;
  705. if (! ContainerLine_SetupOleObject(
  706. lpContainerLine, fDisplayAsIcon, hMetaPict)) {
  707. goto error;
  708. }
  709. /* OLE2NOTE: clear our re-entrancy guard. the object is now ready
  710. ** to have interface methods called.
  711. */
  712. lpContainerLine->m_fGuardObj = FALSE;
  713. OLEDBG_END3
  714. return lpContainerLine;
  715. error:
  716. OutlineApp_ErrorMessage(g_lpApp, "Could not create object!");
  717. // Destroy partially created OLE object
  718. if (lpContainerLine)
  719. ContainerLine_Delete(lpContainerLine);
  720. OLEDBG_END3
  721. return NULL;
  722. }
  723. LPCONTAINERLINE ContainerLine_CreateFromData(
  724. HDC hDC,
  725. UINT nTab,
  726. LPCONTAINERDOC lpContainerDoc,
  727. LPDATAOBJECT lpSrcDataObj,
  728. DWORD dwCreateType,
  729. CLIPFORMAT cfFormat,
  730. BOOL fDisplayAsIcon,
  731. HGLOBAL hMetaPict,
  732. LPSTR lpszStgName
  733. )
  734. {
  735. HGLOBAL hData = NULL;
  736. LPCONTAINERLINE lpContainerLine = NULL;
  737. LPOLEOBJECT lpObj = NULL;
  738. LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc);
  739. DWORD dwDrawAspect =
  740. (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);
  741. DWORD dwOleRenderOpt;
  742. FORMATETC renderFmtEtc;
  743. LPFORMATETC lpRenderFmtEtc = NULL;
  744. HRESULT hrErr;
  745. LPUNKNOWN lpUnk = NULL;
  746. OLEDBG_BEGIN3("ContainerLine_CreateFromData\r\n")
  747. if (dwCreateType == OLECREATEFROMDATA_STATIC && cfFormat != 0) {
  748. // a particular type of static object should be created
  749. dwOleRenderOpt = OLERENDER_FORMAT;
  750. lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;
  751. if (cfFormat == CF_METAFILEPICT)
  752. SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_MFPICT);
  753. else if (cfFormat == CF_BITMAP)
  754. SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_GDI);
  755. else
  756. SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_HGLOBAL);
  757. } else if (dwCreateType == OLECREATEFROMDATA_STATIC && fDisplayAsIcon) {
  758. // a link that currently displayed as an icon needs to be
  759. // converted to a STATIC picture object. this case is driven
  760. // from "BreakLink" in the "Links" dialog. because the current
  761. // data in the source object's cache is DVASPECT_ICON we need
  762. // to tell the OleCreateStaticFromData API to look for
  763. // DVASPECT_ICON data. the static object that results however,
  764. // is considered to be displayed in the DVASPECT_CONTENT view.
  765. dwOleRenderOpt = OLERENDER_DRAW;
  766. lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;
  767. SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);
  768. dwDrawAspect = DVASPECT_CONTENT; // static obj displays only CONTENT
  769. } else if (fDisplayAsIcon && hMetaPict) {
  770. // a special icon should be used. first we create the object
  771. // OLERENDER_NONE and then we stuff the special icon into the cache.
  772. dwOleRenderOpt = OLERENDER_NONE;
  773. } else if (fDisplayAsIcon && hMetaPict == NULL) {
  774. // the object's default icon should be used
  775. dwOleRenderOpt = OLERENDER_DRAW;
  776. lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;
  777. SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);
  778. } else {
  779. // create standard DVASPECT_CONTENT/OLERENDER_DRAW object
  780. dwOleRenderOpt = OLERENDER_DRAW;
  781. }
  782. if (lpDocStg == NULL) {
  783. OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL");
  784. goto error;
  785. }
  786. lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));
  787. if (lpContainerLine == NULL) {
  788. OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");
  789. goto error;
  790. }
  791. ContainerLine_Init(lpContainerLine, nTab, hDC);
  792. /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to
  793. ** guard our object. if this guard is set, then the object is
  794. ** not ready to have any OLE interface methods called. it is
  795. ** necessary to guard the object this way while it is being
  796. ** created or loaded.
  797. */
  798. lpContainerLine->m_fGuardObj = TRUE;
  799. /* OLE2NOTE: In order to have a stable ContainerLine object we must
  800. ** AddRef the object's refcnt. this will be later released when
  801. ** the ContainerLine is deleted.
  802. */
  803. ContainerLine_AddRef(lpContainerLine);
  804. lstrcpy(lpContainerLine->m_szStgName, lpszStgName);
  805. lpContainerLine->m_lpDoc = lpContainerDoc;
  806. /* Create a new storage for the object inside the doc's storage */
  807. lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName);
  808. if (lpContainerLine->m_lpStg == NULL) {
  809. OleDbgAssert(lpContainerLine->m_lpStg != NULL);
  810. goto error;
  811. }
  812. switch (dwCreateType) {
  813. case OLECREATEFROMDATA_LINK:
  814. OLEDBG_BEGIN2("OleCreateLinkFromData called\r\n")
  815. hrErr = OleCreateLinkFromData (
  816. lpSrcDataObj,
  817. &IID_IOleObject,
  818. dwOleRenderOpt,
  819. lpRenderFmtEtc,
  820. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  821. lpContainerLine->m_lpStg,
  822. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  823. );
  824. OLEDBG_END2
  825. #if defined( _DEBUG )
  826. if (hrErr != NOERROR)
  827. OleDbgOutHResult("OleCreateLinkFromData returned", hrErr);
  828. #endif
  829. break;
  830. case OLECREATEFROMDATA_OBJECT:
  831. OLEDBG_BEGIN2("OleCreateFromData called\r\n")
  832. hrErr = OleCreateFromData (
  833. lpSrcDataObj,
  834. &IID_IOleObject,
  835. dwOleRenderOpt,
  836. lpRenderFmtEtc,
  837. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  838. lpContainerLine->m_lpStg,
  839. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  840. );
  841. OLEDBG_END2
  842. #if defined( _DEBUG )
  843. if (hrErr != NOERROR)
  844. OleDbgOutHResult("OleCreateFromData returned", hrErr);
  845. #endif
  846. break;
  847. case OLECREATEFROMDATA_STATIC:
  848. OLEDBG_BEGIN2("OleCreateStaticFromData called\r\n")
  849. hrErr = OleCreateStaticFromData (
  850. lpSrcDataObj,
  851. &IID_IOleObject,
  852. dwOleRenderOpt,
  853. lpRenderFmtEtc,
  854. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  855. lpContainerLine->m_lpStg,
  856. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  857. );
  858. OLEDBG_END2
  859. #if defined( _DEBUG )
  860. if (hrErr != NOERROR)
  861. OleDbgOutHResult("OleCreateStaticFromData returned", hrErr);
  862. #endif
  863. break;
  864. }
  865. if (hrErr != NOERROR)
  866. goto error;
  867. if (! ContainerLine_SetupOleObject(
  868. lpContainerLine, fDisplayAsIcon, hMetaPict)) {
  869. goto error;
  870. }
  871. /* OLE2NOTE: clear our re-entrancy guard. the object is now ready
  872. ** to have interface methods called.
  873. */
  874. lpContainerLine->m_fGuardObj = FALSE;
  875. OLEDBG_END3
  876. return lpContainerLine;
  877. error:
  878. OutlineApp_ErrorMessage(g_lpApp, "Could not create object!");
  879. // Destroy partially created OLE object
  880. if (lpContainerLine)
  881. ContainerLine_Delete(lpContainerLine);
  882. OLEDBG_END3
  883. return NULL;
  884. }
  885. /* ContainerLine_AddRef
  886. ** --------------------
  887. **
  888. ** increment the ref count of the line object.
  889. **
  890. ** Returns the new ref count on the object
  891. */
  892. ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine)
  893. {
  894. ++lpContainerLine->m_cRef;
  895. #if defined( _DEBUG )
  896. OleDbgOutRefCnt4(
  897. "ContainerLine_AddRef: cRef++\r\n",
  898. lpContainerLine,
  899. lpContainerLine->m_cRef
  900. );
  901. #endif
  902. return lpContainerLine->m_cRef;
  903. }
  904. /* ContainerLine_Release
  905. ** ---------------------
  906. **
  907. ** decrement the ref count of the line object.
  908. ** if the ref count goes to 0, then the line is destroyed.
  909. **
  910. ** Returns the remaining ref count on the object
  911. */
  912. ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine)
  913. {
  914. ULONG cRef;
  915. /*********************************************************************
  916. ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. **
  917. ** otherwise the object is still in use. **
  918. *********************************************************************/
  919. cRef = --lpContainerLine->m_cRef;
  920. #if defined( _DEBUG )
  921. OleDbgAssertSz(
  922. lpContainerLine->m_cRef >= 0,"Release called with cRef == 0");
  923. OleDbgOutRefCnt4(
  924. "ContainerLine_Release: cRef--\r\n",
  925. lpContainerLine,
  926. cRef
  927. );
  928. #endif
  929. if (cRef == 0)
  930. ContainerLine_Destroy(lpContainerLine);
  931. return cRef;
  932. }
  933. /* ContainerLine_QueryInterface
  934. ** ----------------------------
  935. **
  936. ** Retrieve a pointer to an interface on the ContainerLine object.
  937. **
  938. ** Returns NOERROR if interface is successfully retrieved.
  939. ** E_NOINTERFACE if the interface is not supported
  940. */
  941. HRESULT ContainerLine_QueryInterface(
  942. LPCONTAINERLINE lpContainerLine,
  943. REFIID riid,
  944. LPVOID FAR* lplpvObj
  945. )
  946. {
  947. SCODE sc = E_NOINTERFACE;
  948. /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */
  949. *lplpvObj = NULL;
  950. if (IsEqualIID(riid, &IID_IUnknown)) {
  951. OleDbgOut4("ContainerLine_QueryInterface: IUnknown* RETURNED\r\n");
  952. *lplpvObj = (LPVOID) &lpContainerLine->m_Unknown;
  953. ContainerLine_AddRef(lpContainerLine);
  954. sc = S_OK;
  955. }
  956. else if (IsEqualIID(riid, &IID_IOleClientSite)) {
  957. OleDbgOut4("ContainerLine_QueryInterface: IOleClientSite* RETURNED\r\n");
  958. *lplpvObj = (LPVOID) &lpContainerLine->m_OleClientSite;
  959. ContainerLine_AddRef(lpContainerLine);
  960. sc = S_OK;
  961. }
  962. else if (IsEqualIID(riid, &IID_IAdviseSink)) {
  963. OleDbgOut4("ContainerLine_QueryInterface: IAdviseSink* RETURNED\r\n");
  964. *lplpvObj = (LPVOID) &lpContainerLine->m_AdviseSink;
  965. ContainerLine_AddRef(lpContainerLine);
  966. sc = S_OK;
  967. }
  968. #if defined( INPLACE_CNTR )
  969. else if (IsEqualIID(riid, &IID_IOleWindow)
  970. || IsEqualIID(riid, &IID_IOleInPlaceSite)) {
  971. OleDbgOut4("ContainerLine_QueryInterface: IOleInPlaceSite* RETURNED\r\n");
  972. *lplpvObj = (LPVOID) &lpContainerLine->m_OleInPlaceSite;
  973. ContainerLine_AddRef(lpContainerLine);
  974. sc = S_OK;
  975. }
  976. #endif // INPLACE_CNTR
  977. OleDbgQueryInterfaceMethod(*lplpvObj);
  978. return ResultFromScode(sc);
  979. }
  980. BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine)
  981. {
  982. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  983. LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerLine->m_lpDoc);
  984. LPOLECLIENTSITE lpOleClientSite;
  985. LPMONIKER lpmkObj;
  986. LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
  987. BOOL fPrevEnable1;
  988. BOOL fPrevEnable2;
  989. HRESULT hrErr;
  990. if (lpContainerLine->m_fGuardObj)
  991. return FALSE; // object in process of creation
  992. if (lpContainerLine->m_lpOleObj)
  993. return TRUE; // object already loaded
  994. OLEDBG_BEGIN3("ContainerLine_LoadOleObject\r\n")
  995. /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to
  996. ** guard our object. if this guard is set, then the object is
  997. ** not ready to have any OLE interface methods called. it is
  998. ** necessary to guard the object this way while it is being
  999. ** created or loaded.
  1000. */
  1001. lpContainerLine->m_fGuardObj = TRUE;
  1002. /* if object storage is not already open, then open it */
  1003. if (! lpContainerLine->m_lpStg) {
  1004. lpContainerLine->m_lpStg = OleStdOpenChildStorage(
  1005. lpDocStg,
  1006. lpContainerLine->m_szStgName,
  1007. STGM_READWRITE
  1008. );
  1009. if (lpContainerLine->m_lpStg == NULL) {
  1010. OleDbgAssert(lpContainerLine->m_lpStg != NULL);
  1011. goto error;
  1012. }
  1013. }
  1014. /* OLE2NOTE: if the OLE object being loaded is in a data transfer
  1015. ** document, then we should NOT pass a IOleClientSite* pointer
  1016. ** to the OleLoad call. This particularly critical if the OLE
  1017. ** object is an OleLink object. If a non-NULL client site is
  1018. ** passed to the OleLoad function, then the link will bind to
  1019. ** the source if its is running. in the situation that we are
  1020. ** loading the object as part of a data transfer document we do
  1021. ** not want this connection to be established. even worse, if
  1022. ** the link source is currently blocked or busy, then this could
  1023. ** hang the system. it is simplest to never pass a
  1024. ** IOleClientSite* when loading an object in a data transfer
  1025. ** document.
  1026. */
  1027. lpOleClientSite = (lpOutlineDoc->m_fDataTransferDoc ?
  1028. NULL : (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite);
  1029. /* OLE2NOTE: we do not want to ever give the Busy/NotResponding
  1030. ** dialogs when we are loading an object. if the object is a
  1031. ** link, it will attempt to BindIfRunning to the link source. if
  1032. ** the link source is currently busy, this could cause the Busy
  1033. ** dialog to come up. even if the link source is busy,
  1034. ** we do not want put up the busy dialog. thus we will disable
  1035. ** the dialog and later re-enable them
  1036. */
  1037. OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);
  1038. OLEDBG_BEGIN2("OleLoad called\r\n")
  1039. hrErr = OleLoad (
  1040. lpContainerLine->m_lpStg,
  1041. &IID_IOleObject,
  1042. lpOleClientSite,
  1043. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  1044. );
  1045. OLEDBG_END2
  1046. // re-enable the Busy/NotResponding dialogs
  1047. OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);
  1048. if (hrErr != NOERROR) {
  1049. OleDbgAssertSz(hrErr == NOERROR, "Could not load object!");
  1050. OleDbgOutHResult("OleLoad returned", hrErr);
  1051. goto error;
  1052. }
  1053. /* Cache a pointer to the IViewObject2* interface. *Required*
  1054. ** we need this everytime we draw the object.
  1055. **
  1056. ** OLE2NOTE: We require the object to support IViewObject2
  1057. ** interface. this is an extension to the IViewObject interface
  1058. ** that was added with the OLE 2.01 release. This interface must
  1059. ** be supported by all object handlers and DLL-based objects.
  1060. */
  1061. lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(
  1062. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2);
  1063. if (! lpContainerLine->m_lpViewObj2) {
  1064. #if defined( _DEBUG )
  1065. OleDbgAssertSz(
  1066. lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n");
  1067. #endif
  1068. goto error;
  1069. }
  1070. // Cache a pointer to the IPersistStorage* interface. *Required*
  1071. // we need this everytime we save the object.
  1072. lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface(
  1073. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage);
  1074. if (! lpContainerLine->m_lpPersistStg) {
  1075. OleDbgAssert(lpContainerLine->m_lpPersistStg);
  1076. goto error;
  1077. }
  1078. // Cache a pointer to the IOleLink* interface if supported. *Optional*
  1079. // if supported the object is a link. we need this to manage the link
  1080. if (lpContainerLine->m_dwLinkType != 0) {
  1081. lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface(
  1082. (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink);
  1083. if (! lpContainerLine->m_lpOleLink) {
  1084. OleDbgAssert(lpContainerLine->m_lpOleLink);
  1085. goto error;
  1086. }
  1087. }
  1088. /* OLE2NOTE: clear our re-entrancy guard. the object is now ready
  1089. ** to have interface methods called.
  1090. */
  1091. lpContainerLine->m_fGuardObj = FALSE;
  1092. /* OLE2NOTE: similarly, if the OLE object being loaded is in a data
  1093. ** transfer document, then we do NOT need to setup any advises,
  1094. ** call SetHostNames, SetMoniker, etc.
  1095. */
  1096. if (lpOleClientSite) {
  1097. /* Setup the Advises (OLE notifications) that we are interested
  1098. ** in receiving.
  1099. */
  1100. OleStdSetupAdvises(
  1101. lpContainerLine->m_lpOleObj,
  1102. lpContainerLine->m_dwDrawAspect,
  1103. (LPSTR)APPNAME,
  1104. lpOutlineDoc->m_lpszDocTitle,
  1105. (LPADVISESINK)&lpContainerLine->m_AdviseSink,
  1106. FALSE /*fCreate*/
  1107. );
  1108. /* OLE2NOTE: if the OLE object has a moniker assigned, we need to
  1109. ** inform the object by calling IOleObject::SetMoniker. this
  1110. ** will force the OLE object to register in the
  1111. ** RunningObjectTable when it enters the running state.
  1112. */
  1113. if (lpContainerLine->m_fMonikerAssigned) {
  1114. lpmkObj = ContainerLine_GetRelMoniker(
  1115. lpContainerLine,
  1116. GETMONIKER_ONLYIFTHERE
  1117. );
  1118. if (lpmkObj) {
  1119. OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n")
  1120. lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(
  1121. lpContainerLine->m_lpOleObj,
  1122. OLEWHICHMK_OBJREL,
  1123. lpmkObj
  1124. );
  1125. OLEDBG_END2
  1126. OleStdRelease((LPUNKNOWN)lpmkObj);
  1127. }
  1128. }
  1129. /* get the Short form of the user type name of the object. this
  1130. ** is used all the time when we have to build the object
  1131. ** verb menu. we will cache this information to make it
  1132. ** quicker to build the verb menu.
  1133. */
  1134. OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")
  1135. CallIOleObjectGetUserTypeA(
  1136. lpContainerLine->m_lpOleObj,
  1137. USERCLASSTYPE_SHORT,
  1138. &lpContainerLine->m_lpszShortType
  1139. );
  1140. OLEDBG_END2
  1141. #if defined( INPLACE_CNTR )
  1142. /* OLE2NOTE: an inside-out container should check if the object
  1143. ** is an inside-out and prefers to be activated when visible
  1144. ** type of object. if so, the object should be immediately
  1145. ** activated in-place, BUT NOT UIActived.
  1146. */
  1147. if (g_fInsideOutContainer &&
  1148. lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) {
  1149. DWORD mstat;
  1150. OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")
  1151. lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(
  1152. lpContainerLine->m_lpOleObj,
  1153. DVASPECT_CONTENT,
  1154. (DWORD FAR*)&mstat
  1155. );
  1156. OLEDBG_END2
  1157. lpContainerLine->m_fInsideOutObj = (BOOL)
  1158. (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE));
  1159. if ( lpContainerLine->m_fInsideOutObj ) {
  1160. HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc);
  1161. ContainerLine_DoVerb(
  1162. lpContainerLine,
  1163. OLEIVERB_INPLACEACTIVATE,
  1164. NULL,
  1165. FALSE,
  1166. FALSE
  1167. );
  1168. /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the
  1169. ** object may have taken focus. but because the
  1170. ** object is NOT UIActive it should NOT have focus.
  1171. ** we will make sure our document has focus.
  1172. */
  1173. SetFocus(hWndDoc);
  1174. }
  1175. }
  1176. #endif // INPLACE_CNTR
  1177. OLEDBG_END2
  1178. }
  1179. OLEDBG_END2
  1180. return TRUE;
  1181. error:
  1182. OLEDBG_END2
  1183. return FALSE;
  1184. }
  1185. /* ContainerLine_CloseOleObject
  1186. ** ----------------------------
  1187. ** Close the OLE object associated with the ContainerLine.
  1188. **
  1189. ** Closing the object forces the object to transition from the
  1190. ** running state to the loaded state. if the object was not running,
  1191. ** then there is no effect. it is necessary to close the OLE object
  1192. ** before releasing the pointers to the OLE object.
  1193. **
  1194. ** Returns TRUE if successfully closed,
  1195. ** FALSE if closing was aborted.
  1196. */
  1197. BOOL ContainerLine_CloseOleObject(
  1198. LPCONTAINERLINE lpContainerLine,
  1199. DWORD dwSaveOption
  1200. )
  1201. {
  1202. HRESULT hrErr;
  1203. SCODE sc;
  1204. if (lpContainerLine->m_fGuardObj)
  1205. return FALSE; // object in process of creation
  1206. if (! lpContainerLine->m_lpOleObj)
  1207. return TRUE; // object is NOT loaded
  1208. OLEDBG_BEGIN2("IOleObject::Close called\r\n")
  1209. hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Close(
  1210. lpContainerLine->m_lpOleObj,
  1211. (dwSaveOption == OLECLOSE_NOSAVE ?
  1212. OLECLOSE_NOSAVE : OLECLOSE_SAVEIFDIRTY)
  1213. );
  1214. OLEDBG_END2
  1215. #if defined( INPLACE_CNTR )
  1216. if (lpContainerLine->m_fIpServerRunning) {
  1217. /* OLE2NOTE: unlock the lock held on the in-place object.
  1218. ** it is VERY important that an in-place container
  1219. ** that also support linking to embeddings properly manage
  1220. ** the running of its in-place objects. in an outside-in
  1221. ** style in-place container, when the user clicks
  1222. ** outside of the in-place active object, the object gets
  1223. ** UIDeactivated and the object hides its window. in order
  1224. ** to make the object fast to reactivate, the container
  1225. ** deliberately does not call IOleObject::Close. the object
  1226. ** stays running in the invisible unlocked state. the idea
  1227. ** here is if the user simply clicks outside of the object
  1228. ** and then wants to double click again to re-activate the
  1229. ** object, we do not want this to be slow. if we want to
  1230. ** keep the object running, however, we MUST Lock it
  1231. ** running. otherwise the object will be in an unstable
  1232. ** state where if a linking client does a "silent-update"
  1233. ** (eg. UpdateNow from the Links dialog), then the in-place
  1234. ** server will shut down even before the object has a chance
  1235. ** to be saved back in its container. this saving normally
  1236. ** occurs when the in-place container closes the object. also
  1237. ** keeping the object in the unstable, hidden, running,
  1238. ** not-locked state can cause problems in some scenarios.
  1239. ** ICntrOtl keeps only one object running. if the user
  1240. ** intiates a DoVerb on another object, then that last
  1241. ** running in-place active object is closed. a more
  1242. ** sophistocated in-place container may keep more object running.
  1243. ** (see CntrLine_IPSite_OnInPlaceActivate)
  1244. */
  1245. lpContainerLine->m_fIpServerRunning = FALSE;
  1246. OLEDBG_BEGIN2("OleLockRunning(FALSE,TRUE) called\r\n")
  1247. OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleObj, FALSE, TRUE);
  1248. OLEDBG_END2
  1249. }
  1250. #endif
  1251. if (hrErr != NOERROR) {
  1252. OleDbgOutHResult("IOleObject::Close returned", hrErr);
  1253. sc = GetScode(hrErr);
  1254. if (sc == RPC_E_CALL_REJECTED || sc==OLE_E_PROMPTSAVECANCELLED)
  1255. return FALSE; // object aborted shutdown
  1256. }
  1257. return TRUE;
  1258. }
  1259. /* ContainerLine_UnloadOleObject
  1260. ** -----------------------------
  1261. ** Close the OLE object associated with the ContainerLine and
  1262. ** release all pointer held to the object.
  1263. **
  1264. ** Closing the object forces the object to transition from the
  1265. ** running state to the loaded state. if the object was not running,
  1266. ** then there is no effect. it is necessary to close the OLE object
  1267. ** before releasing the pointers to the OLE object. releasing all
  1268. ** pointers to the object allows the object to transition from
  1269. ** loaded to unloaded (or passive).
  1270. */
  1271. void ContainerLine_UnloadOleObject(
  1272. LPCONTAINERLINE lpContainerLine,
  1273. DWORD dwSaveOption
  1274. )
  1275. {
  1276. if (lpContainerLine->m_lpOleObj) {
  1277. OLEDBG_BEGIN2("IOleObject::Close called\r\n")
  1278. lpContainerLine->m_lpOleObj->lpVtbl->Close(
  1279. lpContainerLine->m_lpOleObj, dwSaveOption);
  1280. OLEDBG_END2
  1281. /* OLE2NOTE: we will take our IOleClientSite* pointer away from
  1282. ** the object before we release all pointers to the object.
  1283. ** in the scenario where the object is implemented as an
  1284. ** in-proc server (DLL object), then, if there are link
  1285. ** connections to the DLL object, it is possible that the
  1286. ** object will not be destroyed when we release our pointers
  1287. ** to the object. the existance of the remote link
  1288. ** connections will hold the object alive. later when these
  1289. ** strong connections are released, then the object may
  1290. ** attempt to call IOleClientSite::Save if we had not taken
  1291. ** away the client site pointer.
  1292. */
  1293. OLEDBG_BEGIN2("IOleObject::SetClientSite(NULL) called\r\n")
  1294. lpContainerLine->m_lpOleObj->lpVtbl->SetClientSite(
  1295. lpContainerLine->m_lpOleObj, NULL);
  1296. OLEDBG_END2
  1297. OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleObj);
  1298. lpContainerLine->m_lpOleObj = NULL;
  1299. if (lpContainerLine->m_lpViewObj2) {
  1300. OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpViewObj2);
  1301. lpContainerLine->m_lpViewObj2 = NULL;
  1302. }
  1303. if (lpContainerLine->m_lpPersistStg) {
  1304. OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpPersistStg);
  1305. lpContainerLine->m_lpPersistStg = NULL;
  1306. }
  1307. if (lpContainerLine->m_lpOleLink) {
  1308. OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleLink);
  1309. lpContainerLine->m_lpOleLink = NULL;
  1310. }
  1311. }
  1312. if (lpContainerLine->m_lpszShortType) {
  1313. OleStdFreeString(lpContainerLine->m_lpszShortType, NULL);
  1314. lpContainerLine->m_lpszShortType = NULL;
  1315. }
  1316. }
  1317. /* ContainerLine_Delete
  1318. ** --------------------
  1319. ** Delete the ContainerLine.
  1320. **
  1321. ** NOTE: we can NOT directly destroy the memory for the
  1322. ** ContainerLine; the ContainerLine maintains a reference count. a
  1323. ** non-zero reference count indicates that the object is still
  1324. ** in-use. The OleObject keeps a reference-counted pointer to the
  1325. ** ClientLine object. we must take the actions necessary so that the
  1326. ** ContainerLine object receives Releases for outstanding
  1327. ** references. when the reference count of the ContainerLine reaches
  1328. ** zero, then the memory for the object will actually be destroyed
  1329. ** (ContainerLine_Destroy called).
  1330. **
  1331. */
  1332. void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine)
  1333. {
  1334. OLEDBG_BEGIN2("ContainerLine_Delete\r\n")
  1335. #if defined( INPLACE_CNTR )
  1336. if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastIpActiveLine)
  1337. lpContainerLine->m_lpDoc->m_lpLastIpActiveLine = NULL;
  1338. if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine)
  1339. lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL;
  1340. #endif
  1341. /* OLE2NOTE: in order to have a stable line object during the
  1342. ** process of deleting, we intially AddRef the line ref cnt and
  1343. ** later Release it. This initial AddRef is artificial; it is
  1344. ** simply done to guarantee that our object does not destroy
  1345. ** itself until the END of this routine.
  1346. */
  1347. ContainerLine_AddRef(lpContainerLine);
  1348. // Unload the loaded OLE object
  1349. if (lpContainerLine->m_lpOleObj)
  1350. ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_NOSAVE);
  1351. /* OLE2NOTE: we can NOT directly free the memory for the ContainerLine
  1352. ** data structure until everyone holding on to a pointer to our
  1353. ** ClientSite interface and IAdviseSink interface has released
  1354. ** their pointers. There is one refcnt on the ContainerLine object
  1355. ** which is held by the container itself. we will release this
  1356. ** refcnt here.
  1357. */
  1358. ContainerLine_Release(lpContainerLine);
  1359. /* OLE2NOTE: this call forces all external connections to our
  1360. ** ContainerLine to close down and therefore guarantees that
  1361. ** we receive all releases associated with those external
  1362. ** connections. Strictly this call should NOT be necessary, but
  1363. ** it is defensive coding to make this call.
  1364. */
  1365. OLEDBG_BEGIN2("CoDisconnectObject(lpContainerLine) called\r\n")
  1366. CoDisconnectObject((LPUNKNOWN)&lpContainerLine->m_Unknown, 0);
  1367. OLEDBG_END2
  1368. #if defined( _DEBUG )
  1369. /* at this point the object all references from the OLE object to
  1370. ** our ContainerLine object should have been released. there
  1371. ** should only be 1 remaining reference that will be released below.
  1372. */
  1373. if (lpContainerLine->m_cRef != 1) {
  1374. OleDbgOutRefCnt(
  1375. "WARNING: ContainerLine_Delete: cRef != 1\r\n",
  1376. lpContainerLine,
  1377. lpContainerLine->m_cRef
  1378. );
  1379. }
  1380. #endif
  1381. ContainerLine_Release(lpContainerLine); // release artificial AddRef above
  1382. OLEDBG_END2
  1383. }
  1384. /* ContainerLine_Destroy
  1385. ** ---------------------
  1386. ** Destroy (Free) the memory used by a ContainerLine structure.
  1387. ** This function is called when the ref count of the ContainerLine goes
  1388. ** to zero. the ref cnt goes to zero after ContainerLine_Delete forces
  1389. ** the OleObject to unload and release its pointers to the
  1390. ** ContainerLine IOleClientSite and IAdviseSink interfaces.
  1391. */
  1392. void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine)
  1393. {
  1394. LPUNKNOWN lpTmpObj;
  1395. OLEDBG_BEGIN2("ContainerLine_Destroy\r\n")
  1396. // Release the storage opened for the OLE object
  1397. if (lpContainerLine->m_lpStg) {
  1398. lpTmpObj = (LPUNKNOWN)lpContainerLine->m_lpStg;
  1399. lpContainerLine->m_lpStg = NULL;
  1400. OleStdRelease(lpTmpObj);
  1401. }
  1402. if (lpContainerLine->m_lpszShortType) {
  1403. OleStdFreeString(lpContainerLine->m_lpszShortType, NULL);
  1404. lpContainerLine->m_lpszShortType = NULL;
  1405. }
  1406. Delete(lpContainerLine); // Free the memory for the structure itself
  1407. OLEDBG_END2
  1408. }
  1409. /* ContainerLine_CopyToDoc
  1410. * -----------------------
  1411. *
  1412. * Copy a ContainerLine to another Document (usually ClipboardDoc)
  1413. */
  1414. BOOL ContainerLine_CopyToDoc(
  1415. LPCONTAINERLINE lpSrcLine,
  1416. LPOUTLINEDOC lpDestDoc,
  1417. int nIndex
  1418. )
  1419. {
  1420. LPCONTAINERLINE lpDestLine = NULL;
  1421. LPLINELIST lpDestLL = &lpDestDoc->m_LineList;
  1422. HDC hDC;
  1423. HRESULT hrErr;
  1424. BOOL fStatus;
  1425. LPSTORAGE lpDestDocStg = ((LPOLEDOC)lpDestDoc)->m_lpStg;
  1426. LPSTORAGE lpDestObjStg = NULL;
  1427. lpDestLine = (LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));
  1428. if (lpDestLine == NULL) {
  1429. OleDbgAssertSz(lpDestLine!=NULL, "Error allocating ContainerLine");
  1430. return FALSE;
  1431. }
  1432. hDC = LineList_GetDC(lpDestLL);
  1433. ContainerLine_Init(lpDestLine, ((LPLINE)lpSrcLine)->m_nTabLevel, hDC);
  1434. LineList_ReleaseDC(lpDestLL, hDC);
  1435. /* OLE2NOTE: In order to have a stable ContainerLine object we must
  1436. ** AddRef the object's refcnt. this will be later released when
  1437. ** the ContainerLine is deleted.
  1438. */
  1439. ContainerLine_AddRef(lpDestLine);
  1440. lpDestLine->m_lpDoc = (LPCONTAINERDOC)lpDestDoc;
  1441. // Copy data of the original source ContainerLine.
  1442. ((LPLINE)lpDestLine)->m_nWidthInHimetric =
  1443. ((LPLINE)lpSrcLine)->m_nWidthInHimetric;
  1444. ((LPLINE)lpDestLine)->m_nHeightInHimetric =
  1445. ((LPLINE)lpSrcLine)->m_nHeightInHimetric;
  1446. lpDestLine->m_fMonikerAssigned = lpSrcLine->m_fMonikerAssigned;
  1447. lpDestLine->m_dwDrawAspect = lpSrcLine->m_dwDrawAspect;
  1448. lpDestLine->m_sizeInHimetric = lpSrcLine->m_sizeInHimetric;
  1449. lpDestLine->m_dwLinkType = lpSrcLine->m_dwLinkType;
  1450. /* We must create a new sub-storage for the embedded object within
  1451. ** the destination document's storage. We will first attempt to
  1452. ** use the same storage name as the source line. if this name is
  1453. ** in use, then we will allocate a new name. in this way we try
  1454. ** to keep the name associated with the OLE object unchanged
  1455. ** through a Cut/Paste operation.
  1456. */
  1457. lpDestObjStg = OleStdCreateChildStorage(
  1458. lpDestDocStg,
  1459. lpSrcLine->m_szStgName
  1460. );
  1461. if (lpDestObjStg) {
  1462. lstrcpy(lpDestLine->m_szStgName, lpSrcLine->m_szStgName);
  1463. } else {
  1464. /* the original name was in use, make up a new name. */
  1465. ContainerDoc_GetNextStgName(
  1466. (LPCONTAINERDOC)lpDestDoc,
  1467. lpDestLine->m_szStgName,
  1468. sizeof(lpDestLine->m_szStgName)
  1469. );
  1470. lpDestObjStg = OleStdCreateChildStorage(
  1471. lpDestDocStg,
  1472. lpDestLine->m_szStgName
  1473. );
  1474. }
  1475. if (lpDestObjStg == NULL) {
  1476. OleDbgAssertSz(lpDestObjStg != NULL, "Error creating child stg");
  1477. goto error;
  1478. }
  1479. // Copy over storage of the embedded object itself
  1480. if (! lpSrcLine->m_lpOleObj) {
  1481. /*****************************************************************
  1482. ** CASE 1: object is NOT loaded.
  1483. ** because the object is not loaded, we can simply copy the
  1484. ** object's current storage to the new storage.
  1485. *****************************************************************/
  1486. /* if current object storage is not already open, then open it */
  1487. if (! lpSrcLine->m_lpStg) {
  1488. LPSTORAGE lpSrcDocStg = ((LPOLEDOC)lpSrcLine->m_lpDoc)->m_lpStg;
  1489. if (! lpSrcDocStg) goto error;
  1490. // open object storage.
  1491. lpSrcLine->m_lpStg = OleStdOpenChildStorage(
  1492. lpSrcDocStg,
  1493. lpSrcLine->m_szStgName,
  1494. STGM_READWRITE
  1495. );
  1496. if (lpSrcLine->m_lpStg == NULL) {
  1497. #if defined( _DEBUG )
  1498. OleDbgAssertSz(
  1499. lpSrcLine->m_lpStg != NULL,
  1500. "Error opening child stg"
  1501. );
  1502. #endif
  1503. goto error;
  1504. }
  1505. }
  1506. hrErr = lpSrcLine->m_lpStg->lpVtbl->CopyTo(
  1507. lpSrcLine->m_lpStg,
  1508. 0,
  1509. NULL,
  1510. NULL,
  1511. lpDestObjStg
  1512. );
  1513. if (hrErr != NOERROR) {
  1514. OleDbgOutHResult("WARNING: lpSrcObjStg->CopyTo returned", hrErr);
  1515. goto error;
  1516. }
  1517. fStatus = OleStdCommitStorage(lpDestObjStg);
  1518. } else {
  1519. /*****************************************************************
  1520. ** CASE 2: object IS loaded.
  1521. ** we must tell the object to save into the new storage.
  1522. *****************************************************************/
  1523. SCODE sc = S_OK;
  1524. LPPERSISTSTORAGE lpPersistStg = lpSrcLine->m_lpPersistStg;
  1525. OleDbgAssert(lpPersistStg);
  1526. OLEDBG_BEGIN2("OleSave called\r\n")
  1527. hrErr = OleSave(lpPersistStg, lpDestObjStg, FALSE /*fSameAsLoad*/);
  1528. OLEDBG_END2
  1529. if (hrErr != NOERROR) {
  1530. OleDbgOutHResult("WARNING: OleSave returned", hrErr);
  1531. sc = GetScode(hrErr);
  1532. }
  1533. // OLE2NOTE: even if OleSave fails, SaveCompleted must be called.
  1534. OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")
  1535. hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL);
  1536. OLEDBG_END2
  1537. if (hrErr != NOERROR) {
  1538. OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);
  1539. if (sc == S_OK)
  1540. sc = GetScode(hrErr);
  1541. }
  1542. if (sc != S_OK)
  1543. goto error;
  1544. }
  1545. OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex);
  1546. OleStdVerifyRelease(
  1547. (LPUNKNOWN)lpDestObjStg,
  1548. "Copied object stg not released"
  1549. );
  1550. return TRUE;
  1551. error:
  1552. // Delete any partially created storage.
  1553. if (lpDestObjStg) {
  1554. OleStdVerifyRelease(
  1555. (LPUNKNOWN)lpDestObjStg,
  1556. "Copied object stg not released"
  1557. );
  1558. CallIStorageDestroyElementA(
  1559. lpDestDocStg,
  1560. lpDestLine->m_szStgName
  1561. );
  1562. lpDestLine->m_szStgName[0] = '\0';
  1563. }
  1564. // destroy partially created ContainerLine
  1565. if (lpDestLine)
  1566. ContainerLine_Delete(lpDestLine);
  1567. return FALSE;
  1568. }
  1569. /* ContainerLine_UpdateExtent
  1570. ** --------------------------
  1571. ** Update the size of the ContainerLine because the extents of the
  1572. ** object may have changed.
  1573. **
  1574. ** NOTE: because we are using a Windows OwnerDraw ListBox, we must
  1575. ** constrain the maximum possible height of a line. the ListBox has
  1576. ** a limitation (unfortunately) that no line can become larger than
  1577. ** 255 pixels. thus we force the object to scale maintaining its
  1578. ** aspect ratio if this maximum line height limit is reached. the
  1579. ** actual maximum size for an object at 100% Zoom is
  1580. ** 255
  1581. **
  1582. ** RETURNS TRUE -- if the extents of the object changed
  1583. ** FALSE -- if the extents did NOT change
  1584. */
  1585. BOOL ContainerLine_UpdateExtent(
  1586. LPCONTAINERLINE lpContainerLine,
  1587. LPSIZEL lpsizelHim
  1588. )
  1589. {
  1590. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  1591. LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
  1592. LPLINE lpLine = (LPLINE)lpContainerLine;
  1593. int nIndex = LineList_GetLineIndex(lpLL, lpLine);
  1594. UINT nOrgWidthInHimetric = lpLine->m_nWidthInHimetric;
  1595. UINT nOrgHeightInHimetric = lpLine->m_nHeightInHimetric;
  1596. BOOL fWidthChanged = FALSE;
  1597. BOOL fHeightChanged = FALSE;
  1598. SIZEL sizelHim;
  1599. HRESULT hrErr;
  1600. if (!lpContainerLine || !lpContainerLine->m_lpOleObj)
  1601. return FALSE;
  1602. if (lpContainerLine->m_fGuardObj)
  1603. return FALSE; // object in process of creation
  1604. OLEDBG_BEGIN3("ContainerLine_UpdateExtent\r\n");
  1605. lpContainerLine->m_fDoGetExtent = FALSE;
  1606. if (! lpsizelHim) {
  1607. /* OLE2NOTE: We want to call IViewObject2::GetExtent instead of
  1608. ** IOleObject::GetExtent. IViewObject2::GetExtent method was
  1609. ** added in OLE 2.01 release. It always retrieves the
  1610. ** extents of the object corresponding to that which will be
  1611. ** drawn by calling IViewObject::Draw. Normally, this is
  1612. ** determined by the data stored in the data cache. This
  1613. ** call will never result in a remoted (LRPC) call.
  1614. */
  1615. OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n")
  1616. hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->GetExtent(
  1617. lpContainerLine->m_lpViewObj2,
  1618. lpContainerLine->m_dwDrawAspect,
  1619. -1, /*lindex*/
  1620. NULL, /*ptd*/
  1621. (LPSIZEL)&sizelHim
  1622. );
  1623. OLEDBG_END2
  1624. if (hrErr != NOERROR)
  1625. sizelHim.cx = sizelHim.cy = 0;
  1626. lpsizelHim = (LPSIZEL)&sizelHim;
  1627. }
  1628. if (lpsizelHim->cx == lpContainerLine->m_sizeInHimetric.cx &&
  1629. lpsizelHim->cy == lpContainerLine->m_sizeInHimetric.cy) {
  1630. goto noupdate;
  1631. }
  1632. if (lpsizelHim->cx > 0 || lpsizelHim->cy > 0) {
  1633. lpContainerLine->m_sizeInHimetric = *lpsizelHim;
  1634. } else {
  1635. /* object does not have any extents; let's use our container
  1636. ** chosen arbitrary size for OLE objects.
  1637. */
  1638. lpContainerLine->m_sizeInHimetric.cx = (long)DEFOBJWIDTH;
  1639. lpContainerLine->m_sizeInHimetric.cy = (long)DEFOBJHEIGHT;
  1640. }
  1641. ContainerLine_SetLineHeightFromObjectExtent(
  1642. lpContainerLine,
  1643. (LPSIZEL)&lpContainerLine->m_sizeInHimetric);
  1644. // if height of object changed, then reset the height of line in LineList
  1645. if (nOrgHeightInHimetric != lpLine->m_nHeightInHimetric) {
  1646. LineList_SetLineHeight(lpLL, nIndex, lpLine->m_nHeightInHimetric);
  1647. fHeightChanged = TRUE;
  1648. }
  1649. fWidthChanged = LineList_RecalcMaxLineWidthInHimetric(
  1650. lpLL,
  1651. nOrgWidthInHimetric
  1652. );
  1653. fWidthChanged |= (nOrgWidthInHimetric != lpLine->m_nWidthInHimetric);
  1654. if (fHeightChanged || fWidthChanged) {
  1655. OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);
  1656. // mark ContainerDoc as now dirty
  1657. OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE);
  1658. }
  1659. OLEDBG_END3
  1660. return TRUE;
  1661. noupdate:
  1662. OLEDBG_END3
  1663. return FALSE; // No UPDATE necessary
  1664. }
  1665. /* ContainerLine_DoVerb
  1666. ** --------------------
  1667. ** Activate the OLE object and perform a specific verb.
  1668. */
  1669. BOOL ContainerLine_DoVerb(
  1670. LPCONTAINERLINE lpContainerLine,
  1671. LONG iVerb,
  1672. LPMSG lpMsg,
  1673. BOOL fMessage,
  1674. BOOL fAction
  1675. )
  1676. {
  1677. HRESULT hrErr;
  1678. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  1679. RECT rcPosRect;
  1680. OLEDBG_BEGIN3("ContainerLine_DoVerb\r\n")
  1681. if (lpContainerLine->m_fGuardObj) {
  1682. // object in process of creation--Fail the DoVerb call
  1683. hrErr = ResultFromScode(E_FAIL);
  1684. goto error;
  1685. }
  1686. /* if object is not already loaded, then load it now. objects are
  1687. ** loaded lazily in this manner.
  1688. */
  1689. if (! lpContainerLine->m_lpOleObj)
  1690. ContainerLine_LoadOleObject(lpContainerLine);
  1691. if (! lpContainerLine->m_lpOleObj) {
  1692. #if defined( _DEBUG )
  1693. OleDbgAssertSz(
  1694. lpContainerLine->m_lpOleObj != NULL,
  1695. "OLE object not loaded"
  1696. );
  1697. #endif
  1698. goto error;
  1699. }
  1700. ExecuteDoVerb:
  1701. ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcPosRect);
  1702. // run the object
  1703. hrErr = ContainerLine_RunOleObject(lpContainerLine);
  1704. if (hrErr != NOERROR)
  1705. goto error;
  1706. /* Tell object server to perform a "verb". */
  1707. OLEDBG_BEGIN2("IOleObject::DoVerb called\r\n")
  1708. hrErr = lpContainerLine->m_lpOleObj->lpVtbl->DoVerb (
  1709. lpContainerLine->m_lpOleObj,
  1710. iVerb,
  1711. lpMsg,
  1712. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  1713. -1,
  1714. OutlineDoc_GetWindow(lpOutlineDoc),
  1715. (LPCRECT)&rcPosRect
  1716. );
  1717. OLEDBG_END2
  1718. /* OLE2NOTE: IOleObject::DoVerb may return a success code
  1719. ** OLE_S_INVALIDVERB. this SCODE should NOT be considered an
  1720. ** error; thus it is important to use the "FAILED" macro to
  1721. ** check for an error SCODE.
  1722. */
  1723. if (FAILED(GetScode(hrErr))) {
  1724. OleDbgOutHResult("WARNING: lpOleObj->DoVerb returned", hrErr);
  1725. goto error;
  1726. }
  1727. #if defined( INPLACE_CNTR )
  1728. /* OLE2NOTE: we want to keep only 1 inplace server active at any
  1729. ** given time. so when we start to do a DoVerb on another line,
  1730. ** then we want to shut down the previously activated server. in
  1731. ** this way we keep at most one inplace server active at a time.
  1732. ** because it is possible that the object we want to do DoVerb
  1733. ** on is handled by the same EXE as that of the previously
  1734. ** activated server, then we do not want the EXE to be shut down
  1735. ** only to be launched again. in order to avoid this we will do
  1736. ** the DoVerb BEFORE trying to shutdown the previous object.
  1737. */
  1738. if (!g_fInsideOutContainer) {
  1739. ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(
  1740. lpContainerLine->m_lpDoc, lpContainerLine);
  1741. }
  1742. #endif // INPLACE_CNTR
  1743. OLEDBG_END3
  1744. return TRUE;
  1745. error:
  1746. if (lpContainerLine->m_dwLinkType != 0)
  1747. lpContainerLine->m_fLinkUnavailable = TRUE;
  1748. #if defined( INPLACE_CNTR )
  1749. /* OLE2NOTE: we want to keep only 1 inplace server active at any
  1750. ** given time. so when we start to do a DoVerb on another line,
  1751. ** then we want to shut down the previously activated server. in
  1752. ** this way we keep at most one inplace server active at a time.
  1753. ** even though the DoVerb failed, we will still shutdown the
  1754. ** previous server. it is possible that we ran out of memory and
  1755. ** that the DoVerb will succeed next time after shutting down
  1756. ** the pervious server.
  1757. */
  1758. if (!g_fInsideOutContainer) {
  1759. ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(
  1760. lpContainerLine->m_lpDoc, lpContainerLine);
  1761. }
  1762. #endif // INPLACE_CNTR
  1763. /* OLE2NOTE: if an error occurs we must give the appropriate error
  1764. ** message box. there are many potential errors that can occur.
  1765. ** the OLE2.0 user model has specific guidelines as to the
  1766. ** dialogs that should be displayed given the various potential
  1767. ** errors (eg. server not registered, unavailable link source.
  1768. ** the OLE2UI library includes support for most of the
  1769. ** recommended message dialogs. (see OleUIPrompUser function)
  1770. */
  1771. if (fMessage) {
  1772. BOOL fReDoVerb = ContainerLine_ProcessOleRunError(
  1773. lpContainerLine,
  1774. hrErr,
  1775. fAction,
  1776. (lpMsg==NULL && iVerb>=0) /* fMenuInvoked */
  1777. );
  1778. if (fReDoVerb) {
  1779. goto ExecuteDoVerb;
  1780. }
  1781. }
  1782. OLEDBG_END3
  1783. return FALSE;
  1784. }
  1785. /* ContainerLine_ProcessOleRunError
  1786. * --------------------------------
  1787. *
  1788. * Handle the various errors possible when attempting OleRun of an object.
  1789. * Popup up appropriate message according to the error and/or take action
  1790. * specified button pressed by the user.
  1791. *
  1792. * OLE2NOTE: The OLE 2.0 User Interface Guidelines specify the messages
  1793. * that should be given for the following situations:
  1794. * 1. Link Source Unavailable...goto Links dialog
  1795. * 2. Server Not Registered...goto Convert dialog
  1796. * 3. Link Type Changed
  1797. * 4. Server Not Found
  1798. *
  1799. * Returns: TRUE -- repeat IOleObject::DoVerb call.
  1800. * FALSE -- do NOT repeat IOleObject::DoVerb call.
  1801. *
  1802. * Comments:
  1803. * (see LinkTypeChanged case)
  1804. */
  1805. BOOL ContainerLine_ProcessOleRunError(
  1806. LPCONTAINERLINE lpContainerLine,
  1807. HRESULT hrErr,
  1808. BOOL fAction,
  1809. BOOL fMenuInvoked
  1810. )
  1811. {
  1812. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  1813. HWND hwndParent = OutlineDoc_GetWindow(lpOutlineDoc);
  1814. SCODE sc = GetScode(hrErr);
  1815. BOOL fReDoVerb = FALSE;
  1816. OleDbgOutHResult("ProcessError", hrErr);
  1817. if ((sc >= MK_E_FIRST) && (sc <= MK_E_LAST))
  1818. goto LinkSourceUnavailable;
  1819. if (sc == OLE_E_CANT_BINDTOSOURCE)
  1820. goto LinkSourceUnavailable;
  1821. if (sc == STG_E_PATHNOTFOUND)
  1822. goto LinkSourceUnavailable;
  1823. if (sc == REGDB_E_CLASSNOTREG)
  1824. goto ServerNotReg;
  1825. if (sc == OLE_E_STATIC)
  1826. goto ServerNotReg; // user dblclk'ed a static object w/ no svr reg'd
  1827. if (sc == OLE_E_CLASSDIFF)
  1828. goto LinkTypeChanged;
  1829. if (sc == CO_E_APPDIDNTREG)
  1830. goto ServerNotFound;
  1831. if (sc == CO_E_APPNOTFOUND)
  1832. goto ServerNotFound;
  1833. if (sc == E_OUTOFMEMORY)
  1834. goto OutOfMemory;
  1835. if (ContainerLine_IsOleLink(lpContainerLine))
  1836. goto LinkSourceUnavailable;
  1837. else
  1838. goto ServerNotFound;
  1839. /*************************************************************************
  1840. ** Error handling routines **
  1841. *************************************************************************/
  1842. LinkSourceUnavailable:
  1843. if (ID_PU_LINKS == OleUIPromptUser(
  1844. (WORD)IDD_LINKSOURCEUNAVAILABLE,
  1845. hwndParent,
  1846. (LPSTR)APPNAME)) {
  1847. if (fAction) {
  1848. ContainerDoc_EditLinksCommand(lpContainerLine->m_lpDoc);
  1849. }
  1850. }
  1851. return fReDoVerb;
  1852. ServerNotReg:
  1853. {
  1854. LPSTR lpszUserType = NULL;
  1855. CLIPFORMAT cfFormat; // not used
  1856. hrErr = ReadFmtUserTypeStgA(
  1857. lpContainerLine->m_lpStg, &cfFormat, &lpszUserType);
  1858. if (ID_PU_CONVERT == OleUIPromptUser(
  1859. (WORD)IDD_SERVERNOTREG,
  1860. hwndParent,
  1861. (LPSTR)APPNAME,
  1862. (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object")) {
  1863. if (fAction) {
  1864. ContainerDoc_ConvertCommand(
  1865. lpContainerLine->m_lpDoc,
  1866. TRUE // fMustActivate
  1867. );
  1868. }
  1869. }
  1870. if (lpszUserType)
  1871. OleStdFreeString(lpszUserType, NULL);
  1872. return fReDoVerb;
  1873. }
  1874. LinkTypeChanged:
  1875. {
  1876. /* OLE2NOTE: If IOleObject::DoVerb is executed on a Link object and it
  1877. ** returns OLE_E_CLASSDIFF because the link source is no longer
  1878. ** the expected class, then if the verb is a semantically
  1879. ** defined verb (eg. OLEIVERB_PRIMARY, OLEIVERB_SHOW,
  1880. ** OLEIVERB_OPEN, etc.), then the link should be re-created with
  1881. ** the new link source and the same verb executed on the new
  1882. ** link. there is no need to give a message to the user. if the
  1883. ** user had selected a verb from the object's verb menu
  1884. ** (fMenuInvoked==TRUE), then we can not be certain of the
  1885. ** semantics of the verb and whether the new link can still
  1886. ** support the verb. in this case the user is given a prompt
  1887. ** telling him to "choose a different command offered by the new
  1888. ** type".
  1889. */
  1890. LPSTR lpszUserType = NULL;
  1891. if (fMenuInvoked) {
  1892. hrErr = CallIOleObjectGetUserTypeA(
  1893. lpContainerLine->m_lpOleObj,USERCLASSTYPE_FULL, &lpszUserType);
  1894. OleUIPromptUser(
  1895. (WORD)IDD_LINKTYPECHANGED,
  1896. hwndParent,
  1897. (LPSTR)APPNAME,
  1898. (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object"
  1899. );
  1900. } else {
  1901. fReDoVerb = TRUE;
  1902. }
  1903. ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine);
  1904. if (lpszUserType)
  1905. OleStdFreeString(lpszUserType, NULL);
  1906. return fReDoVerb;
  1907. }
  1908. ServerNotFound:
  1909. OleUIPromptUser(
  1910. (WORD)IDD_SERVERNOTFOUND,
  1911. hwndParent,
  1912. (LPSTR)APPNAME);
  1913. return fReDoVerb;
  1914. OutOfMemory:
  1915. OleUIPromptUser(
  1916. (WORD)IDD_OUTOFMEMORY,
  1917. hwndParent,
  1918. (LPSTR)APPNAME);
  1919. return fReDoVerb;
  1920. }
  1921. /* ContainerLine_ReCreateLinkBecauseClassDiff
  1922. ** ------------------------------------------
  1923. ** Re-create the link. The existing link was created when
  1924. ** the moniker binds to a link source bound of a different class
  1925. ** than the same moniker currently binds to. the link may be a
  1926. ** special link object specifically used with the old link
  1927. ** source class. thus the link object needs to be re-created to
  1928. ** give the new link source the opportunity to create its own
  1929. ** special link object. (see description "Custom Link Source")
  1930. */
  1931. HRESULT ContainerLine_ReCreateLinkBecauseClassDiff(
  1932. LPCONTAINERLINE lpContainerLine
  1933. )
  1934. {
  1935. LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink;
  1936. HGLOBAL hMetaPict = NULL;
  1937. LPMONIKER lpmkLinkSrc = NULL;
  1938. SCODE sc = E_FAIL;
  1939. HRESULT hrErr;
  1940. if (lpOleLink &&
  1941. lpOleLink->lpVtbl->GetSourceMoniker(
  1942. lpOleLink, (LPMONIKER FAR*)&lpmkLinkSrc) == NOERROR) {
  1943. BOOL fDisplayAsIcon =
  1944. (lpContainerLine->m_dwDrawAspect==DVASPECT_ICON);
  1945. STGMEDIUM medium;
  1946. LPDATAOBJECT lpDataObj = NULL;
  1947. DWORD dwOleRenderOpt;
  1948. FORMATETC renderFmtEtc;
  1949. LPFORMATETC lpRenderFmtEtc = NULL;
  1950. // get the current icon if object is displayed as icon
  1951. if (fDisplayAsIcon &&
  1952. (lpDataObj = (LPDATAOBJECT)OleStdQueryInterface( (LPUNKNOWN)
  1953. lpContainerLine->m_lpOleObj,&IID_IDataObject)) != NULL ) {
  1954. hMetaPict = OleStdGetData(
  1955. lpDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium);
  1956. OleStdRelease((LPUNKNOWN)lpDataObj);
  1957. }
  1958. if (fDisplayAsIcon && hMetaPict) {
  1959. // a special icon should be used. first we create the object
  1960. // OLERENDER_NONE. then we stuff the special icon into the cache.
  1961. dwOleRenderOpt = OLERENDER_NONE;
  1962. } else if (fDisplayAsIcon && hMetaPict == NULL) {
  1963. // the object's default icon should be used
  1964. dwOleRenderOpt = OLERENDER_DRAW;
  1965. lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;
  1966. SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);
  1967. } else {
  1968. // create standard DVASPECT_CONTENT/OLERENDER_DRAW object
  1969. dwOleRenderOpt = OLERENDER_DRAW;
  1970. }
  1971. // unload original link object
  1972. ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY);
  1973. // delete entire contents of the current object's storage
  1974. OleStdDestroyAllElements(lpContainerLine->m_lpStg);
  1975. OLEDBG_BEGIN2("OleCreateLink called\r\n")
  1976. hrErr = OleCreateLink (
  1977. lpmkLinkSrc,
  1978. &IID_IOleObject,
  1979. dwOleRenderOpt,
  1980. lpRenderFmtEtc,
  1981. (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,
  1982. lpContainerLine->m_lpStg,
  1983. (LPVOID FAR*)&lpContainerLine->m_lpOleObj
  1984. );
  1985. OLEDBG_END2
  1986. if (hrErr == NOERROR) {
  1987. if (! ContainerLine_SetupOleObject(
  1988. lpContainerLine, fDisplayAsIcon, hMetaPict) ) {
  1989. // ERROR: setup of the new link failed.
  1990. // revert the storage to restore the original link.
  1991. ContainerLine_UnloadOleObject(
  1992. lpContainerLine, OLECLOSE_NOSAVE);
  1993. lpContainerLine->m_lpStg->lpVtbl->Revert(
  1994. lpContainerLine->m_lpStg);
  1995. sc = E_FAIL;
  1996. } else {
  1997. sc = S_OK; // IT WORKED!
  1998. }
  1999. }
  2000. else {
  2001. sc = GetScode(hrErr);
  2002. OleDbgOutHResult("OleCreateLink returned", hrErr);
  2003. // ERROR: Re-creating the link failed.
  2004. // revert the storage to restore the original link.
  2005. lpContainerLine->m_lpStg->lpVtbl->Revert(
  2006. lpContainerLine->m_lpStg);
  2007. }
  2008. }
  2009. if (hMetaPict)
  2010. OleUIMetafilePictIconFree(hMetaPict); // clean up metafile
  2011. return ResultFromScode(sc);
  2012. }
  2013. /* ContainerLine_GetOleObject
  2014. ** --------------------------
  2015. ** return pointer to desired interface of embedded/linked object.
  2016. **
  2017. ** NOTE: this function causes an AddRef to the object. when the caller is
  2018. ** finished with the object, it must call Release.
  2019. ** this function does not AddRef the ContainerLine object.
  2020. */
  2021. LPUNKNOWN ContainerLine_GetOleObject(
  2022. LPCONTAINERLINE lpContainerLine,
  2023. REFIID riid
  2024. )
  2025. {
  2026. /* if object is not already loaded, then load it now. objects are
  2027. ** loaded lazily in this manner.
  2028. */
  2029. if (! lpContainerLine->m_lpOleObj)
  2030. ContainerLine_LoadOleObject(lpContainerLine);
  2031. if (lpContainerLine->m_lpOleObj)
  2032. return OleStdQueryInterface(
  2033. (LPUNKNOWN)lpContainerLine->m_lpOleObj,
  2034. riid
  2035. );
  2036. else
  2037. return NULL;
  2038. }
  2039. /* ContainerLine_RunOleObject
  2040. ** --------------------------
  2041. ** Load and run the object. Upon running and if size of object has changed,
  2042. ** use SetExtent to change to new size.
  2043. **
  2044. */
  2045. HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine)
  2046. {
  2047. LPLINE lpLine = (LPLINE)lpContainerLine;
  2048. SIZEL sizelNew;
  2049. HRESULT hrErr;
  2050. HCURSOR hPrevCursor;
  2051. if (! lpContainerLine)
  2052. return NOERROR;
  2053. if (lpContainerLine->m_fGuardObj) {
  2054. // object in process of creation--Fail to Run the object
  2055. return ResultFromScode(E_FAIL);
  2056. }
  2057. if (lpContainerLine->m_lpOleObj &&
  2058. OleIsRunning(lpContainerLine->m_lpOleObj))
  2059. return NOERROR; // object already running
  2060. // this may take a while, put up hourglass cursor
  2061. hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2062. OLEDBG_BEGIN3("ContainerLine_RunOleObject\r\n")
  2063. if (! lpContainerLine->m_lpOleObj) {
  2064. if (! ContainerLine_LoadOleObject(lpContainerLine))
  2065. return ResultFromScode(E_OUTOFMEMORY); // Error: couldn't load obj
  2066. }
  2067. OLEDBG_BEGIN2("OleRun called\r\n")
  2068. hrErr = OleRun((LPUNKNOWN)lpContainerLine->m_lpOleObj);
  2069. OLEDBG_END2
  2070. if (hrErr != NOERROR) {
  2071. SetCursor(hPrevCursor); // restore original cursor
  2072. OleDbgOutHResult("OleRun returned", hrErr);
  2073. OLEDBG_END3
  2074. return hrErr;
  2075. }
  2076. if (lpContainerLine->m_fDoSetExtent) {
  2077. /* OLE2NOTE: the OLE object was resized when it was not running
  2078. ** and the object did not have the OLEMISC_RECOMPOSEONRESIZE
  2079. ** bit set. if it had, the object would have been run
  2080. ** immediately when it was resized. this flag indicates that
  2081. ** the object does something other than simple scaling when
  2082. ** it is resized. because the object is being run now, we
  2083. ** will call IOleObject::SetExtent.
  2084. */
  2085. lpContainerLine->m_fDoSetExtent = FALSE;
  2086. // the size stored in our Line includes the border around the object.
  2087. // we must subtract the border to get the size of the object itself.
  2088. sizelNew.cx = lpLine->m_nWidthInHimetric;
  2089. sizelNew.cy = lpLine->m_nHeightInHimetric;
  2090. if ((sizelNew.cx != lpContainerLine->m_sizeInHimetric.cx) ||
  2091. (sizelNew.cy != lpContainerLine->m_sizeInHimetric.cy)) {
  2092. OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n")
  2093. lpContainerLine->m_lpOleObj->lpVtbl->SetExtent(
  2094. lpContainerLine->m_lpOleObj,
  2095. lpContainerLine->m_dwDrawAspect,
  2096. (LPSIZEL)&sizelNew
  2097. );
  2098. OLEDBG_END2
  2099. }
  2100. }
  2101. SetCursor(hPrevCursor); // restore original cursor
  2102. OLEDBG_END3
  2103. return NOERROR;
  2104. }
  2105. /* ContainerLine_IsOleLink
  2106. ** -----------------------
  2107. **
  2108. ** return TRUE if the ContainerLine has an OleLink.
  2109. ** FALSE if the ContainerLine has an embedding
  2110. */
  2111. BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine)
  2112. {
  2113. if (!lpContainerLine)
  2114. return FALSE;
  2115. return (lpContainerLine->m_dwLinkType != 0);
  2116. }
  2117. /* ContainerLine_Draw
  2118. ** ------------------
  2119. **
  2120. ** Draw a ContainerLine object on a DC.
  2121. **
  2122. ** Parameters:
  2123. ** hDC - DC to which the line will be drawn
  2124. ** lpRect - the object rect in logical coordinates
  2125. ** lpRectWBounds - bounding rect of the metafile underneath hDC
  2126. ** (NULL if hDC is not a metafile DC)
  2127. ** fHighlight - TRUE if line has selection highlight
  2128. */
  2129. void ContainerLine_Draw(
  2130. LPCONTAINERLINE lpContainerLine,
  2131. HDC hDC,
  2132. LPRECT lpRect,
  2133. LPRECT lpRectWBounds,
  2134. BOOL fHighlight
  2135. )
  2136. {
  2137. LPLINE lpLine = (LPLINE) lpContainerLine;
  2138. HRESULT hrErr = NOERROR;
  2139. RECTL rclHim;
  2140. RECTL rclHimWBounds;
  2141. RECT rcHim;
  2142. if (lpContainerLine->m_fGuardObj) {
  2143. // object in process of creation--do NOT try to draw
  2144. return;
  2145. }
  2146. /* if object is not already loaded, then load it now. objects are
  2147. ** loaded lazily in this manner.
  2148. */
  2149. if (! lpContainerLine->m_lpViewObj2) {
  2150. if (! ContainerLine_LoadOleObject(lpContainerLine))
  2151. return; // Error: could not load object
  2152. }
  2153. if (lpRectWBounds) {
  2154. rclHimWBounds.left = (long) lpRectWBounds->left;
  2155. rclHimWBounds.bottom = (long) lpRectWBounds->bottom;
  2156. rclHimWBounds.top = (long) lpRectWBounds->top;
  2157. rclHimWBounds.right = (long) lpRectWBounds->right;
  2158. }
  2159. /* construct bounds rectangle for the object.
  2160. ** offset origin for object to correct tab indentation
  2161. */
  2162. rclHim.left = (long) lpRect->left;
  2163. rclHim.bottom = (long) lpRect->bottom;
  2164. rclHim.top = (long) lpRect->top;
  2165. rclHim.right = (long) lpRect->right;
  2166. rclHim.left += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric;
  2167. rclHim.right += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric;
  2168. #if defined( INPLACE_CNTR )
  2169. /* OLE2NOTE: if the OLE object currently has a visible in-place
  2170. ** window, then we do NOT want to draw on top of its window.
  2171. ** this could interfere with the object's display.
  2172. */
  2173. if ( !lpContainerLine->m_fIpVisible )
  2174. #endif
  2175. {
  2176. hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->Draw(
  2177. lpContainerLine->m_lpViewObj2,
  2178. lpContainerLine->m_dwDrawAspect,
  2179. -1,
  2180. NULL,
  2181. NULL,
  2182. NULL,
  2183. hDC,
  2184. (LPRECTL)&rclHim,
  2185. (lpRectWBounds ? (LPRECTL)&rclHimWBounds : NULL),
  2186. NULL,
  2187. 0
  2188. );
  2189. if (hrErr != NOERROR)
  2190. OleDbgOutHResult("IViewObject::Draw returned", hrErr);
  2191. if (lpContainerLine->m_fObjWinOpen)
  2192. {
  2193. rcHim.left = (int) rclHim.left;
  2194. rcHim.top = (int) rclHim.top;
  2195. rcHim.right = (int) rclHim.right;
  2196. rcHim.bottom = (int) rclHim.bottom;
  2197. /* OLE2NOTE: if the object servers window is Open (ie. not active
  2198. ** in-place) then we must shade the object in our document to
  2199. ** indicate to the user that the object is open elsewhere.
  2200. */
  2201. OleUIDrawShading((LPRECT)&rcHim, hDC, OLEUI_SHADE_FULLRECT, 0);
  2202. }
  2203. }
  2204. /* if the object associated with the ContainerLine is an automatic
  2205. ** link then try to connect it with its LinkSource if the
  2206. ** LinkSource is already running. we do not want to force the
  2207. ** LinkSource to run.
  2208. **
  2209. ** OLE2NOTE: a sophistocated container will want to continually
  2210. ** attempt to connect its automatic links. OLE does NOT
  2211. ** automatically connect links when link sources become
  2212. ** available. some containers will want to attempt to connect
  2213. ** its links as part of idle time processing. another strategy
  2214. ** is to attempt to connect an automatic link every time it is
  2215. ** drawn on the screen. (this is the strategy used by this
  2216. ** CntrOutl sample application.)
  2217. */
  2218. if (lpContainerLine->m_dwLinkType == OLEUPDATE_ALWAYS)
  2219. ContainerLine_BindLinkIfLinkSrcIsRunning(lpContainerLine);
  2220. return;
  2221. }
  2222. void ContainerLine_DrawSelHilight(
  2223. LPCONTAINERLINE lpContainerLine,
  2224. HDC hDC, // MM_TEXT mode
  2225. LPRECT lprcPix, // listbox rect
  2226. UINT itemAction,
  2227. UINT itemState
  2228. )
  2229. {
  2230. LPLINE lpLine = (LPLINE)lpContainerLine;
  2231. RECT rcObj;
  2232. DWORD dwFlags = OLEUI_HANDLES_INSIDE | OLEUI_HANDLES_USEINVERSE;
  2233. int nHandleSize;
  2234. LPCONTAINERDOC lpContainerDoc;
  2235. if (!lpContainerLine || !hDC || !lprcPix)
  2236. return;
  2237. lpContainerDoc = lpContainerLine->m_lpDoc;
  2238. // Get size of OLE object
  2239. ContainerLine_GetOleObjectRectInPixels(lpContainerLine, (LPRECT)&rcObj);
  2240. nHandleSize = GetProfileInt("windows", "oleinplaceborderwidth",
  2241. DEFAULT_HATCHBORDER_WIDTH) + 1;
  2242. OleUIDrawHandles((LPRECT)&rcObj, hDC, dwFlags, nHandleSize, TRUE);
  2243. }
  2244. /* InvertDiffRect
  2245. ** --------------
  2246. **
  2247. ** Paint the surrounding of the Obj rect black but within lprcPix
  2248. ** (similar to the lprcPix minus lprcObj)
  2249. */
  2250. static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC)
  2251. {
  2252. RECT rcBlack;
  2253. // draw black in all space outside of object's rectangle
  2254. rcBlack.top = lprcPix->top;
  2255. rcBlack.bottom = lprcPix->bottom;
  2256. rcBlack.left = lprcPix->left + 1;
  2257. rcBlack.right = lprcObj->left - 1;
  2258. InvertRect(hDC, (LPRECT)&rcBlack);
  2259. rcBlack.left = lprcObj->right + 1;
  2260. rcBlack.right = lprcPix->right - 1;
  2261. InvertRect(hDC, (LPRECT)&rcBlack);
  2262. rcBlack.top = lprcPix->top;
  2263. rcBlack.bottom = lprcPix->top + 1;
  2264. rcBlack.left = lprcObj->left - 1;
  2265. rcBlack.right = lprcObj->right + 1;
  2266. InvertRect(hDC, (LPRECT)&rcBlack);
  2267. rcBlack.top = lprcPix->bottom;
  2268. rcBlack.bottom = lprcPix->bottom - 1;
  2269. rcBlack.left = lprcObj->left - 1;
  2270. rcBlack.right = lprcObj->right + 1;
  2271. InvertRect(hDC, (LPRECT)&rcBlack);
  2272. }
  2273. /* Edit the ContainerLine line object.
  2274. ** returns TRUE if line was changed
  2275. ** FALSE if the line was NOT changed
  2276. */
  2277. BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine, HWND hWndDoc,HDC hDC)
  2278. {
  2279. ContainerLine_DoVerb(lpContainerLine, OLEIVERB_PRIMARY, NULL, TRUE, TRUE);
  2280. /* assume object was NOT changed, if it was obj will send Changed
  2281. ** or Saved notification.
  2282. */
  2283. return FALSE;
  2284. }
  2285. /* ContainerLine_SetHeightInHimetric
  2286. ** ---------------------------------
  2287. **
  2288. ** Set the height of a ContainerLine object. The widht will be changed
  2289. ** to keep the aspect ratio
  2290. */
  2291. void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight)
  2292. {
  2293. LPLINE lpLine = (LPLINE)lpContainerLine;
  2294. SIZEL sizelOleObject;
  2295. HRESULT hrErr;
  2296. if (!lpContainerLine)
  2297. return;
  2298. if (lpContainerLine->m_fGuardObj) {
  2299. // object in process of creation--Fail to set the Height
  2300. return;
  2301. }
  2302. if (nHeight != -1) {
  2303. BOOL fMustClose = FALSE;
  2304. BOOL fMustRun = FALSE;
  2305. /* if object is not already loaded, then load it now. objects are
  2306. ** loaded lazily in this manner.
  2307. */
  2308. if (! lpContainerLine->m_lpOleObj)
  2309. ContainerLine_LoadOleObject(lpContainerLine);
  2310. // the height argument specifies the desired height for the Line.
  2311. sizelOleObject.cy = nHeight;
  2312. // we will calculate the corresponding width for the object by
  2313. // maintaining the current aspect ratio of the object.
  2314. sizelOleObject.cx = (int)(sizelOleObject.cy *
  2315. lpContainerLine->m_sizeInHimetric.cx /
  2316. lpContainerLine->m_sizeInHimetric.cy);
  2317. /* OLE2NOTE: if the OLE object is already running then we can
  2318. ** immediately call SetExtent. But, if the object is NOT
  2319. ** currently running then we will check if the object
  2320. ** indicates that it is normally recomposes itself on
  2321. ** resizing. ie. that the object does not simply scale its
  2322. ** display when it it resized. if so then we will force the
  2323. ** object to run so that we can call IOleObject::SetExtent.
  2324. ** SetExtent does not have any effect if the object is only
  2325. ** loaded. if the object does NOT indicate that it
  2326. ** recomposes on resize (OLEMISC_RECOMPOSEONRESIZE) then we
  2327. ** will wait till the next time that the object is run to
  2328. ** call SetExtent. we will store a flag in the ContainerLine
  2329. ** to indicate that a SetExtent is necessary. It is
  2330. ** necessary to persist this flag.
  2331. */
  2332. if (! OleIsRunning(lpContainerLine->m_lpOleObj)) {
  2333. DWORD dwStatus;
  2334. OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")
  2335. hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(
  2336. lpContainerLine->m_lpOleObj,
  2337. lpContainerLine->m_dwDrawAspect,
  2338. (LPDWORD)&dwStatus
  2339. );
  2340. OLEDBG_END2
  2341. if (hrErr == NOERROR && (dwStatus & OLEMISC_RECOMPOSEONRESIZE)) {
  2342. // force the object to run
  2343. ContainerLine_RunOleObject(lpContainerLine);
  2344. fMustClose = TRUE;
  2345. } else {
  2346. /* the OLE object is NOT running and does NOT
  2347. ** recompose on resize. simply scale the object now
  2348. ** and do the SetExtent the next time the object is
  2349. ** run. we set the Line to the new size even though
  2350. ** the object's extents have not been changed.
  2351. ** this has the result of scaling the object's
  2352. ** display to the new size.
  2353. */
  2354. lpContainerLine->m_fDoSetExtent = TRUE;
  2355. ContainerLine_SetLineHeightFromObjectExtent(
  2356. lpContainerLine, (LPSIZEL)&sizelOleObject);
  2357. return;
  2358. }
  2359. }
  2360. OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n")
  2361. hrErr = lpContainerLine->m_lpOleObj->lpVtbl->SetExtent(
  2362. lpContainerLine->m_lpOleObj,
  2363. lpContainerLine->m_dwDrawAspect,
  2364. (LPSIZEL)&sizelOleObject);
  2365. OLEDBG_END2
  2366. if (hrErr != NOERROR) {
  2367. /* OLE Object refuses to take on the new extents. Set the
  2368. ** Line to the new size even though the object refused
  2369. ** the new extents. this has the result of scaling the
  2370. ** object's display to the new size.
  2371. **
  2372. ** if the object HAD accepted the new extents, then it
  2373. ** will send out an OnViewChange/OnDataChange
  2374. ** notification. this results in our container receiving
  2375. ** an OnViewChange notification; the line height will be
  2376. ** reset when this notification is received.
  2377. */
  2378. ContainerLine_SetLineHeightFromObjectExtent(
  2379. lpContainerLine, (LPSIZEL)&sizelOleObject);
  2380. }
  2381. if (fMustClose)
  2382. ContainerLine_CloseOleObject(
  2383. lpContainerLine, OLECLOSE_SAVEIFDIRTY);
  2384. }
  2385. else {
  2386. /* Set the line to default height given the natural (unscaled)
  2387. ** extents of the OLE object.
  2388. */
  2389. ContainerLine_SetLineHeightFromObjectExtent(
  2390. lpContainerLine,(LPSIZEL)&lpContainerLine->m_sizeInHimetric);
  2391. }
  2392. }
  2393. /* ContainerLine_SetLineHeightFromObjectExtent
  2394. *
  2395. * Purpose:
  2396. * Calculate the corresponding line height from the OleObject size
  2397. * Scale the line height to fit the limit if necessary
  2398. *
  2399. * Parameters:
  2400. * lpsizelOleObject pointer to size of OLE Object
  2401. *
  2402. * Returns:
  2403. * nil
  2404. */
  2405. void ContainerLine_SetLineHeightFromObjectExtent(
  2406. LPCONTAINERLINE lpContainerLine,
  2407. LPSIZEL lpsizelOleObject
  2408. )
  2409. {
  2410. LPLINE lpLine = (LPLINE)lpContainerLine;
  2411. UINT uMaxObjectHeight = XformHeightInPixelsToHimetric(NULL,
  2412. LISTBOX_HEIGHT_LIMIT);
  2413. if (!lpContainerLine || !lpsizelOleObject)
  2414. return;
  2415. if (lpContainerLine->m_fGuardObj) {
  2416. // object in process of creation--Fail to set the Height
  2417. return;
  2418. }
  2419. lpLine->m_nWidthInHimetric = (int)lpsizelOleObject->cx;
  2420. lpLine->m_nHeightInHimetric = (int)lpsizelOleObject->cy;
  2421. // Rescale the object if height is greater than the limit
  2422. if (lpLine->m_nHeightInHimetric > (UINT)uMaxObjectHeight) {
  2423. lpLine->m_nWidthInHimetric = (UINT)
  2424. ((long)lpLine->m_nWidthInHimetric *
  2425. (long)uMaxObjectHeight /
  2426. (long)lpLine->m_nHeightInHimetric);
  2427. lpLine->m_nHeightInHimetric = uMaxObjectHeight;
  2428. }
  2429. }
  2430. /* ContainerLine_SaveToStg
  2431. ** -----------------------
  2432. ** Save a given ContainerLine and associated OLE object to an IStorage*.
  2433. */
  2434. BOOL ContainerLine_SaveToStm(
  2435. LPCONTAINERLINE lpContainerLine,
  2436. LPSTREAM lpLLStm
  2437. )
  2438. {
  2439. CONTAINERLINERECORD_ONDISK objLineRecord;
  2440. ULONG nWritten;
  2441. HRESULT hrErr;
  2442. // Compilers should handle aligment correctly
  2443. lstrcpy(objLineRecord.m_szStgName, lpContainerLine->m_szStgName);
  2444. objLineRecord.m_fMonikerAssigned = (USHORT) lpContainerLine->m_fMonikerAssigned;
  2445. objLineRecord.m_dwDrawAspect = lpContainerLine->m_dwDrawAspect;
  2446. objLineRecord.m_sizeInHimetric = lpContainerLine->m_sizeInHimetric;
  2447. objLineRecord.m_dwLinkType = lpContainerLine->m_dwLinkType;
  2448. objLineRecord.m_fDoSetExtent = (USHORT) lpContainerLine->m_fDoSetExtent;
  2449. /* write line record */
  2450. hrErr = lpLLStm->lpVtbl->Write(
  2451. lpLLStm,
  2452. (LPVOID)&objLineRecord,
  2453. sizeof(objLineRecord),
  2454. &nWritten
  2455. );
  2456. if (hrErr != NOERROR) {
  2457. OleDbgAssertSz(hrErr == NOERROR,"Could not write to LineList stream");
  2458. return FALSE;
  2459. }
  2460. return TRUE;
  2461. }
  2462. /* ContainerLine_SaveOleObjectToStg
  2463. ** --------------------------------
  2464. ** Save the OLE object associated with the ContainerLine to an IStorage*.
  2465. */
  2466. BOOL ContainerLine_SaveOleObjectToStg(
  2467. LPCONTAINERLINE lpContainerLine,
  2468. LPSTORAGE lpSrcStg,
  2469. LPSTORAGE lpDestStg,
  2470. BOOL fRemember
  2471. )
  2472. {
  2473. HRESULT hrErr;
  2474. SCODE sc = S_OK;
  2475. BOOL fStatus;
  2476. BOOL fSameAsLoad = (lpSrcStg==lpDestStg ? TRUE : FALSE);
  2477. LPSTORAGE lpObjDestStg;
  2478. if (lpContainerLine->m_fGuardObj) {
  2479. // object in process of creation--Fail to save
  2480. return FALSE;
  2481. }
  2482. if (! lpContainerLine->m_lpOleObj) {
  2483. /*****************************************************************
  2484. ** CASE 1: object is NOT loaded.
  2485. *****************************************************************/
  2486. if (fSameAsLoad) {
  2487. /*************************************************************
  2488. ** CASE 1A: we are saving to the current storage. because
  2489. ** the object is not loaded, it is up-to-date
  2490. ** (ie. nothing to do).
  2491. *************************************************************/
  2492. ;
  2493. } else {
  2494. /*************************************************************
  2495. ** CASE 1B: we are saving to a new storage. because
  2496. ** the object is not loaded, we can simply copy the
  2497. ** object's current storage to the new storage.
  2498. *************************************************************/
  2499. /* if current object storage is not already open, then open it */
  2500. if (! lpContainerLine->m_lpStg) {
  2501. lpContainerLine->m_lpStg = OleStdOpenChildStorage(
  2502. lpSrcStg,
  2503. lpContainerLine->m_szStgName,
  2504. STGM_READWRITE
  2505. );
  2506. if (lpContainerLine->m_lpStg == NULL) {
  2507. #if defined( _DEBUG )
  2508. OleDbgAssertSz(
  2509. lpContainerLine->m_lpStg != NULL,
  2510. "Error opening child stg"
  2511. );
  2512. #endif
  2513. return FALSE;
  2514. }
  2515. }
  2516. /* Create a child storage inside the destination storage. */
  2517. lpObjDestStg = OleStdCreateChildStorage(
  2518. lpDestStg,
  2519. lpContainerLine->m_szStgName
  2520. );
  2521. if (lpObjDestStg == NULL) {
  2522. #if defined( _DEBUG )
  2523. OleDbgAssertSz(
  2524. lpObjDestStg != NULL,
  2525. "Could not create obj storage!"
  2526. );
  2527. #endif
  2528. return FALSE;
  2529. }
  2530. hrErr = lpContainerLine->m_lpStg->lpVtbl->CopyTo(
  2531. lpContainerLine->m_lpStg,
  2532. 0,
  2533. NULL,
  2534. NULL,
  2535. lpObjDestStg
  2536. );
  2537. // REVIEW: should we handle error here?
  2538. fStatus = OleStdCommitStorage(lpObjDestStg);
  2539. /* if we are supposed to remember this storage as the new
  2540. ** storage for the object, then release the old one and
  2541. ** save the new one. else, throw away the new one.
  2542. */
  2543. if (fRemember) {
  2544. OleStdVerifyRelease(
  2545. (LPUNKNOWN)lpContainerLine->m_lpStg,
  2546. "Original object stg not released"
  2547. );
  2548. lpContainerLine->m_lpStg = lpObjDestStg;
  2549. } else {
  2550. OleStdVerifyRelease(
  2551. (LPUNKNOWN)lpObjDestStg,
  2552. "Copied object stg not released"
  2553. );
  2554. }
  2555. }
  2556. } else {
  2557. /*****************************************************************
  2558. ** CASE 2: object IS loaded.
  2559. *****************************************************************/
  2560. if (fSameAsLoad) {
  2561. /*************************************************************
  2562. ** CASE 2A: we are saving to the current storage. if the object
  2563. ** is not dirty, then the current storage is up-to-date
  2564. ** (ie. nothing to do).
  2565. *************************************************************/
  2566. LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;
  2567. OleDbgAssert(lpPersistStg);
  2568. hrErr = lpPersistStg->lpVtbl->IsDirty(lpPersistStg);
  2569. /* OLE2NOTE: we will only accept an explicit "no i
  2570. ** am NOT dirty statement" (ie. S_FALSE) as an
  2571. ** indication that the object is clean. eg. if
  2572. ** the object returns E_NOTIMPL we must
  2573. ** interpret it as the object IS dirty.
  2574. */
  2575. if (GetScode(hrErr) != S_FALSE) {
  2576. /* OLE object IS dirty */
  2577. OLEDBG_BEGIN2("OleSave called\r\n")
  2578. hrErr = OleSave(
  2579. lpPersistStg, lpContainerLine->m_lpStg, fSameAsLoad);
  2580. OLEDBG_END2
  2581. if (hrErr != NOERROR) {
  2582. OleDbgOutHResult("WARNING: OleSave returned", hrErr);
  2583. sc = GetScode(hrErr);
  2584. }
  2585. // OLE2NOTE: if OleSave fails, SaveCompleted must be called.
  2586. OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")
  2587. hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL);
  2588. OLEDBG_END2
  2589. if (hrErr != NOERROR) {
  2590. OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);
  2591. if (sc == S_OK)
  2592. sc = GetScode(hrErr);
  2593. }
  2594. if (sc != S_OK)
  2595. return FALSE;
  2596. }
  2597. } else {
  2598. /*************************************************************
  2599. ** CASE 2B: we are saving to a new storage. we must
  2600. ** tell the object to save into the new storage.
  2601. *************************************************************/
  2602. LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;
  2603. if (! lpPersistStg) return FALSE;
  2604. /* Create a child storage inside the destination storage. */
  2605. lpObjDestStg = OleStdCreateChildStorage(
  2606. lpDestStg,
  2607. lpContainerLine->m_szStgName
  2608. );
  2609. if (lpObjDestStg == NULL) {
  2610. #if defined( _DEBUG )
  2611. OleDbgAssertSz(
  2612. lpObjDestStg != NULL,
  2613. "Could not create object storage!"
  2614. );
  2615. #endif
  2616. return FALSE;
  2617. }
  2618. OLEDBG_BEGIN2("OleSave called\r\n")
  2619. hrErr = OleSave(lpPersistStg, lpObjDestStg, fSameAsLoad);
  2620. OLEDBG_END2
  2621. // OLE2NOTE: even if OleSave fails, must still call SaveCompleted
  2622. if (hrErr != NOERROR) {
  2623. OleDbgOutHResult("WARNING: OleSave returned", hrErr);
  2624. sc = GetScode(hrErr);
  2625. }
  2626. /* OLE2NOTE: a root level container should immediately
  2627. ** call IPersistStorage::SaveCompleted after calling
  2628. ** OleSave. a nested level container should not call
  2629. ** SaveCompleted now, but must wait until SaveCompleted
  2630. ** is call on it by its container. since our container
  2631. ** is not a container/server, then we always call
  2632. ** SaveComplete here.
  2633. **
  2634. ** if this is a SaveAs operation, then we need to pass
  2635. ** the lpStg back in SaveCompleted to inform the object
  2636. ** of its new storage that it may hold on to. if this is
  2637. ** a Save or a SaveCopyAs operation, then we simply pass
  2638. ** NULL in SaveCompleted; the object can continue to hold
  2639. ** its current storage. if an error occurs during the
  2640. ** OleSave call we must still call SaveCompleted but we
  2641. ** must pass NULL.
  2642. */
  2643. OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")
  2644. hrErr = lpPersistStg->lpVtbl->SaveCompleted(
  2645. lpPersistStg,
  2646. ((FAILED(sc) || !fRemember) ? NULL : lpObjDestStg)
  2647. );
  2648. OLEDBG_END2
  2649. if (hrErr != NOERROR) {
  2650. OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);
  2651. if (sc == S_OK)
  2652. sc = GetScode(hrErr);
  2653. }
  2654. if (sc != S_OK) {
  2655. OleStdVerifyRelease(
  2656. (LPUNKNOWN)lpObjDestStg,
  2657. "Copied object stg not released"
  2658. );
  2659. return FALSE;
  2660. }
  2661. /* if we are supposed to remember this storage as the new
  2662. ** storage for the object, then release the old one and
  2663. ** save the new one. else, throw away the new one.
  2664. */
  2665. if (fRemember) {
  2666. OleStdVerifyRelease(
  2667. (LPUNKNOWN)lpContainerLine->m_lpStg,
  2668. "Original object stg not released"
  2669. );
  2670. lpContainerLine->m_lpStg = lpObjDestStg;
  2671. } else {
  2672. OleStdVerifyRelease(
  2673. (LPUNKNOWN)lpObjDestStg,
  2674. "Copied object stg not released"
  2675. );
  2676. }
  2677. }
  2678. }
  2679. /* OLE2NOTE: after saving an OLE object it is possible that it sent
  2680. ** an OnViewChange notification because it had been modified. in
  2681. ** this situation it is possible that the extents of the object
  2682. ** have changed. if so we want to relayout the space for the
  2683. ** object immediately so that the extent information saved with
  2684. ** the ContainerLine match the data saved with the OLE object
  2685. ** itself.
  2686. */
  2687. if (lpContainerLine->m_fDoGetExtent) {
  2688. BOOL fSizeChanged = ContainerLine_UpdateExtent(lpContainerLine, NULL);
  2689. #if defined( INPLACE_CNTR )
  2690. /* if the extents of this ContainerLine have changed, then we
  2691. ** need to reset the fDoGetExtent flag to TRUE so that later
  2692. ** when ContainerDoc_UpdateExtentOfAllOleObjects is called
  2693. ** (when the WM_U_UPDATEOBJECTEXTENT message is processed),
  2694. ** it is recognized that the extents of this line have
  2695. ** changed. if any line changes size, then any in-place
  2696. ** active object below this line must be told to update the
  2697. ** position of their windows (via SetObjectRects -- see
  2698. ** ContainerDoc_UpdateInPlaceObjectRects function).
  2699. */
  2700. lpContainerLine->m_fDoGetExtent = fSizeChanged;
  2701. #endif
  2702. }
  2703. return TRUE;
  2704. }
  2705. /* ContainerLine_LoadFromStg
  2706. ** -------------------------
  2707. ** Create a ContainerLine object and initialize it with data that
  2708. ** was previously writen to an IStorage*. this function does not
  2709. ** immediately OleLoad the associated OLE object, only the data of
  2710. ** the ContainerLine object itself is loaded from the IStorage*.
  2711. */
  2712. LPLINE ContainerLine_LoadFromStg(
  2713. LPSTORAGE lpSrcStg,
  2714. LPSTREAM lpLLStm,
  2715. LPOUTLINEDOC lpDestDoc
  2716. )
  2717. {
  2718. HDC hDC;
  2719. LPLINELIST lpDestLL = &lpDestDoc->m_LineList;
  2720. ULONG nRead;
  2721. HRESULT hrErr;
  2722. LPCONTAINERLINE lpContainerLine;
  2723. CONTAINERLINERECORD_ONDISK objLineRecord;
  2724. lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));
  2725. if (lpContainerLine == NULL) {
  2726. OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");
  2727. return NULL;
  2728. }
  2729. hDC = LineList_GetDC(lpDestLL);
  2730. ContainerLine_Init(lpContainerLine, 0, hDC);
  2731. LineList_ReleaseDC(lpDestLL, hDC);
  2732. /* OLE2NOTE: In order to have a stable ContainerLine object we must
  2733. ** AddRef the object's refcnt. this will be later released when
  2734. ** the ContainerLine is deleted.
  2735. */
  2736. ContainerLine_AddRef(lpContainerLine);
  2737. lpContainerLine->m_lpDoc = (LPCONTAINERDOC) lpDestDoc;
  2738. /* read line record */
  2739. hrErr = lpLLStm->lpVtbl->Read(
  2740. lpLLStm,
  2741. (LPVOID)&objLineRecord,
  2742. sizeof(objLineRecord),
  2743. &nRead
  2744. );
  2745. if (hrErr != NOERROR) {
  2746. OleDbgAssertSz(hrErr==NOERROR, "Could not read from LineList stream");
  2747. goto error;
  2748. }
  2749. // Compilers should handle aligment correctly
  2750. lstrcpy(lpContainerLine->m_szStgName, objLineRecord.m_szStgName);
  2751. lpContainerLine->m_fMonikerAssigned = (BOOL) objLineRecord.m_fMonikerAssigned;
  2752. lpContainerLine->m_dwDrawAspect = objLineRecord.m_dwDrawAspect;
  2753. lpContainerLine->m_sizeInHimetric = objLineRecord.m_sizeInHimetric;
  2754. lpContainerLine->m_dwLinkType = objLineRecord.m_dwLinkType;
  2755. lpContainerLine->m_fDoSetExtent = (BOOL) objLineRecord.m_fDoSetExtent;
  2756. return (LPLINE)lpContainerLine;
  2757. error:
  2758. // destroy partially created ContainerLine
  2759. if (lpContainerLine)
  2760. ContainerLine_Delete(lpContainerLine);
  2761. return NULL;
  2762. }
  2763. /* ContainerLine_GetTextLen
  2764. * ------------------------
  2765. *
  2766. * Return length of the string representation of the ContainerLine
  2767. * (not considering the tab level). we will use the following as the
  2768. * string representation of a ContainerLine:
  2769. * "<" + user type name of OLE object + ">"
  2770. * eg:
  2771. * <Microsoft Excel Worksheet>
  2772. */
  2773. int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine)
  2774. {
  2775. LPSTR lpszUserType = NULL;
  2776. HRESULT hrErr;
  2777. int nLen;
  2778. BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine);
  2779. /* if object is not already loaded, then load it now. objects are
  2780. ** loaded lazily in this manner.
  2781. */
  2782. if (! lpContainerLine->m_lpOleObj)
  2783. ContainerLine_LoadOleObject(lpContainerLine);
  2784. OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")
  2785. hrErr = CallIOleObjectGetUserTypeA(
  2786. lpContainerLine->m_lpOleObj,
  2787. USERCLASSTYPE_FULL,
  2788. &lpszUserType
  2789. );
  2790. OLEDBG_END2
  2791. if (hrErr != NOERROR) {
  2792. // user type is NOT available
  2793. nLen = sizeof(UNKNOWN_OLEOBJ_TYPE) + 2; // allow space for '<' + '>'
  2794. nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1;
  2795. } else {
  2796. nLen = lstrlen(lpszUserType) + 2; // allow space for '<' + '>'
  2797. nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1;
  2798. /* OLE2NOTE: we must free the string that was allocated by the
  2799. ** IOleObject::GetUserType method.
  2800. */
  2801. OleStdFreeString(lpszUserType, NULL);
  2802. }
  2803. return nLen;
  2804. }
  2805. /* ContainerLine_GetTextData
  2806. * -------------------------
  2807. *
  2808. * Return the string representation of the ContainerLine
  2809. * (not considering the tab level). we will use the following as the
  2810. * string representation of a ContainerLine:
  2811. * "<" + user type name of OLE object + ">"
  2812. * eg:
  2813. * <Microsoft Excel Worksheet>
  2814. */
  2815. void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine, LPSTR lpszBuf)
  2816. {
  2817. LPSTR lpszUserType = NULL;
  2818. BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine);
  2819. HRESULT hrErr;
  2820. /* if object is not already loaded, then load it now. objects are
  2821. ** loaded lazily in this manner.
  2822. */
  2823. if (! lpContainerLine->m_lpOleObj)
  2824. ContainerLine_LoadOleObject(lpContainerLine);
  2825. hrErr = CallIOleObjectGetUserTypeA(
  2826. lpContainerLine->m_lpOleObj,
  2827. USERCLASSTYPE_FULL,
  2828. &lpszUserType
  2829. );
  2830. if (hrErr != NOERROR) {
  2831. // user type is NOT available
  2832. wsprintf(
  2833. lpszBuf,
  2834. "<%s %s>",
  2835. UNKNOWN_OLEOBJ_TYPE,
  2836. (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)
  2837. );
  2838. } else {
  2839. wsprintf(
  2840. lpszBuf,
  2841. "<%s %s>",
  2842. lpszUserType,
  2843. (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)
  2844. );
  2845. /* OLE2NOTE: we must free the string that was allocated by the
  2846. ** IOleObject::GetUserType method.
  2847. */
  2848. OleStdFreeString(lpszUserType, NULL);
  2849. }
  2850. }
  2851. /* ContainerLine_GetOutlineData
  2852. * ----------------------------
  2853. *
  2854. * Return the CF_OUTLINE format data for the ContainerLine.
  2855. */
  2856. BOOL ContainerLine_GetOutlineData(
  2857. LPCONTAINERLINE lpContainerLine,
  2858. LPTEXTLINE lpBuf
  2859. )
  2860. {
  2861. LPLINE lpLine = (LPLINE)lpContainerLine;
  2862. LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList;
  2863. HDC hDC;
  2864. char szTmpBuf[MAXSTRLEN+1];
  2865. LPTEXTLINE lpTmpTextLine;
  2866. // Create a TextLine with the Text representation of the ContainerLine.
  2867. ContainerLine_GetTextData(lpContainerLine, (LPSTR)szTmpBuf);
  2868. hDC = LineList_GetDC(lpLL);
  2869. lpTmpTextLine = TextLine_Create(hDC, lpLine->m_nTabLevel, szTmpBuf);
  2870. LineList_ReleaseDC(lpLL, hDC);
  2871. TextLine_Copy(lpTmpTextLine, lpBuf);
  2872. // Delete the temporary TextLine
  2873. TextLine_Delete(lpTmpTextLine);
  2874. return TRUE;
  2875. }
  2876. /* ContainerLine_GetPosRect
  2877. ** -----------------------
  2878. ** Get the PosRect in client coordinates for the OLE object's window.
  2879. **
  2880. ** OLE2NOTE: the PosRect must take into account the scroll postion of
  2881. ** the document window.
  2882. */
  2883. void ContainerLine_GetPosRect(
  2884. LPCONTAINERLINE lpContainerLine,
  2885. LPRECT lprcPosRect
  2886. )
  2887. {
  2888. ContainerLine_GetOleObjectRectInPixels(lpContainerLine,lprcPosRect);
  2889. // shift rect for left margin
  2890. lprcPosRect->left += lpContainerLine->m_nHorizScrollShift;
  2891. lprcPosRect->right += lpContainerLine->m_nHorizScrollShift;
  2892. }
  2893. /* ContainerLine_GetOleObjectRectInPixels
  2894. ** --------------------------------------
  2895. ** Get the extent of the OLE Object contained in the given Line in
  2896. ** client coordinates after scaling.
  2897. */
  2898. void ContainerLine_GetOleObjectRectInPixels(LPCONTAINERLINE lpContainerLine, LPRECT lprc)
  2899. {
  2900. LPOUTLINEDOC lpOutlineDoc;
  2901. LPSCALEFACTOR lpscale;
  2902. LPLINELIST lpLL;
  2903. LPLINE lpLine;
  2904. int nIndex;
  2905. HDC hdcLL;
  2906. if (!lpContainerLine || !lprc)
  2907. return;
  2908. lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
  2909. lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);
  2910. lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
  2911. lpLine = (LPLINE)lpContainerLine;
  2912. nIndex = LineList_GetLineIndex(lpLL, lpLine);
  2913. LineList_GetLineRect(lpLL, nIndex, lprc);
  2914. hdcLL = GetDC(lpLL->m_hWndListBox);
  2915. /* lprc is set to be size of Line Object (including the boundary) */
  2916. lprc->left += (int)(
  2917. (long)XformWidthInHimetricToPixels(hdcLL,
  2918. lpLine->m_nTabWidthInHimetric +
  2919. LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *
  2920. lpscale->dwSxN / lpscale->dwSxD);
  2921. lprc->right = (int)(
  2922. lprc->left + (long)
  2923. XformWidthInHimetricToPixels(hdcLL, lpLine->m_nWidthInHimetric) *
  2924. lpscale->dwSxN / lpscale->dwSxD);
  2925. ReleaseDC(lpLL->m_hWndListBox, hdcLL);
  2926. }
  2927. /* ContainerLine_GetOleObjectSizeInHimetric
  2928. ** ----------------------------------------
  2929. ** Get the size of the OLE Object contained in the given Line
  2930. */
  2931. void ContainerLine_GetOleObjectSizeInHimetric(LPCONTAINERLINE lpContainerLine, LPSIZEL lpsizel)
  2932. {
  2933. if (!lpContainerLine || !lpsizel)
  2934. return;
  2935. *lpsizel = lpContainerLine->m_sizeInHimetric;
  2936. }
  2937. /* ContainerLine_BindLinkIfLinkSrcIsRunning
  2938. ** ----------------------------------------
  2939. ** Try to connect the OLE link object associated with the
  2940. ** ContainerLine with its LinkSource if the LinkSource is already
  2941. ** running and the link is an automatic link. we do not want to
  2942. ** force the LinkSource to run.
  2943. **
  2944. ** OLE2NOTE: a sophistocated container will want to continually
  2945. ** attempt to connect its automatic links. OLE does NOT
  2946. ** automatically connect links when link source become available. some
  2947. ** containers will want to attempt to connect its links as part of
  2948. ** idle time processing. another strategy is to attempt to connect
  2949. ** an automatic link every time it is drawn on the screen. (this is
  2950. ** the strategy used by this CntrOutl sample application.)
  2951. */
  2952. void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine)
  2953. {
  2954. LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
  2955. HRESULT hrErr;
  2956. BOOL fPrevEnable1;
  2957. BOOL fPrevEnable2;
  2958. // if the link source is known to be un-bindable, then don't even try
  2959. if (lpContainerLine->m_fLinkUnavailable)
  2960. return;
  2961. /* OLE2NOTE: we do not want to ever give the Busy/NotResponding
  2962. ** dialogs when we are attempting to BindIfRunning to the link
  2963. ** source. if the link source is currently busy, this could
  2964. ** cause the Busy dialog to come up. even if the link source is
  2965. ** busy, we do not want put up the busy dialog. thus we will
  2966. ** disable the dialog and later re-enable them
  2967. */
  2968. OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);
  2969. OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n")
  2970. hrErr = lpContainerLine->m_lpOleLink->lpVtbl->BindIfRunning(
  2971. lpContainerLine->m_lpOleLink);
  2972. OLEDBG_END2
  2973. // re-enable the Busy/NotResponding dialogs
  2974. OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);
  2975. }