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