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

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