|
|
1.1 root 1: /*************************************************************************
2: **
3: ** OLE 2 Container Sample Code
4: **
5: ** cntrbase.c
6: **
7: ** This file contains all interfaces, methods and related support
8: ** functions for the basic OLE Container application. The
9: ** basic OLE Container application supports being a container for
10: ** embedded and linked objects.
11: ** The basic Container application includes the following
12: ** implementation objects:
13: **
14: ** ContainerDoc Object
15: ** no required interfaces for basic functionality
16: ** (see linking.c for linking related support)
17: ** (see clipbrd.c for clipboard related support)
18: ** (see dragdrop.c for drag/drop related support)
19: **
20: ** ContainerLine Object
21: ** (see cntrline.c for all ContainerLine functions and interfaces)
22: ** exposed interfaces:
23: ** IOleClientSite
24: ** IAdviseSink
25: **
26: ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
27: **
28: *************************************************************************/
29:
30: #include "outline.h"
31: #include <geticon.h> // for OleStdGetUserTypeOfClass
32:
33:
34: OLEDBGDATA
35:
36:
37: extern LPOUTLINEAPP g_lpApp;
38: extern IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl;
39:
40:
41: // REVIEW: should use string resource for messages
42: char ErrMsgShowObj[] = "Could not show object server!";
43: char ErrMsgInsertObj[] = "Insert Object failed!";
44: char ErrMsgConvertObj[] = "Convert Object failed!";
45: char ErrMsgCantConvert[] = "Unable to convert the selection!";
46: char ErrMsgActivateAsObj[] = "Activate As Object failed!";
47:
48: extern char ErrMsgSaving[];
49: extern char ErrMsgOpening[];
50:
51:
52: /* ContainerDoc_Init
53: * -----------------
54: *
55: * Initialize the fields of a new ContainerDoc object. The doc is initially
56: * not associated with a file or an (Untitled) document. This function sets
57: * the docInitType to DOCTYPE_UNKNOWN. After calling this function the
58: * caller should call:
59: * 1.) Doc_InitNewFile to set the ContainerDoc to (Untitled)
60: * 2.) Doc_LoadFromFile to associate the ContainerDoc with a file.
61: * This function creates a new window for the document.
62: *
63: * NOTE: the window is initially created with a NIL size. it must be
64: * sized and positioned by the caller. also the document is initially
65: * created invisible. the caller must call Doc_ShowWindow
66: * after sizing it to make the document window visible.
67: */
68: BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc)
69: {
70: LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
71: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
72:
73: lpOutlineDoc->m_cfSaveFormat = lpContainerApp->m_cfCntrOutl;
74: lpContainerDoc->m_nNextObjNo = 0L;
75: lpContainerDoc->m_lpStg = NULL;
76: lpContainerDoc->m_lpNewStg = NULL;
77: lpContainerDoc->m_fEmbeddedObjectAvail = FALSE;
78: lpContainerDoc->m_clsidOleObjCopied = CLSID_NULL;
79: lpContainerDoc->m_dwAspectOleObjCopied = DVASPECT_CONTENT;
80: lpContainerDoc->m_lpSrcContainerLine = NULL;
81: lpContainerDoc->m_fShowObject = TRUE;
82:
83: #if defined( INPLACE_CNTR )
84: lpContainerDoc->m_lpLastIpActiveLine = NULL;
85: lpContainerDoc->m_lpLastUIActiveLine = NULL;
86: lpContainerDoc->m_hwndUIActiveObj = NULL;
87: lpContainerDoc->m_fAddMyUI = TRUE; // UI needs to be added
88: lpContainerDoc->m_cIPActiveObjects = 0;
89:
90: #if defined( INPLACE_CNTRSVR )
91: lpContainerDoc->m_lpTopIPFrame =
92: (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceFrame;
93: lpContainerDoc->m_lpTopIPDoc =
94: (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc;
95: lpContainerDoc->m_hSharedMenu = NULL;
96: lpContainerDoc->m_hOleMenu = NULL;
97:
98: #endif // INPLACE_CNTRSVR
99: #endif // INPLACE_CNTR
100:
101: INIT_INTERFACEIMPL(
102: &lpContainerDoc->m_OleUILinkContainer,
103: &g_CntrDoc_OleUILinkContainerVtbl,
104: lpContainerDoc
105: );
106:
107: return TRUE;
108: }
109:
110:
111: /* ContainerDoc_GetNextLink
112: * ------------------------
113: *
114: * Update all links in the document. A dialog box will be popped up showing
115: * the progress of the update and allow the user to quit by pushing the
116: * stop button
117: */
118: LPCONTAINERLINE ContainerDoc_GetNextLink(
119: LPCONTAINERDOC lpContainerDoc,
120: LPCONTAINERLINE lpContainerLine
121: )
122: {
123: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
124: DWORD dwNextLink = 0;
125: LPLINE lpLine;
126: static int nIndex = 0;
127:
128: if (lpContainerLine==NULL)
129: nIndex = 0;
130:
131: for ( ; nIndex < lpLL->m_nNumLines; nIndex++) {
132: lpLine = LineList_GetLine(lpLL, nIndex);
133:
134: if (lpLine
135: && (Line_GetLineType(lpLine) == CONTAINERLINETYPE)
136: && ContainerLine_IsOleLink((LPCONTAINERLINE)lpLine)) {
137:
138: nIndex++;
139: return (LPCONTAINERLINE)lpLine;
140: }
141: }
142:
143: return NULL;
144: }
145:
146:
147:
148: /* ContainerDoc_UpdateLinks
149: * ------------------------
150: *
151: * Update all links in the document. A dialog box will be popped up showing
152: * the progress of the update and allow the user to quit by pushing the
153: * stop button
154: */
155: void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc)
156: {
157: int cLinks;
158: HWND hwndDoc = ((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
159: HCURSOR hCursor;
160: LPCONTAINERLINE lpContainerLine = NULL;
161: HRESULT hrErr;
162: DWORD dwUpdateOpt;
163:
164: hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
165:
166: /* get total number of automatic links */
167: cLinks = 0;
168: while (lpContainerLine = ContainerDoc_GetNextLink(
169: lpContainerDoc,
170: lpContainerLine)) {
171: hrErr = CntrDoc_LinkCont_GetLinkUpdateOptions(
172: (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer,
173: (DWORD)lpContainerLine,
174: (LPDWORD)&dwUpdateOpt
175: );
176: if (hrErr == NOERROR) {
177: if (dwUpdateOpt==OLEUPDATE_ALWAYS)
178: cLinks++;
179: }
180: else
181: OleDbgOutHResult("IOleUILinkContainer::GetLinkUpdateOptions returned",hrErr);
182:
183: }
184:
185: SetCursor(hCursor);
186:
187: if ((cLinks > 0) && !OleUIUpdateLinks(
188: (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer,
189: hwndDoc,
190: (LPSTR)APPNAME,
191: cLinks)) {
192: if (ID_PU_LINKS == OleUIPromptUser(
193: IDD_CANNOTUPDATELINK,
194: hwndDoc,
195: (LPSTR)APPNAME)) {
196: ContainerDoc_EditLinksCommand(lpContainerDoc);
197: }
198: }
199: }
200:
201:
202:
203: /* ContainerDoc_SetShowObjectFlag
204: * ------------------------------
205: *
206: * Set/Clear the ShowObject flag of ContainerDoc
207: */
208: void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow)
209: {
210: if (!lpContainerDoc)
211: return;
212:
213: lpContainerDoc->m_fShowObject = fShow;
214: }
215:
216:
217: /* ContainerDoc_GetShowObjectFlag
218: * ------------------------------
219: *
220: * Get the ShowObject flag of ContainerDoc
221: */
222: BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc)
223: {
224: if (!lpContainerDoc)
225: return FALSE;
226:
227: return lpContainerDoc->m_fShowObject;
228: }
229:
230:
231: /* ContainerDoc_InsertOleObjectCommand
232: * -----------------------------------
233: *
234: * Insert a new OLE object in the ContainerDoc.
235: */
236: void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc)
237: {
238: LPLINELIST lpLL =&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
239: LPLINE lpLine = NULL;
240: HDC hDC;
241: int nTab = 0;
242: int nIndex = LineList_GetFocusLineIndex(lpLL);
243: LPCONTAINERLINE lpContainerLine=NULL;
244: char szStgName[CWCSTORAGENAME];
245: UINT uRet;
246: OLEUIINSERTOBJECT io;
247: char szFile[OLEUI_CCHPATHMAX];
248: DWORD dwOleCreateType;
249: BOOL fDisplayAsIcon;
250: HCURSOR hPrevCursor;
251:
252: //String initially NULL.
253: _fmemset((LPSTR)szFile, 0, OLEUI_CCHPATHMAX);
254:
255: _fmemset((LPOLEUIINSERTOBJECT)&io, 0, sizeof(io));
256: io.cbStruct=sizeof(io);
257: io.dwFlags=IOF_SELECTCREATENEW | IOF_SHOWHELP;
258: io.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
259:
260: io.lpszFile=(LPSTR)szFile;
261: io.cchFile=sizeof(szFile);
262:
263: OLEDBG_BEGIN3("OleUIInsertObject called\r\n")
264: uRet=OleUIInsertObject((LPOLEUIINSERTOBJECT)&io);
265: OLEDBG_END3
266:
267: if (OLEUI_OK != uRet)
268: return; // user canceled dialog
269:
270: // this may take a while, put up hourglass cursor
271: hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
272:
273: fDisplayAsIcon = (io.dwFlags & IOF_CHECKDISPLAYASICON ? TRUE : FALSE);
274:
275: // make up a storage name for the OLE object
276: ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
277:
278: /* default the new line to have the same indent as previous line */
279: lpLine = LineList_GetLine(lpLL, nIndex);
280: if (lpLine)
281: nTab = Line_GetTabLevel(lpLine);
282:
283: hDC = LineList_GetDC(lpLL);
284:
285: //Only try to create new objects IF Create New was selected
286: if ((io.dwFlags & IOF_SELECTCREATENEW))
287: dwOleCreateType = IOF_SELECTCREATENEW;
288: else
289: {
290: if ((io.dwFlags & IOF_SELECTCREATEFROMFILE))
291: dwOleCreateType = IOF_SELECTCREATEFROMFILE;
292:
293: if ((io.dwFlags & IOF_CHECKLINK))
294: dwOleCreateType = IOF_CHECKLINK;
295: }
296:
297: lpContainerLine = ContainerLine_Create(
298: dwOleCreateType,
299: hDC,
300: nTab,
301: lpContainerDoc,
302: &io.clsid,
303: (LPSTR)szFile,
304: fDisplayAsIcon,
305: io.hMetaPict,
306: szStgName
307: );
308:
309: if (!lpContainerLine)
310: goto error; // creation of OLE object FAILED
311:
312: if (io.hMetaPict) {
313: OleUIMetafilePictIconFree(io.hMetaPict); // clean up metafile
314: }
315:
316: /* add a ContainerLine object to the document's LineList. The
317: ** ContainerLine manages the rectangle on the screen occupied by
318: ** the OLE object. later when the app is updated to support
319: ** extended layout, there could be more than one Line associated
320: ** with the OLE object.
321: */
322:
323: LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);
324:
325: /* before calling DoVerb(OLEIVERB_SHOW), check to see if the object
326: ** has any initial extents.
327: */
328: ContainerLine_UpdateExtent(lpContainerLine, NULL);
329:
330: /* If a new embedded object was created, tell the object server to
331: ** make itself visible (show itself).
332: */
333: if (dwOleCreateType == IOF_SELECTCREATENEW) {
334: if (! ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, TRUE,
335: TRUE)) {
336: OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj);
337: }
338:
339: /* OLE2NOTE: we will immediately force a save of the object
340: ** to guarantee that a valid initial object is saved
341: ** with our document. if the object is a OLE 1.0 object,
342: ** then it may exit without update. by forcing this
343: ** initial save we consistently always have a valid
344: ** object even if it is a OLE 1.0 object that exited
345: ** without saving. if we did NOT do this save here, then
346: ** we would have to worry about deleting the object if
347: ** it was a OLE 1.0 object that closed without saving.
348: ** the OLE 2.0 User Model dictates that the object
349: ** should always be valid after CreateNew performed. the
350: ** user must explicitly delete it.
351: */
352: ContainerLine_SaveOleObject(
353: lpContainerLine,
354: lpContainerLine->m_lpStg,
355: TRUE, /* fSameAsLoad */
356: TRUE, /* fRemember */
357: TRUE /* fForceUpdate */
358: );
359: }
360:
361: OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);
362:
363: LineList_ReleaseDC(lpLL, hDC);
364:
365: SetCursor(hPrevCursor); // restore original cursor
366:
367: return;
368:
369: error:
370: // NOTE: if ContainerLine_Create failed
371: LineList_ReleaseDC(lpLL, hDC);
372:
373: if (OLEUI_OK == uRet && io.hMetaPict)
374: OleUIMetafilePictIconFree(io.hMetaPict); // clean up metafile
375:
376: SetCursor(hPrevCursor); // restore original cursor
377: OutlineApp_ErrorMessage(g_lpApp, ErrMsgInsertObj);
378: }
379:
380:
381:
382: void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc)
383: {
384: UINT uRet;
385: OLEUIEDITLINKS el;
386: LPCONTAINERLINE lpContainerLine = NULL;
387: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
388:
389: _fmemset((LPOLEUIEDITLINKS)&el,0,sizeof(el));
390: el.cbStruct=sizeof(el);
391: el.dwFlags=ELF_SHOWHELP; //what else?
392: el.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
393: el.lpOleUILinkContainer =
394: (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer;
395:
396: OLEDBG_BEGIN3("OleUIEditLinks called\r\n")
397: uRet=OleUIEditLinks((LPOLEUIEDITLINKS)&el);
398: OLEDBG_END3
399:
400: OleDbgAssert((uRet==1) || (uRet==OLEUI_CANCEL));
401:
402: }
403:
404:
405: /* Convert command - brings up the "Convert" dialog
406: */
407: void ContainerDoc_ConvertCommand(
408: LPCONTAINERDOC lpContainerDoc,
409: BOOL fServerNotRegistered
410: )
411: {
412: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
413: OLEUICONVERT ct;
414: UINT uRet;
415: LPDATAOBJECT lpDataObj;
416: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
417: LPCONTAINERLINE lpContainerLine = NULL;
418: BOOL fSelIsOleObject;
419: int nIndex;
420: STGMEDIUM medium;
421: LPSTR lpErrMsg = NULL;
422: HRESULT hrErr;
423: HCURSOR hPrevCursor;
424: BOOL fRunServer=FALSE;
425: BOOL fMustRun = FALSE;
426: BOOL fObjConverted = FALSE;
427: BOOL fDisplayChanged = FALSE;
428: BOOL fHaveCLSID = FALSE;
429: BOOL fHaveFmtUserType = FALSE;
430: char szUserType[128];
431: BOOL fMustActivate;
432:
433: /* OLE2NOTE: if we came to the Convert dialog because the user
434: ** activated a non-registered object, then we should activate
435: ** the object after the user has converted it or setup an
436: ** ActivateAs server.
437: */
438: fMustActivate = fServerNotRegistered;
439:
440: _fmemset((LPOLEUICONVERT)&ct,0,sizeof(ct));
441:
442: fSelIsOleObject = ContainerDoc_IsSelAnOleObject(
443: (LPCONTAINERDOC)lpContainerDoc,
444: &IID_IDataObject,
445: (LPUNKNOWN FAR*)&lpDataObj,
446: &nIndex,
447: (LPCONTAINERLINE FAR*)&lpContainerLine
448: );
449:
450: lpErrMsg = ErrMsgCantConvert;
451:
452: if (! fSelIsOleObject)
453: goto error; // can NOT do Convert.
454:
455: if (! lpContainerLine) {
456: OleStdRelease((LPUNKNOWN)lpDataObj);
457: goto error; // can NOT do Convert.
458: }
459:
460: ct.cbStruct = sizeof(OLEUICONVERT);
461: ct.dwFlags = CF_SHOWHELPBUTTON;
462: ct.hWndOwner = lpContainerDoc->m_OleDoc.m_OutlineDoc.m_hWndDoc;
463: ct.lpszCaption = (LPSTR)NULL;
464: ct.lpfnHook = NULL;
465: ct.lCustData = 0;
466: ct.hInstance = NULL;
467: ct.lpszTemplate = NULL;
468: ct.hResource = 0;
469: ct.fIsLinkedObject = ContainerLine_IsOleLink(lpContainerLine);
470: ct.dvAspect = lpContainerLine->m_dwDrawAspect;
471:
472: if (! ct.fIsLinkedObject) {
473: /* OLE2NOTE: the object is an embedded object. we should first
474: ** attempt to read the actual object CLSID, file data
475: ** format, and full user type name that is written inside of
476: ** the object's storage as this should be the most
477: ** definitive information. if this fails we will ask the
478: ** object what its class is and attempt to get the rest of
479: ** the information out of the REGDB.
480: */
481: hrErr=ReadClassStg(lpContainerLine->m_lpStg,(CLSID FAR*)&(ct.clsid));
482: if (hrErr == NOERROR)
483: fHaveCLSID = TRUE;
484: else {
485: OleDbgOutHResult("ReadClassStg returned", hrErr);
486: }
487: hrErr = ReadFmtUserTypeStg(
488: lpContainerLine->m_lpStg,
489: (CLIPFORMAT FAR*)&ct.wFormat,
490: (LPSTR FAR*)&ct.lpszUserType);
491: if (hrErr == NOERROR)
492: fHaveFmtUserType = TRUE;
493: else {
494: OleDbgOutHResult("ReadFmtUserTypeStg returned", hrErr);
495: }
496: }
497:
498: if (! fHaveCLSID) {
499: hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(
500: lpContainerLine->m_lpOleObj,
501: (CLSID FAR*)&ct.clsid
502: );
503: if (hrErr != NOERROR)
504: ct.clsid = CLSID_NULL;
505: }
506: if (! fHaveFmtUserType) {
507: ct.wFormat = 0;
508: if (OleStdGetUserTypeOfClass(
509: (CLSID FAR*)&ct.clsid,szUserType,sizeof(szUserType),NULL)) {
510: ct.lpszUserType = OleStdCopyString(szUserType, NULL);
511: } else {
512: ct.lpszUserType = NULL;
513: }
514: }
515:
516: if (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON) {
517: ct.hMetaPict = OleStdGetData(
518: lpDataObj,
519: CF_METAFILEPICT,
520: NULL,
521: DVASPECT_ICON,
522: (LPSTGMEDIUM)&medium
523: );
524: } else {
525: ct.hMetaPict = NULL;
526: }
527: OleStdRelease((LPUNKNOWN)lpDataObj);
528:
529: OLEDBG_BEGIN3("OleUIConvert called\r\n")
530: uRet = OleUIConvert(&ct);
531: OLEDBG_END3
532:
533: // this may take a while, put up hourglass cursor
534: hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
535:
536: if (uRet == OLEUI_OK) {
537:
538: /*****************************************************************
539: ** OLE2NOTE: the convert dialog actually allows the user to
540: ** change two orthogonal properties of the object: the
541: ** object's type/server and the object's display aspect.
542: ** first we will execute the ConvertTo/ActivateAs action and
543: ** then we will deal with any display aspect change. we want
544: ** to be careful to only call IOleObject::Update once
545: ** because this is an expensive operation; it results in
546: ** launching the object's server.
547: *****************************************************************/
548:
549: if (ct.dwFlags & CF_SELECTCONVERTTO &&
550: ! IsEqualCLSID(&ct.clsid, &ct.clsidNew)) {
551:
552: /* user selected CONVERT.
553: **
554: ** OLE2NOTE: to achieve the "Convert To" at this point we
555: ** need to take the following steps:
556: ** 1. unload the object.
557: ** 2. write the NEW CLSID and NEW user type name
558: ** string into the storage of the object,
559: ** BUT write the OLD format tag.
560: ** 3. force an update to force the actual conversion of
561: ** the data bits.
562: */
563: lpErrMsg = ErrMsgConvertObj; // setup correct msg in case of error
564:
565: ContainerLine_UnloadOleObject(lpContainerLine);
566:
567: OLEDBG_BEGIN2("OleStdDoConvert called \r\n")
568: hrErr = OleStdDoConvert(
569: lpContainerLine->m_lpStg, (REFCLSID)&ct.clsidNew);
570: OLEDBG_END2
571: if (hrErr != NOERROR)
572: goto error;
573:
574: // Reload the object
575: ContainerLine_LoadOleObject(lpContainerLine);
576:
577: /* we need to force the object to run to complete the
578: ** conversion. set flag to force OleRun to be called at
579: ** end of function.
580: */
581: fMustRun = TRUE;
582: fObjConverted = TRUE;
583:
584: } else if (ct.dwFlags & CF_SELECTACTIVATEAS) {
585: /* user selected ACTIVATE AS.
586: **
587: ** OLE2NOTE: to achieve the "Activate As" at this point we
588: ** need to take the following steps:
589: ** 1. unload ALL objects of the OLD class that app knows about
590: ** 2. add the TreatAs tag in the registration database
591: ** by calling CoTreatAsClass().
592: ** 3. lazily it can reload the objects; when the objects
593: ** are reloaded the TreatAs will take effect.
594: */
595: lpErrMsg = ErrMsgActivateAsObj; // setup msg in case of error
596:
597: ContainerDoc_UnloadAllOleObjectsOfClass(
598: lpContainerDoc, (REFCLSID)&ct.clsid);
599:
600: OLEDBG_BEGIN2("OleStdDoTreatAsClass called \r\n")
601: hrErr = OleStdDoTreatAsClass(ct.lpszUserType, (REFCLSID)&ct.clsid,
602: (REFCLSID)&ct.clsidNew);
603: OLEDBG_END2
604:
605: // Reload the object
606: ContainerLine_LoadOleObject(lpContainerLine);
607:
608: fMustActivate = TRUE; // we should activate this object
609: }
610:
611: /*****************************************************************
612: ** OLE2NOTE: now we will try to change the display if
613: ** necessary.
614: *****************************************************************/
615:
616: if (lpContainerLine->m_lpOleObj &&
617: ct.dvAspect != lpContainerLine->m_dwDrawAspect) {
618: /* user has selected to change display aspect between icon
619: ** aspect and content aspect.
620: **
621: ** OLE2NOTE: if we got here because the server was not
622: ** registered, then we will NOT delete the object's
623: ** original display aspect. because we do not have the
624: ** original server, we can NEVER get it back. this is a
625: ** safety precaution.
626: */
627:
628: hrErr = OleStdSwitchDisplayAspect(
629: lpContainerLine->m_lpOleObj,
630: &lpContainerLine->m_dwDrawAspect,
631: ct.dvAspect,
632: ct.hMetaPict,
633: !fServerNotRegistered, /* fDeleteOldAspect */
634: TRUE, /* fSetupViewAdvise */
635: (LPADVISESINK)&lpContainerLine->m_AdviseSink,
636: (BOOL FAR*)&fMustRun
637: );
638:
639: if (hrErr == NOERROR)
640: fDisplayChanged = TRUE;
641:
642: #if defined( INPLACE_CNTR )
643: ContainerDoc_UpdateInPlaceObjectRects(
644: lpContainerLine->m_lpDoc, nIndex);
645: #endif
646:
647: } else if (ct.dvAspect == DVASPECT_ICON && ct.fObjectsIconChanged) {
648: hrErr = OleStdSetIconInCache(
649: lpContainerLine->m_lpOleObj,
650: ct.hMetaPict
651: );
652:
653: if (hrErr == NOERROR)
654: fDisplayChanged = TRUE;
655: }
656:
657: /* we deliberately run the object so that the update won't shut
658: ** the server down.
659: */
660: if ((fMustActivate || fMustRun)
661: && !OleIsRunning(lpContainerLine->m_lpOleObj)) {
662: ContainerLine_RunOleObject(lpContainerLine);
663: fRunServer = TRUE;
664: }
665:
666: if (fDisplayChanged) {
667: /* the Object's display was changed, force a repaint of
668: ** the line. note the extents of the object may have
669: ** changed.
670: */
671: ContainerLine_UpdateExtent(lpContainerLine, NULL);
672: LineList_ForceLineRedraw(lpLL, nIndex, TRUE);
673: }
674:
675: if (fDisplayChanged || fObjConverted) {
676: /* mark ContainerDoc as now dirty. if display changed, then
677: ** the extents of the object may have changed.
678: */
679: OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fDisplayChanged);
680: }
681:
682: if (fMustActivate)
683: ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, FALSE,FALSE);
684: else if (fRunServer) {
685: /* if we launched the server in order to get an update of
686: ** the presentation, then we must shut the server down
687: */
688: ContainerLine_CloseOleObject(lpContainerLine);
689: }
690: }
691:
692:
693: if (ct.hMetaPict)
694: OleUIMetafilePictIconFree(ct.hMetaPict); // clean up metafile
695:
696: SetCursor(hPrevCursor); // restore original cursor
697:
698: return;
699:
700: error:
701: if (fRunServer)
702: ContainerLine_CloseOleObject(lpContainerLine);
703:
704: if (ct.lpszUserType)
705: OleStdFreeString(ct.lpszUserType, NULL);
706:
707: if (ct.hMetaPict)
708: OleUIMetafilePictIconFree(ct.hMetaPict); // clean up metafile
709:
710: SetCursor(hPrevCursor); // restore original cursor
711: if (lpErrMsg)
712: OutlineApp_ErrorMessage(g_lpApp, lpErrMsg);
713:
714: }
715:
716:
717: /* ContainerDoc_CloseAllOleObjects
718: ** -------------------------------
719: ** Close all OLE objects. This forces all OLE objects to transition
720: ** from the running state to the loaded state.
721: **
722: ** Returns TRUE if all objects closed successfully
723: ** FALSE if any object could not be closed.
724: */
725: BOOL ContainerDoc_CloseAllOleObjects(LPCONTAINERDOC lpContainerDoc)
726: {
727: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
728: int i;
729: LPLINE lpLine;
730: BOOL fStatus = TRUE;
731:
732: for (i = 0; i < lpLL->m_nNumLines; i++) {
733: lpLine=LineList_GetLine(lpLL, i);
734:
735: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))
736: if (! ContainerLine_CloseOleObject((LPCONTAINERLINE)lpLine))
737: fStatus = FALSE;
738: }
739:
740: return fStatus;
741: }
742:
743:
744: /* ContainerDoc_UnloadAllOleObjectsOfClass
745: ** ---------------------------------------
746: ** Unload all OLE objects of a particular class. this is necessary
747: ** when a class level "ActivateAs" (aka. TreatAs) is setup. the user
748: ** can do this with the Convert dialog. for the TreatAs to take
749: ** effect, all objects of the class have to loaded and reloaded.
750: */
751: void ContainerDoc_UnloadAllOleObjectsOfClass(
752: LPCONTAINERDOC lpContainerDoc,
753: REFCLSID rClsid
754: )
755: {
756: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
757: int i;
758: LPLINE lpLine;
759: CLSID clsid;
760: HRESULT hrErr;
761:
762: for (i = 0; i < lpLL->m_nNumLines; i++) {
763: lpLine=LineList_GetLine(lpLL, i);
764:
765: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
766: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
767:
768: if (! lpContainerLine->m_lpOleObj)
769: continue; // this object is NOT loaded
770:
771: hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(
772: lpContainerLine->m_lpOleObj,
773: (CLSID FAR*)&clsid
774: );
775: if (hrErr == NOERROR &&
776: ( IsEqualCLSID((CLSID FAR*)&clsid,rClsid)
777: || IsEqualCLSID(rClsid,&CLSID_NULL) ) ) {
778: ContainerLine_UnloadOleObject(lpContainerLine);
779: }
780: }
781: }
782: }
783:
784:
785: /* ContainerDoc_UpdateExtentOfAllOleObjects
786: ** ----------------------------------------
787: ** Update the extents of any OLE object that is marked that its size
788: ** may have changed. when an IAdviseSink::OnViewChange notification
789: ** is received, the corresponding ContainerLine is marked
790: ** (m_fDoGetExtent==TRUE) and a message (WM_U_UPDATEOBJECTEXTENT) is
791: ** posted to the document indicating that there are dirty objects.
792: ** when this message is received, this function is called.
793: */
794: void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc)
795: {
796: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
797: int i;
798: LPLINE lpLine;
799: BOOL fStatus = TRUE;
800:
801: for (i = 0; i < lpLL->m_nNumLines; i++) {
802: lpLine=LineList_GetLine(lpLL, i);
803:
804: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
805: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
806:
807: if (lpContainerLine->m_fDoGetExtent)
808: ContainerLine_UpdateExtent(lpContainerLine, NULL);
809: }
810: }
811: }
812:
813:
814: BOOL ContainerDoc_SaveToFile(
815: LPCONTAINERDOC lpContainerDoc,
816: LPCSTR lpszFileName,
817: UINT uFormat,
818: BOOL fRemember
819: )
820: {
821: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
822: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
823: LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
824: LPSTORAGE lpDestStg;
825: BOOL fStatus;
826: BOOL fMustRelDestStg = FALSE;
827: HRESULT hrErr;
828:
829: if (fRemember) {
830: if (lpszFileName) {
831: fStatus = OutlineDoc_SetFileName(
832: lpOutlineDoc, (LPSTR)lpszFileName, NULL);
833: if (! fStatus) goto error;
834: }
835:
836: /* The ContainerDoc keeps its storage open at all times. it is not
837: ** necessary to reopen the file.
838: ** if SaveAs is pending, then lpNewStg is the new destination for
839: ** the save operation, else the existing storage is the dest.
840: */
841: lpDestStg = (lpContainerDoc->m_lpNewStg ?
842: lpContainerDoc->m_lpNewStg : lpContainerDoc->m_lpStg);
843: } else {
844: if (! lpszFileName)
845: goto error;
846:
847: /* OLE2NOTE: since we are preforming a SaveCopyAs operation, we
848: ** do not need to have the DocFile open in STGM_TRANSACTED mode.
849: ** there is less overhead to use STGM_DIRECT mode.
850: */
851: hrErr = StgCreateDocfile(
852: lpszFileName,
853: STGM_READWRITE|STGM_DIRECT|STGM_SHARE_DENY_WRITE|STGM_CREATE,
854: 0,
855: &lpDestStg
856: );
857: if (! OleDbgVerifySz(hrErr == NOERROR, "Could not create Docfile"))
858: goto error;
859: fMustRelDestStg = TRUE;
860: }
861:
862: /* OLE2NOTE: we must be sure to write our class ID into our
863: ** storage. this information is used by OLE to determine the
864: ** class of the data stored in our storage. Even for top
865: ** "file-level" objects this information should be written to
866: ** the file.
867: */
868: hrErr = WriteClassStg(lpDestStg, &CLSID_APP);
869: if(hrErr != NOERROR) goto error;
870:
871: fStatus = OutlineDoc_SaveSelToStg(
872: lpOutlineDoc,
873: NULL, // save all lines
874: uFormat,
875: lpDestStg,
876: TRUE // remember this stg
877: );
878:
879: if (fStatus)
880: fStatus = OleStdCommitStorage(lpDestStg);
881:
882: if (fRemember) {
883: /* if SaveAs was pending, then release the old storage and remember
884: ** the new storage as the active current storage. all data from
885: ** the old storage has been copied into the new storage.
886: */
887: if (lpContainerDoc->m_lpNewStg) {
888: OleStdRelease((LPUNKNOWN)lpContainerDoc->m_lpStg); // free old stg
889: lpContainerDoc->m_lpStg = lpContainerDoc->m_lpNewStg; // save new stg
890: lpContainerDoc->m_lpNewStg = NULL;
891: }
892: if (! fStatus) goto error;
893:
894: OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);
895:
896: /* OLE2NOTE: we must note the time this File-Based object has
897: ** been saved in the RunningObjectTable. this is necessary
898: ** for Container applications which support linking to
899: ** embedded objects. These change times are used as the
900: ** basis for IOleObject::IsUpToDate. It is important to set
901: ** the time of the file-based object following a save
902: ** operation to exactly the time of the saved file. this
903: ** helps IOleObject::IsUpToDate to give the correct answer
904: ** after a file has been saved.
905: */
906: OleStdNoteFileChangeTime(
907: lpOutlineDoc->m_szFileName, lpOleDoc->m_dwRegROT);
908: }
909:
910: if (fMustRelDestStg)
911: OleStdRelease((LPUNKNOWN)lpDestStg);
912: return TRUE;
913:
914: error:
915: if (fMustRelDestStg)
916: OleStdRelease((LPUNKNOWN)lpDestStg);
917: OutlineApp_ErrorMessage(g_lpApp, ErrMsgSaving);
918: return FALSE;
919: }
920:
921:
922: /* ContainerDoc_ContainerLineDoVerbCommand
923: ** ---------------------------------------
924: ** Execute a verb of the OLE object in the current focus line.
925: */
926: void ContainerDoc_ContainerLineDoVerbCommand(
927: LPCONTAINERDOC lpContainerDoc,
928: LONG iVerb
929: )
930: {
931: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
932: int nIndex = LineList_GetFocusLineIndex(lpLL);
933: LPLINE lpLine = LineList_GetLine(lpLL, nIndex);
934: HCURSOR hPrevCursor;
935:
936: if (! lpLine || (Line_GetLineType(lpLine) != CONTAINERLINETYPE) ) return;
937:
938: // this may take a while, put up hourglass cursor
939: hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
940:
941: ContainerLine_DoVerb((LPCONTAINERLINE) lpLine, iVerb, TRUE, TRUE);
942:
943: SetCursor(hPrevCursor); // restore original cursor
944: }
945:
946:
947: /* ContainerDoc_GetNextStgName
948: ** ---------------------------
949: ** Generate the next unused name for a sub-storage to be used by an
950: ** OLE object. The ContainerDoc keeps a counter. The storages for
951: ** OLE objects are simply numbered (eg. Obj 0, Obj 1). A "long"
952: ** integer worth of storage names should be more than enough than we
953: ** will ever need.
954: **
955: ** NOTE: when an OLE object is transfered via drag/drop or the
956: ** clipboard, we attempt to keep the currently assigned name for the
957: ** object (if not currently in use). thus it is possible that an
958: ** object with a the next default name (eg. "Obj 5") already exists
959: ** in the current document if an object with this name was privously
960: ** transfered (pasted or dropped). we therefore loop until we find
961: ** the next lowest unused name.
962: */
963: void ContainerDoc_GetNextStgName(
964: LPCONTAINERDOC lpContainerDoc,
965: LPSTR lpszStgName,
966: int nLen
967: )
968: {
969: wsprintf(lpszStgName, "%s %ld",
970: (LPSTR)DEFOBJNAMEPREFIX,
971: ++(lpContainerDoc->m_nNextObjNo)
972: );
973:
974: while (ContainerDoc_IsStgNameUsed(lpContainerDoc, lpszStgName) == TRUE) {
975: wsprintf(lpszStgName, "%s %ld",
976: (LPSTR)DEFOBJNAMEPREFIX,
977: ++(lpContainerDoc->m_nNextObjNo)
978: );
979: }
980: }
981:
982:
983: /* ContainerDoc_IsStgNameUsed
984: ** --------------------------
985: ** Check if a given StgName is already in use.
986: */
987: BOOL ContainerDoc_IsStgNameUsed(
988: LPCONTAINERDOC lpContainerDoc,
989: LPSTR lpszStgName
990: )
991: {
992: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
993: int i;
994: LPLINE lpLine;
995:
996: for (i = 0; i < lpLL->m_nNumLines; i++) {
997: lpLine=LineList_GetLine(lpLL, i);
998:
999: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
1000: if (lstrcmp(lpszStgName,
1001: ((LPCONTAINERLINE)lpLine)->m_szStgName) == 0) {
1002: return TRUE; // Match FOUND!
1003: }
1004: }
1005: }
1006: return FALSE; // if we get here, then NO match was found.
1007: }
1008:
1009:
1010: LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc)
1011: {
1012: return lpContainerDoc->m_lpStg;
1013: }
1014:
1015:
1016: /* ContainerDoc_GetSingleOleObject
1017: ** -------------------------------
1018: ** If the entire document contains a single OLE object, then
1019: ** return the desired interface of the object.
1020: **
1021: ** Returns NULL if there is are multiple lines in the document or
1022: ** the single line is not a ContainerLine.
1023: */
1024: LPUNKNOWN ContainerDoc_GetSingleOleObject(
1025: LPCONTAINERDOC lpContainerDoc,
1026: REFIID riid,
1027: LPCONTAINERLINE FAR* lplpContainerLine
1028: )
1029: {
1030: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
1031: LPLINE lpLine;
1032: LPUNKNOWN lpObj = NULL;
1033:
1034: if (lplpContainerLine)
1035: *lplpContainerLine = NULL;
1036:
1037: if (lpLL->m_nNumLines != 1)
1038: return NULL; // doc does NOT contain a single line
1039:
1040: lpLine=LineList_GetLine(lpLL, 0);
1041:
1042: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))
1043: lpObj = ContainerLine_GetOleObject((LPCONTAINERLINE)lpLine, riid);
1044:
1045: if (lplpContainerLine)
1046: *lplpContainerLine = (LPCONTAINERLINE)lpLine;
1047:
1048: return lpObj;
1049: }
1050:
1051:
1052: /* ContainerDoc_IsSelAnOleObject
1053: ** -----------------------------
1054: ** Check if the selection is a single selection of an OLE object.
1055: ** if so, then optionally return the desired interface of the object
1056: ** and/or index of the ContainerLine containing the OLE object.
1057: **
1058: ** Returns FALSE if there is a multiple selection or the single
1059: ** selection is not a ContainerLine.
1060: */
1061: BOOL ContainerDoc_IsSelAnOleObject(
1062: LPCONTAINERDOC lpContainerDoc,
1063: REFIID riid,
1064: LPUNKNOWN FAR* lplpvObj,
1065: int FAR* lpnIndex,
1066: LPCONTAINERLINE FAR* lplpContainerLine
1067: )
1068: {
1069: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
1070: LINERANGE lrSel;
1071: int nNumSel;
1072: LPLINE lpLine;
1073:
1074: if (lplpvObj) *lplpvObj = NULL;
1075: if (lpnIndex) *lpnIndex = -1;
1076: if (lplpContainerLine) *lplpContainerLine = NULL;
1077:
1078: nNumSel = LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);
1079: if (nNumSel != 1)
1080: return FALSE; // selection is not a single line
1081:
1082: lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine);
1083:
1084: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
1085: if (lpnIndex)
1086: *lpnIndex = lrSel.m_nStartLine;
1087: if (lplpContainerLine)
1088: *lplpContainerLine = (LPCONTAINERLINE)lpLine;
1089: if (riid) {
1090: *lplpvObj = ContainerLine_GetOleObject(
1091: (LPCONTAINERLINE)lpLine,
1092: riid
1093: );
1094: }
1095:
1096: return (*lplpvObj ? TRUE : FALSE);
1097: }
1098:
1099: return FALSE;
1100: }
1101:
1102:
1103: /*************************************************************************
1104: ** ContainerDoc::IOleUILinkContainer interface implementation
1105: *************************************************************************/
1106:
1107: STDMETHODIMP CntrDoc_LinkCont_QueryInterface(
1108: LPOLEUILINKCONTAINER lpThis,
1109: REFIID riid,
1110: LPVOID FAR* lplpvObj
1111: )
1112: {
1113: LPOLEDOC lpOleDoc = (LPOLEDOC)
1114: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1115:
1116: return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
1117: }
1118:
1119:
1120: STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis)
1121: {
1122: LPOLEDOC lpOleDoc = (LPOLEDOC)
1123: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1124:
1125: OleDbgAddRefMethod(lpThis, "IOleUILinkContainer");
1126:
1127: return OleDoc_AddRef(lpOleDoc);
1128: }
1129:
1130:
1131: STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis)
1132: {
1133: LPOLEDOC lpOleDoc = (LPOLEDOC)
1134: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1135:
1136: OleDbgReleaseMethod(lpThis, "IOleUILinkContainer");
1137:
1138: return OleDoc_Release(lpOleDoc);
1139: }
1140:
1141:
1142: STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink(
1143: LPOLEUILINKCONTAINER lpThis,
1144: DWORD dwLink
1145: )
1146: {
1147: LPCONTAINERDOC lpContainerDoc =
1148: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1149: LPCONTAINERLINE lpContainerLine = NULL;
1150:
1151: OLEDBG_BEGIN2("CntrDoc_LinkCont_GetNextLink\r\n")
1152:
1153: lpContainerLine = ContainerDoc_GetNextLink(
1154: lpContainerDoc,
1155: (LPCONTAINERLINE)dwLink
1156: );
1157:
1158: OLEDBG_END2
1159: return (DWORD)lpContainerLine;
1160: }
1161:
1162:
1163: STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions(
1164: LPOLEUILINKCONTAINER lpThis,
1165: DWORD dwLink,
1166: DWORD dwUpdateOpt
1167: )
1168: {
1169: LPCONTAINERDOC lpContainerDoc =
1170: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1171: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1172: LPOLELINK lpOleLink;
1173: SCODE sc = S_OK;
1174: HRESULT hrErr;
1175:
1176: OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkUpdateOptions\r\n")
1177:
1178: OleDbgAssert(lpContainerLine);
1179:
1180: lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
1181: lpContainerLine,
1182: &IID_IOleLink
1183: );
1184:
1185: if (! lpOleLink) {
1186: sc = E_FAIL;
1187: goto error;
1188: }
1189:
1190: OLEDBG_BEGIN2("IOleLink::SetUpdateOptions called\r\n")
1191: hrErr = lpOleLink->lpVtbl->SetUpdateOptions(
1192: lpOleLink,
1193: dwUpdateOpt
1194: );
1195: OLEDBG_END2
1196:
1197: OleStdRelease((LPUNKNOWN)lpOleLink);
1198:
1199: if (hrErr != NOERROR) {
1200: OleDbgOutHResult("IOleLink::SetUpdateOptions returned", hrErr);
1201: sc = GetScode(hrErr);
1202: goto error;
1203: }
1204:
1205: OLEDBG_END2
1206: return ResultFromScode(sc);
1207:
1208: error:
1209: OLEDBG_END2
1210: return ResultFromScode(sc);
1211: }
1212:
1213:
1214: STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions(
1215: LPOLEUILINKCONTAINER lpThis,
1216: DWORD dwLink,
1217: DWORD FAR* lpdwUpdateOpt
1218: )
1219: {
1220: LPCONTAINERDOC lpContainerDoc =
1221: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1222: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1223: LPOLELINK lpOleLink;
1224: SCODE sc = S_OK;
1225: HRESULT hrErr;
1226:
1227: OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkUpdateOptions\r\n")
1228:
1229: OleDbgAssert(lpContainerLine);
1230:
1231: lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
1232: lpContainerLine,
1233: &IID_IOleLink
1234: );
1235:
1236: if (! lpOleLink) {
1237: sc = E_FAIL;
1238: goto error;
1239: }
1240:
1241: OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n")
1242: hrErr = lpOleLink->lpVtbl->GetUpdateOptions(
1243: lpOleLink,
1244: lpdwUpdateOpt
1245: );
1246: OLEDBG_END2
1247:
1248: OleStdRelease((LPUNKNOWN)lpOleLink);
1249:
1250: if (hrErr != NOERROR) {
1251: OleDbgOutHResult("IOleLink::GetUpdateOptions returned", hrErr);
1252: sc = GetScode(hrErr);
1253: goto error;
1254: }
1255:
1256: OLEDBG_END2
1257: return ResultFromScode(sc);
1258:
1259: error:
1260: OLEDBG_END2
1261: return ResultFromScode(sc);
1262: }
1263:
1264:
1265: STDMETHODIMP CntrDoc_LinkCont_SetLinkSource(
1266: LPOLEUILINKCONTAINER lpThis,
1267: DWORD dwLink,
1268: LPSTR lpszDisplayName,
1269: ULONG lenFileName,
1270: ULONG FAR* lpchEaten,
1271: BOOL fValidateSource
1272: )
1273: {
1274: LPCONTAINERDOC lpContainerDoc =
1275: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1276: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1277: SCODE sc = S_OK;
1278: HRESULT hrErr;
1279: LPOLELINK lpOleLink = NULL;
1280: LPBC lpbc = NULL;
1281: LPMONIKER lpmk = NULL;
1282: LPOLEOBJECT lpLinkSrcOleObj = NULL;
1283: CLSID clsid = CLSID_NULL;
1284:
1285:
1286: OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkSource\r\n")
1287:
1288: OleDbgAssert(lpContainerLine);
1289:
1290: lpContainerLine->m_fLinkUnavailable = TRUE;
1291:
1292: if (fValidateSource) {
1293:
1294: /* OLE2NOTE: validate the link source by parsing the string
1295: ** into a Moniker. if this is successful, then the string is
1296: ** valid.
1297: */
1298: hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);
1299: if (hrErr != NOERROR) {
1300: sc = GetScode(hrErr); // ERROR: OOM
1301: goto cleanup;
1302: }
1303:
1304: OLEDBG_BEGIN2("MkParseDisplayName called\r\n")
1305: hrErr = MkParseDisplayName(
1306: lpbc, lpszDisplayName, lpchEaten, (LPMONIKER FAR*)&lpmk);
1307: OLEDBG_END2
1308:
1309: if (hrErr != NOERROR) {
1310: sc = GetScode(hrErr); // ERROR in parsing moniker!
1311: goto cleanup;
1312: }
1313: /* OLE2NOTE: the link source was validated; it successfully
1314: ** parsed into a Moniker. we can set the source of the link
1315: ** directly with this Moniker. if we want the link to be
1316: ** able to know the correct class for the new link source,
1317: ** we must bind to the moniker and get the CLSID. if we do
1318: ** not do this then methods like IOleObject::GetUserType
1319: ** will return nothing (NULL strings).
1320: */
1321:
1322: hrErr = lpmk->lpVtbl->BindToObject(
1323: lpmk,lpbc,NULL,&IID_IOleObject,(LPVOID FAR*)&lpLinkSrcOleObj);
1324: if (hrErr == NOERROR) {
1325: hrErr = lpLinkSrcOleObj->lpVtbl->GetUserClassID(
1326: lpLinkSrcOleObj,
1327: (CLSID FAR*)&clsid);
1328: lpContainerLine->m_fLinkUnavailable = FALSE;
1329: }
1330: else
1331: lpContainerLine->m_fLinkUnavailable = TRUE;
1332: }
1333: else {
1334: LPMONIKER lpmkFile = NULL;
1335: LPMONIKER lpmkItem = NULL;
1336: char szName[OLEUI_CCHPATHMAX];
1337:
1338: lstrcpyn((LPSTR)szName, lpszDisplayName, (int)lenFileName + 1);
1339:
1340: OLEDBG_BEGIN2("CreateFileMoniker called\r\n")
1341: CreateFileMoniker((LPSTR)szName, (LPMONIKER FAR*)&lpmkFile);
1342: OLEDBG_END2
1343:
1344: if (!lpmkFile)
1345: goto cleanup;
1346:
1347: if (lstrlen(lpszDisplayName) > (int)lenFileName) { // have item name
1348: lstrcpy((LPSTR)szName, lpszDisplayName + lenFileName + 1);
1349:
1350: OLEDBG_BEGIN2("CreateItemMoniker called\r\n")
1351: CreateItemMoniker(
1352: OLESTDDELIM, (LPSTR)szName, (LPMONIKER FAR*)&lpmkItem);
1353: OLEDBG_END2
1354:
1355: if (!lpmkItem) {
1356: OleStdRelease((LPUNKNOWN)lpmkFile);
1357: goto cleanup;
1358: }
1359:
1360: OLEDBG_BEGIN2("CreateGenericComposite called\r\n")
1361: CreateGenericComposite(lpmkFile, lpmkItem, (LPMONIKER FAR*)&lpmk);
1362: OLEDBG_END2
1363:
1364: if (lpmkFile)
1365: OleStdRelease((LPUNKNOWN)lpmkFile);
1366: if (lpmkItem)
1367: OleStdRelease((LPUNKNOWN)lpmkItem);
1368:
1369: if (!lpmk)
1370: goto cleanup;
1371: }
1372: else
1373: lpmk = lpmkFile;
1374: }
1375:
1376: lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
1377: lpContainerLine,
1378: &IID_IOleLink
1379: );
1380:
1381: if (! lpOleLink) {
1382: OleDbgAssert(lpOleLink != NULL);
1383: sc = E_FAIL;
1384: goto cleanup;
1385: }
1386:
1387: if (lpmk) {
1388:
1389: OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")
1390: hrErr = lpOleLink->lpVtbl->SetSourceMoniker(
1391: lpOleLink, lpmk, (REFCLSID)&clsid);
1392: OLEDBG_END2
1393:
1394: if (FAILED(GetScode(hrErr))) {
1395: OleDbgOutHResult("IOleLink::SetSourceMoniker returned",hrErr);
1396: sc = GetScode(hrErr);
1397: goto cleanup;
1398: }
1399:
1400: /* OLE2NOTE: above we forced the link source moniker to bind.
1401: ** because we deliberately hold on to the bind context
1402: ** (lpbc) the link source object will not shut down. during
1403: ** the call to IOleLink::SetSourceMoniker, the link will
1404: ** connect to the running link source (the link internally
1405: ** calls BindIfRunning). it is important to initially allow
1406: ** the link to bind to the running object so that it can get
1407: ** an update of the presentation for its cache. we do not
1408: ** want the connection from our link to the link source be
1409: ** the only reason the link source stays running. thus we
1410: ** deliberately for the link to release (unbind) the source
1411: ** object, we then release the bind context, and then we
1412: ** allow the link to rebind to the link source if it is
1413: ** running anyway.
1414: */
1415: if (lpbc && lpmk->lpVtbl->IsRunning(lpmk,lpbc,NULL,NULL) == NOERROR) {
1416:
1417: OLEDBG_BEGIN2("IOleLink::Update called\r\n")
1418: hrErr = lpOleLink->lpVtbl->Update(lpOleLink, NULL);
1419: OLEDBG_END2
1420:
1421: #if defined( _DEBUG )
1422: if (FAILED(GetScode(hrErr)))
1423: OleDbgOutHResult("IOleLink::Update returned",hrErr);
1424: #endif
1425:
1426: OLEDBG_BEGIN2("IOleLink::UnbindSource called\r\n")
1427: hrErr = lpOleLink->lpVtbl->UnbindSource(lpOleLink);
1428: OLEDBG_END2
1429:
1430: #if defined( _DEBUG )
1431: if (FAILED(GetScode(hrErr)))
1432: OleDbgOutHResult("IOleLink::UnbindSource returned",hrErr);
1433: #endif
1434:
1435: if (lpLinkSrcOleObj) {
1436: OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);
1437: lpLinkSrcOleObj = NULL;
1438: }
1439:
1440: if (lpbc) {
1441: OleStdRelease((LPUNKNOWN)lpbc);
1442: lpbc = NULL;
1443: }
1444:
1445: OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n")
1446: hrErr = lpOleLink->lpVtbl->BindIfRunning(lpOleLink);
1447: OLEDBG_END2
1448:
1449: #if defined( _DEBUG )
1450: if (FAILED(GetScode(hrErr)))
1451: OleDbgOutHResult("IOleLink::BindIfRunning returned",hrErr);
1452: #endif
1453: }
1454: } else {
1455: /* OLE2NOTE: the link source was NOT validated; it was NOT
1456: ** successfully parsed into a Moniker. we can only set the
1457: ** display name string as the source of the link. this link
1458: ** is not able to bind.
1459: */
1460: OLEDBG_BEGIN2("IOleLink::SetSourceDisplayName called\r\n")
1461: hrErr = lpOleLink->lpVtbl->SetSourceDisplayName(
1462: lpOleLink, (LPCSTR)lpszDisplayName);
1463: OLEDBG_END2
1464:
1465: if (hrErr != NOERROR) {
1466: OleDbgOutHResult("IOleLink::SetSourceDisplayName returned",hrErr);
1467: sc = GetScode(hrErr);
1468: goto cleanup;
1469: }
1470: }
1471:
1472: cleanup:
1473: if (lpOleLink)
1474: OleStdRelease((LPUNKNOWN)lpOleLink);
1475: if (lpLinkSrcOleObj)
1476: OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);
1477: if (lpmk)
1478: OleStdRelease((LPUNKNOWN)lpmk);
1479: if (lpbc)
1480: OleStdRelease((LPUNKNOWN)lpbc);
1481:
1482: OLEDBG_END2
1483: return ResultFromScode(sc);
1484: }
1485:
1486:
1487: STDMETHODIMP CntrDoc_LinkCont_GetLinkSource(
1488: LPOLEUILINKCONTAINER lpThis,
1489: DWORD dwLink,
1490: LPSTR FAR* lplpszDisplayName,
1491: ULONG FAR* lplenFileName,
1492: LPSTR FAR* lplpszFullLinkType,
1493: LPSTR FAR* lplpszShortLinkType,
1494: BOOL FAR* lpfSourceAvailable,
1495: BOOL FAR* lpfIsSelected
1496: )
1497: {
1498: LPCONTAINERDOC lpContainerDoc =
1499: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1500: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1501: LPOLELINK lpOleLink = NULL;
1502: LPOLEOBJECT lpOleObj = NULL;
1503: LPMONIKER lpmk = NULL;
1504: LPMONIKER lpmkFirst = NULL;
1505: LPBC lpbc = NULL;
1506: SCODE sc = S_OK;
1507: HRESULT hrErr;
1508:
1509: OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkSource\r\n")
1510:
1511: /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
1512: *lplpszDisplayName = NULL;
1513: *lplpszFullLinkType = NULL;
1514: *lplpszShortLinkType= NULL;
1515: *lplenFileName = 0;
1516: *lpfSourceAvailable = !lpContainerLine->m_fLinkUnavailable;
1517:
1518: OleDbgAssert(lpContainerLine);
1519:
1520: lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
1521: lpContainerLine,
1522: &IID_IOleLink
1523: );
1524:
1525: if (! lpOleLink) {
1526: OLEDBG_END2
1527: return ResultFromScode(E_FAIL);
1528: }
1529:
1530: OLEDBG_BEGIN2("IOleLink::GetSourceMoniker called\r\n")
1531: hrErr = lpOleLink->lpVtbl->GetSourceMoniker(
1532: lpOleLink,
1533: (LPMONIKER FAR*)&lpmk
1534: );
1535: OLEDBG_END2
1536:
1537: if (hrErr == NOERROR) {
1538: /* OLE2NOTE: the link has the Moniker form of the link source;
1539: ** this is therefore a validated link source. if the first
1540: ** part of the Moniker is a FileMoniker, then we need to
1541: ** return the length of the filename string. we need to
1542: ** return the ProgID associated with the link source as the
1543: ** "lpszShortLinkType". we need to return the
1544: ** FullUserTypeName associated with the link source as the
1545: ** "lpszFullLinkType".
1546: */
1547:
1548: lpOleObj = (LPOLEOBJECT)OleStdQueryInterface(
1549: (LPUNKNOWN)lpOleLink, &IID_IOleObject);
1550: if (lpOleObj) {
1551: lpOleObj->lpVtbl->GetUserType(
1552: lpOleObj,
1553: USERCLASSTYPE_FULL,
1554: lplpszFullLinkType
1555: );
1556: lpOleObj->lpVtbl->GetUserType(
1557: lpOleObj,
1558: USERCLASSTYPE_SHORT,
1559: lplpszShortLinkType
1560: );
1561: OleStdRelease((LPUNKNOWN)lpOleObj);
1562: }
1563: *lplenFileName = OleStdGetLenFilePrefixOfMoniker(lpmk);
1564: lpmk->lpVtbl->Release(lpmk);
1565: }
1566:
1567: OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")
1568: hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(
1569: lpOleLink,
1570: lplpszDisplayName
1571: );
1572: OLEDBG_END2
1573:
1574: OleStdRelease((LPUNKNOWN)lpOleLink);
1575:
1576: if (hrErr != NOERROR) {
1577: OleDbgOutHResult("IOleLink::GetSourceDisplayName returned", hrErr);
1578: OLEDBG_END2
1579: return hrErr;
1580: }
1581:
1582: OLEDBG_END2
1583:
1584: if (lpfIsSelected)
1585: *lpfIsSelected = Line_IsSelected((LPLINE)lpContainerLine);
1586:
1587: return NOERROR;
1588: }
1589:
1590:
1591: STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource(
1592: LPOLEUILINKCONTAINER lpThis,
1593: DWORD dwLink
1594: )
1595: {
1596: LPCONTAINERDOC lpContainerDoc =
1597: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1598: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1599: SCODE sc = S_OK;
1600:
1601: OLEDBG_BEGIN2("CntrDoc_LinkCont_OpenLinkSource\r\n")
1602:
1603: OleDbgAssert(lpContainerLine);
1604:
1605: if (! ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, TRUE, FALSE)) {
1606: OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj);
1607: sc = E_FAIL;
1608: }
1609:
1610: lpContainerLine->m_fLinkUnavailable = (sc != S_OK);
1611:
1612: OLEDBG_END2
1613: return ResultFromScode(sc);
1614: }
1615:
1616:
1617: STDMETHODIMP CntrDoc_LinkCont_UpdateLink(
1618: LPOLEUILINKCONTAINER lpThis,
1619: DWORD dwLink,
1620: BOOL fErrorMessage,
1621: BOOL fErrorAction // ignore if fErrorMessage
1622: // is FALSE
1623: )
1624: {
1625: LPCONTAINERDOC lpContainerDoc =
1626: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1627: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1628: SCODE sc = S_OK;
1629: HRESULT hrErr;
1630:
1631: OLEDBG_BEGIN2("CntrDoc_LinkCont_UpdateLink\r\n")
1632:
1633: OleDbgAssert(lpContainerLine);
1634:
1635: if (! lpContainerLine->m_lpOleObj)
1636: ContainerLine_LoadOleObject(lpContainerLine);
1637:
1638: if (!fErrorMessage) {
1639: OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n")
1640: hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate(
1641: lpContainerLine->m_lpOleObj
1642: );
1643: OLEDBG_END2
1644: }
1645:
1646: if (hrErr != NOERROR) {
1647: OLEDBG_BEGIN2("IOleObject::Update called\r\n")
1648: hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Update(
1649: lpContainerLine->m_lpOleObj
1650: );
1651: OLEDBG_END2
1652: }
1653:
1654: lpContainerLine->m_fLinkUnavailable = (hrErr != NOERROR);
1655:
1656: if (hrErr != NOERROR) {
1657: OleDbgOutHResult("IOleObject::Update returned", hrErr);
1658: sc = GetScode(hrErr);
1659: if (fErrorMessage)
1660: ProcessError(hrErr, lpContainerLine, fErrorAction);
1661: }
1662: /* OLE2NOTE: if the update of the object requires us to update our
1663: ** display, then we will automatically be sent a OnViewChange
1664: ** advise. thus we do not need to take any action here to force
1665: ** a repaint.
1666: */
1667:
1668: OLEDBG_END2
1669: return ResultFromScode(sc);
1670: }
1671:
1672:
1673: /* CntrDoc_LinkCont_CancelLink
1674: ** ---------------------------
1675: ** Convert the link to a static picture.
1676: **
1677: ** OLE2NOTE: OleCreateStaticFromData can be used to create a static
1678: ** picture object.
1679: */
1680: STDMETHODIMP CntrDoc_LinkCont_CancelLink(
1681: LPOLEUILINKCONTAINER lpThis,
1682: DWORD dwLink
1683: )
1684: {
1685: LPCONTAINERDOC lpContainerDoc =
1686: ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
1687: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
1688: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
1689: LPLINE lpLine = NULL;
1690: HDC hDC;
1691: int nTab = 0;
1692: char szStgName[CWCSTORAGENAME];
1693: LPCONTAINERLINE lpNewContainerLine = NULL;
1694: LPDATAOBJECT lpSrcDataObj;
1695: LPOLELINK lpOleLink;
1696: int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
1697:
1698: OLEDBG_BEGIN2("CntrDoc_LinkCont_CancelLink\r\n")
1699:
1700: /* we will first break the connection of the link to its source. */
1701: lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
1702: lpContainerLine,
1703: &IID_IOleLink
1704: );
1705: if (lpOleLink) {
1706: OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")
1707: lpOleLink->lpVtbl->SetSourceMoniker(
1708: lpOleLink, NULL, (REFCLSID)&CLSID_NULL);
1709: OLEDBG_END2
1710: OleStdRelease((LPUNKNOWN)lpOleLink);
1711: }
1712:
1713: lpSrcDataObj = (LPDATAOBJECT)ContainerLine_GetOleObject(
1714: lpContainerLine,&IID_IDataObject);
1715: if (! lpSrcDataObj)
1716: goto error;
1717:
1718: ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
1719: nTab = Line_GetTabLevel((LPLINE)lpContainerLine);
1720: hDC = LineList_GetDC(lpLL);
1721:
1722: lpNewContainerLine = ContainerLine_CreateFromData(
1723: hDC,
1724: nTab,
1725: lpContainerDoc,
1726: lpSrcDataObj,
1727: OLECREATEFROMDATA_STATIC,
1728: 0, /* no special cfFormat required */
1729: FALSE, /* fDisplayAsIcon */
1730: NULL, /* hMetaPict */
1731: szStgName
1732: );
1733: LineList_ReleaseDC(lpLL, hDC);
1734:
1735: OleStdRelease((LPUNKNOWN)lpSrcDataObj);
1736:
1737: if (! lpNewContainerLine)
1738: goto error;
1739:
1740: OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, FALSE);
1741:
1742: LineList_ReplaceLine(lpLL, (LPLINE)lpNewContainerLine, nIndex);
1743:
1744: OLEDBG_END2
1745: return ResultFromScode(NOERROR);
1746:
1747: error:
1748: OutlineApp_ErrorMessage(g_lpApp, "Could not break the link.");
1749: OLEDBG_END2
1750: return ResultFromScode(E_FAIL);
1751: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.