|
|
1.1 root 1: /*************************************************************************
2: **
3: ** OLE 2 Server Sample Code
4: **
5: ** oledoc.c
6: **
7: ** This file contains general OleDoc methods and related support
8: ** functions. OleDoc implementation is used by both the Container
9: ** versions and the Server (Object) versions of the Outline Sample.
10: **
11: ** This file includes general support for the following:
12: ** 1. show/hide doc window
13: ** 2. QueryInterface, AddRef, Release
14: ** 3. document locking (calls CoLockObjectExternal)
15: ** 4. document shutdown (Close, Destroy)
16: ** 5. clipboard support
17: **
18: ** OleDoc Object
19: ** exposed interfaces:
20: ** IUnknown
21: ** IPersistFile
22: ** IOleItemContainer
23: ** IDataObject
24: **
25: ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
26: **
27: *************************************************************************/
28:
29:
30: #include "outline.h"
31:
32: OLEDBGDATA
33:
34: extern LPOUTLINEAPP g_lpApp;
35:
36: extern IUnknownVtbl g_OleDoc_UnknownVtbl;
37: extern IPersistFileVtbl g_OleDoc_PersistFileVtbl;
38: extern IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl;
39: extern IDataObjectVtbl g_OleDoc_DataObjectVtbl;
40:
41: #if defined( USE_DRAGDROP )
42: extern IDropTargetVtbl g_OleDoc_DropTargetVtbl;
43: extern IDropSourceVtbl g_OleDoc_DropSourceVtbl;
44: #endif // USE_DRAGDROP
45:
46: #if defined( INPLACE_CNTR )
47: extern BOOL g_fInsideOutContainer;
48: #endif
49:
50:
51: /* OleDoc_Init
52: * -----------
53: *
54: * Initialize the fields of a new OleDoc object. The object is initially
55: * not associated with a file or an (Untitled) document. This function sets
56: * the docInitType to DOCTYPE_UNKNOWN. After calling this function the
57: * caller should call:
58: * 1.) Doc_InitNewFile to set the OleDoc to (Untitled)
59: * 2.) Doc_LoadFromFile to associate the OleDoc with a file.
60: * This function creates a new window for the document.
61: *
62: * NOTE: the window is initially created with a NIL size. it must be
63: * sized and positioned by the caller. also the document is initially
64: * created invisible. the caller must call OutlineDoc_ShowWindow
65: * after sizing it to make the document window visible.
66: */
67: BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc)
68: {
69: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
70: LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
71:
72: lpOleDoc->m_cRef = 0;
73: lpOleDoc->m_cLock = 0;
74:
75: lpOleDoc->m_dwRegROT = 0;
76: lpOleDoc->m_lpFileMoniker = NULL;
77: lpOleDoc->m_fLinkSourceAvail = FALSE;
78: lpOleDoc->m_lpSrcDocOfCopy = NULL;
79: lpOleDoc->m_fObjIsClosing = FALSE;
80: lpOleDoc->m_fObjIsDestroying = FALSE;
81: lpOleDoc->m_fUpdateEditMenu = FALSE;
82:
83: #if defined( USE_DRAGDROP )
84: lpOleDoc->m_dwTimeEnterScrollArea = 0;
85: lpOleDoc->m_lastdwScrollDir = SCROLLDIR_NULL;
86: lpOleDoc->m_fRegDragDrop = FALSE;
87: lpOleDoc->m_fLocalDrag = FALSE;
88: lpOleDoc->m_fCanDropCopy = FALSE;
89: lpOleDoc->m_fCanDropLink = FALSE;
90: lpOleDoc->m_fLocalDrop = FALSE;
91: lpOleDoc->m_fDragLeave = FALSE;
92: lpOleDoc->m_fPendingDrag = FALSE;
93: #endif
94:
95: INIT_INTERFACEIMPL(
96: &lpOleDoc->m_Unknown,
97: &g_OleDoc_UnknownVtbl,
98: lpOleDoc
99: );
100:
101: INIT_INTERFACEIMPL(
102: &lpOleDoc->m_PersistFile,
103: &g_OleDoc_PersistFileVtbl,
104: lpOleDoc
105: );
106:
107: INIT_INTERFACEIMPL(
108: &lpOleDoc->m_OleItemContainer,
109: &g_OleDoc_OleItemContainerVtbl,
110: lpOleDoc
111: );
112:
113: INIT_INTERFACEIMPL(
114: &lpOleDoc->m_DataObject,
115: &g_OleDoc_DataObjectVtbl,
116: lpOleDoc
117: );
118:
119: #if defined( USE_DRAGDROP )
120: INIT_INTERFACEIMPL(
121: &lpOleDoc->m_DropSource,
122: &g_OleDoc_DropSourceVtbl,
123: lpOleDoc
124: );
125:
126: INIT_INTERFACEIMPL(
127: &lpOleDoc->m_DropTarget,
128: &g_OleDoc_DropTargetVtbl,
129: lpOleDoc
130: );
131: #endif // USE_DRAGDROP
132:
133: /*
134: ** OLE2NOTE: each user level document addref's the app object in
135: ** order to guarentee that the app does not shut down while the
136: ** doc is still open.
137: */
138:
139: // OLE2NOTE: data transfer documents should not hold the app alive
140: if (! fDataTransferDoc)
141: OleApp_DocLockApp(lpOleApp);
142:
143: #if defined( OLE_SERVER )
144:
145: /* OLE2NOTE: perform initialization specific for an OLE server */
146: if (! ServerDoc_Init((LPSERVERDOC)lpOleDoc, fDataTransferDoc))
147: return FALSE;
148:
149: #elif defined( OLE_CNTR )
150:
151: /* OLE2NOTE: perform initialization specific for an OLE container */
152: if (! ContainerDoc_Init((LPCONTAINERDOC)lpOleDoc, fDataTransferDoc))
153: return FALSE;
154:
155: #endif
156:
157: return TRUE;
158: }
159:
160:
161:
162: /* OleDoc_InitNewFile
163: * ------------------
164: *
165: * Initialize the document to be a new (Untitled) document.
166: * This function sets the docInitType to DOCTYPE_NEW.
167: *
168: * OLE2NOTE: if this is a visible user document then generate a unique
169: * untitled name that we can use to register in the RunningObjectTable.
170: * We need a unique name so that clients can link to data in this document
171: * even when the document is in the un-saved (untitled) state. it would be
172: * ambiguous to register two documents titled "Outline1" in the ROT. we
173: * thus generate the lowest numbered document that is not already
174: * registered in the ROT.
175: */
176: BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc)
177: {
178: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
179:
180: static UINT uUnique = 1;
181:
182: OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);
183:
184: #if defined( OLE_CNTR )
185: {
186: LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
187:
188: OleDbgAssertSz(lpContainerDoc->m_lpStg == NULL,
189: "Setting to untitled with current file open"
190: );
191:
192: /* Create a temp, (delete-on-release) file base storage
193: ** for the untitled document.
194: */
195: lpContainerDoc->m_lpStg = OleStdCreateRootStorage(
196: NULL,
197: STGM_SHARE_EXCLUSIVE
198: );
199: if (! lpContainerDoc->m_lpStg) return FALSE;
200: }
201: #endif
202:
203: lpOutlineDoc->m_docInitType = DOCTYPE_NEW;
204:
205: if (! lpOutlineDoc->m_fDataTransferDoc) {
206: /* OLE2NOTE: choose a unique name for a Moniker so that
207: ** potential clients can link to our new, untitled document.
208: ** if links are established (and currently are connected),
209: ** then they will be notified that we have been renamed when
210: ** this document is saved to a file.
211: */
212:
213: lpOleDoc->m_fLinkSourceAvail = TRUE;
214:
215: // REVIEW: should load UNTITLED string from string resource
216: OleStdCreateTempFileMoniker(
217: UNTITLED,
218: (UINT FAR*)&uUnique,
219: lpOutlineDoc->m_szFileName,
220: &lpOleDoc->m_lpFileMoniker
221: );
222:
223: OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n")
224: OleStdRegisterAsRunning(
225: (LPUNKNOWN)&lpOleDoc->m_PersistFile,
226: (LPMONIKER)lpOleDoc->m_lpFileMoniker,
227: &lpOleDoc->m_dwRegROT
228: );
229: OLEDBG_END3
230:
231: lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
232: OutlineDoc_SetTitle(lpOutlineDoc);
233: } else {
234: lstrcpy(lpOutlineDoc->m_szFileName, UNTITLED);
235: lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
236: }
237:
238: return TRUE;
239: }
240:
241:
242: /* OleDoc_ShowWindow
243: * -----------------
244: *
245: * Show the window of the document to the user.
246: * make sure app window is visible and bring the document to the top.
247: * if the document is a file-based document or a new untitled
248: * document, give the user the control over the life-time of the doc.
249: */
250: void OleDoc_ShowWindow(LPOLEDOC lpOleDoc)
251: {
252: LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
253: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
254: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
255: LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
256: #if defined( OLE_SERVER )
257: LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
258: #endif // OLE_SERVER
259:
260: OLEDBG_BEGIN3("OleDoc_ShowWindow\r\n")
261:
262: /* OLE2NOTE: while the document is visible, we do NOT want it to be
263: ** prematurely destroyed when a linking client disconnects. thus
264: ** we must inform OLE to hold an external lock on our document.
265: ** this arranges that OLE holds at least 1 reference to our
266: ** document that will NOT be released until we release this
267: ** external lock. later, when the document window is hidden, we
268: ** will release this external lock.
269: */
270: if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))
271: OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */);
272:
273: #if defined( USE_DRAGDROP )
274: /* OLE2NOTE: since our window is now being made visible, we will
275: ** register our window as a potential drop target. when the
276: ** window is hidden there is no reason to be registered as a
277: ** drop target.
278: */
279: if (! lpOleDoc->m_fRegDragDrop) {
280: OLEDBG_BEGIN2("RegisterDragDrop called\r\n")
281: RegisterDragDrop(
282: LineList_GetWindow(lpLL),
283: (LPDROPTARGET)&lpOleDoc->m_DropTarget
284: );
285: OLEDBG_END2
286: lpOleDoc->m_fRegDragDrop = TRUE;
287: }
288: #endif // USE_DRAGDROP
289:
290: #if defined( USE_FRAMETOOLS )
291: {
292: /* OLE2NOTE: we need to enable our frame level tools
293: */
294: FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);
295: }
296: #endif // USE_FRAMETOOLS
297:
298: #if defined( OLE_SERVER )
299:
300: if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED &&
301: lpServerDoc->m_lpOleClientSite != NULL) {
302:
303: /* OLE2NOTE: we must also ask our container to show itself if
304: ** it is not already visible and to scroll us into view. we
305: ** must make sure to call this BEFORE showing our server's
306: ** window and taking focus. we do not want our container's
307: ** window to end up on top.
308: */
309: OLEDBG_BEGIN2("IOleClientSite::ShowObject called\r\n");
310: lpServerDoc->m_lpOleClientSite->lpVtbl->ShowObject(
311: lpServerDoc->m_lpOleClientSite
312: );
313: OLEDBG_END2
314:
315: /* OLE2NOTE: if we are an embedded object and we are not
316: ** in-place active in our containers window, we must inform our
317: ** embedding container that our window is opening.
318: ** the container must now hatch our object.
319: */
320:
321: #if defined( INPLACE_SVR )
322: if (! lpServerDoc->m_fInPlaceActive)
323: #endif
324: {
325: OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(TRUE) called\r\n");
326: lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
327: lpServerDoc->m_lpOleClientSite,
328: TRUE
329: );
330: OLEDBG_END2
331: }
332:
333: /* OLE2NOTE: the life-time of our document is controlled by our
334: ** client and NOT by the user. we are not an independent
335: ** file-level object. we simply want to show our window here.
336: **
337: ** if we are not in-place active (ie. we are opening
338: ** our own window), we must make sure our main app window is
339: ** visible. we do not, however, want to give the user
340: ** control of the App window; we do not want OleApp_ShowWindow
341: ** to call OleApp_Lock on behalf of the user.
342: */
343: if (! IsWindowVisible(lpOutlineApp->m_hWndApp) ||
344: IsIconic(lpOutlineApp->m_hWndApp)) {
345: #if defined( INPLACE_SVR )
346: if (! ((LPSERVERDOC)lpOleDoc)->m_fInPlaceActive)
347: #endif
348: OleApp_ShowWindow(lpOleApp, FALSE /* fGiveUserCtrl */);
349: SetFocus(lpOutlineDoc->m_hWndDoc);
350: }
351:
352: } else
353: #endif // OLE_SERVER
354:
355: { // DOCTYPE_NEW || DOCTYPE_FROMFILE
356:
357: // we must make sure our app window is visible
358: OleApp_ShowWindow(lpOleApp, TRUE /* fGiveUserCtrl */);
359: }
360:
361: // make document window visible and make sure it is not minimized
362: ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL);
363: SetFocus(lpOutlineDoc->m_hWndDoc);
364:
365: OLEDBG_END3
366: }
367:
368:
369: /* OleDoc_HideWindow
370: * -----------------
371: *
372: * Hide the window of the document from the user.
373: * take away the control of the document by the user.
374: */
375: void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutdown)
376: {
377: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
378: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
379: LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
380:
381: if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))
382: return; // already visible
383:
384: OLEDBG_BEGIN3("OleDoc_HideWindow\r\n")
385:
386: #if defined( USE_DRAGDROP )
387: // The document's window is being hidden, revoke it as a DropTarget
388: if (lpOleDoc->m_fRegDragDrop) {
389: OLEDBG_BEGIN2("RevokeDragDrop called\r\n");
390: RevokeDragDrop(LineList_GetWindow(lpLL));
391: OLEDBG_END2
392:
393: lpOleDoc->m_fRegDragDrop = FALSE ;
394: }
395: #endif // USE_DRAGDROP
396:
397: /* OLE2NOTE: the document is now being hidden, so we must release
398: ** the external lock made when the document was made visible.
399: ** if this is a shutdown situation (fShutdown==TRUE), then OLE
400: ** is instructed to release our document. if this is that last
401: ** external lock on our document, thus enabling our document to
402: ** complete its shutdown operation. If This is not a shutdown
403: ** situation (eg. in-place server hiding its window when
404: ** UIDeactivating or IOleObject::DoVerb(OLEVERB_HIDE) is called),
405: ** then OLE is told to NOT immediately release the document.
406: ** this leaves the document in an unstable state where the next
407: ** Lock/Unlock sequence will shut the document down (eg. a
408: ** linking client connecting and disconnecting).
409: */
410: if (fShutdown && IsWindowVisible(lpOutlineDoc->m_hWndDoc))
411: OleDoc_Lock(lpOleDoc, FALSE /* fLock */, fShutdown);
412:
413: ShowWindow(((LPOUTLINEDOC)lpOleDoc)->m_hWndDoc, SW_HIDE);
414:
415: #if defined( OLE_SERVER )
416: {
417: LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
418:
419: /* OLE2NOTE: if we are an embedded object and we are not
420: ** in-place active, we must inform our
421: ** embedding container that our window is hiding (closing
422: ** from the user's perspective). the container must now
423: ** un-hatch our object.
424: */
425: if (lpServerDoc->m_lpOleClientSite != NULL
426: #if defined( INPLACE_SVR )
427: && !lpServerDoc->m_fInPlaceVisible
428: #endif
429: ) {
430: OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(FALSE) called\r\n");
431: lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
432: lpServerDoc->m_lpOleClientSite,
433: FALSE
434: );
435: OLEDBG_END2
436: }
437: }
438: #endif
439:
440: /* OLE2NOTE: if there are no more documents visible to the user.
441: ** and the app itself is not under user control, then
442: ** it has no reason to stay visible. we thus should hide the
443: ** app. we can not directly destroy the app, because it may be
444: ** validly being used programatically by another client
445: ** application and should remain running. it should simply be
446: ** hidded from the user.
447: */
448: OleApp_HideIfNoReasonToStayVisible(lpOleApp);
449: OLEDBG_END3
450: }
451:
452:
453: /* OleDoc_Lock
454: ** -----------
455: ** Lock/Unlock the Doc object. if the last lock is unlocked and
456: ** fLastUnlockReleases == TRUE, then the Doc object will shut down
457: ** (ie. it will recieve its final release and its refcnt will go to 0).
458: */
459: HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases)
460: {
461: HRESULT hrErr;
462:
463: #if defined( _DEBUG )
464: if (fLock) {
465: OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,TRUE) called\r\n")
466: } else {
467: if (fLastUnlockReleases)
468: OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,TRUE) called\r\n")
469: else
470: OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,FALSE) called\r\n")
471: }
472: #endif // _DEBUG
473:
474: OleDoc_AddRef(lpOleDoc); // artificial AddRef to make object stable
475:
476: hrErr = CoLockObjectExternal(
477: (LPUNKNOWN)&lpOleDoc->m_Unknown, fLock, fLastUnlockReleases);
478:
479: OleDoc_Release(lpOleDoc); // release artificial AddRef above
480:
481: OLEDBG_END2
482: return hrErr;
483: }
484:
485:
486: /* OleDoc_AddRef
487: ** -------------
488: **
489: ** increment the ref count of the document object.
490: **
491: ** Returns the new ref count on the object
492: */
493: ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc)
494: {
495: ++lpOleDoc->m_cRef;
496:
497: OleDbgOutRefCnt4(
498: "OleDoc_AddRef: cRef++\r\n",
499: lpOleDoc,
500: lpOleDoc->m_cRef
501: );
502:
503: return lpOleDoc->m_cRef;
504: }
505:
506:
507: /* OleDoc_Release
508: ** --------------
509: **
510: ** decrement the ref count of the document object.
511: ** if the ref count goes to 0, then the document is destroyed.
512: **
513: ** Returns the remaining ref count on the object
514: */
515: ULONG OleDoc_Release (LPOLEDOC lpOleDoc)
516: {
517: ULONG cRef;
518: LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
519: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
520:
521: OleDbgAssertSz (lpOleDoc->m_cRef > 0, "Release called with cRef == 0");
522:
523: /*********************************************************************
524: ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. **
525: ** otherwise the object is still in use. **
526: *********************************************************************/
527:
528: cRef = --lpOleDoc->m_cRef;
529:
530: OleDbgOutRefCnt4(
531: "OleDoc_Release: cRef--\r\n", lpOleDoc, cRef);
532:
533: if (cRef == 0)
534: OutlineDoc_Destroy((LPOUTLINEDOC)lpOleDoc);
535:
536: return cRef;
537: }
538:
539:
540: /* OleDoc_QueryInterface
541: ** ---------------------
542: **
543: ** Retrieve a pointer to an interface on the document object.
544: **
545: ** OLE2NOTE: this function will AddRef the ref cnt of the object.
546: **
547: ** Returns S_OK if interface is successfully retrieved.
548: ** S_FALSE if the interface is not supported
549: */
550: HRESULT OleDoc_QueryInterface(
551: LPOLEDOC lpOleDoc,
552: REFIID riid,
553: LPVOID FAR* lplpvObj
554: )
555: {
556: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
557: SCODE sc = E_NOINTERFACE;
558:
559: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */
560: *lplpvObj = NULL;
561:
562: if (IsEqualIID(riid, &IID_IUnknown)) {
563: OleDbgOut4("OleDoc_QueryInterface: IUnknown* RETURNED\r\n");
564:
565: *lplpvObj = (LPVOID) &lpOleDoc->m_Unknown;
566: OleDoc_AddRef(lpOleDoc);
567: sc = S_OK;
568: }
569: else if(lpOutlineDoc->m_fDataTransferDoc
570: && IsEqualIID(riid, &IID_IDataObject)) {
571: OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");
572:
573: *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;
574: OleDoc_AddRef(lpOleDoc);
575: sc = S_OK;
576: }
577:
578: #if defined( USE_DRAGDROP )
579:
580: /* DropSource is only needed on a DataTransferDoc */
581: else if(lpOutlineDoc->m_fDataTransferDoc
582: && IsEqualIID(riid, &IID_IDropSource)) {
583:
584: OleDbgOut4("OleDoc_QueryInterface: IDropSource* RETURNED\r\n");
585:
586: *lplpvObj = (LPVOID) &lpOleDoc->m_DropSource;
587: OleDoc_AddRef(lpOleDoc);
588: sc = S_OK;
589: }
590: #endif
591:
592: /* OLE2NOTE: if this document is a DataTransferDocument used to
593: ** support a clipboard or drag/drop operation, then it should
594: ** only expose IUnknown, IDataObject, and IDropSource
595: ** interfaces. if the document is a normal user document, then
596: ** we will also continue to consider our other interfaces.
597: */
598: if (lpOutlineDoc->m_fDataTransferDoc)
599: goto done;
600:
601: if(IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IPersistFile)) {
602: OleDbgOut4("OleDoc_QueryInterface: IPersistFile* RETURNED\r\n");
603:
604: *lplpvObj = (LPVOID) &lpOleDoc->m_PersistFile;
605: OleDoc_AddRef(lpOleDoc);
606: sc = S_OK;
607: }
608: else if(IsEqualIID(riid, &IID_IOleItemContainer) ||
609: IsEqualIID(riid, &IID_IOleContainer) ||
610: IsEqualIID(riid, &IID_IParseDisplayName) ) {
611: OleDbgOut4("OleDoc_QueryInterface: IOleItemContainer* RETURNED\r\n");
612:
613: *lplpvObj = (LPVOID) &lpOleDoc->m_OleItemContainer;
614: OleDoc_AddRef(lpOleDoc);
615: sc = S_OK;
616: }
617:
618: #if defined( USE_DRAGDROP )
619:
620: else if(IsEqualIID(riid, &IID_IDropTarget)) {
621: OleDbgOut4("OleDoc_QueryInterface: IDropTarget* RETURNED\r\n");
622:
623: *lplpvObj = (LPVOID) &lpOleDoc->m_DropTarget;
624: OleDoc_AddRef(lpOleDoc);
625: sc = S_OK;
626: }
627: #endif
628:
629: #if defined( OLE_CNTR ) && defined ( IID_IOleUILinkContainer )
630:
631: else if (IsEqualIID(riid, &IID_IOleUILinkContainer)) {
632: OleDbgOut4("OleDoc_QueryInterface: IOleUILinkContainer* RETURNED\r\n");
633:
634: *lplpvObj=(LPVOID)&((LPCONTAINERERDOC)lpOleDoc)->m_OleUILinkContainer;
635: OleDoc_AddRef(lpOleDoc);
636: sc = S_OK;
637: }
638: #endif
639:
640: #if defined( OLE_SERVER )
641:
642: /* OLE2NOTE: if OLE server version, than also offer the server
643: ** specific interfaces: IOleObject and IPersistStorage.
644: */
645: else if (IsEqualIID(riid, &IID_IOleObject)) {
646: OleDbgOut4("OleDoc_QueryInterface: IOleObject* RETURNED\r\n");
647:
648: *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleObject;
649: OleDoc_AddRef(lpOleDoc);
650: sc = S_OK;
651: }
652: else if(IsEqualIID(riid, &IID_IPersistStorage)) {
653: OleDbgOut4("OleDoc_QueryInterface: IPersistStorage* RETURNED\r\n");
654:
655: *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_PersistStorage;
656: OleDoc_AddRef(lpOleDoc);
657: sc = S_OK;
658: }
659: else if(IsEqualIID(riid, &IID_IDataObject)) {
660: OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");
661:
662: *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;
663: OleDoc_AddRef(lpOleDoc);
664: sc = S_OK;
665: }
666:
667: #if defined( SVR_TREATAS )
668: else if(IsEqualIID(riid, &IID_IStdMarshalInfo)) {
669: OleDbgOut4("OleDoc_QueryInterface: IStdMarshalInfo* RETURNED\r\n");
670:
671: *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_StdMarshalInfo;
672: OleDoc_AddRef(lpOleDoc);
673: sc = S_OK;
674: }
675: #endif // SVR_TREATAS
676:
677: #if defined( INPLACE_SVR )
678: else if (IsEqualIID(riid, &IID_IOleWindow) ||
679: IsEqualIID(riid, &IID_IOleInPlaceObject)) {
680: OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceObject* RETURNED\r\n");
681:
682: *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleInPlaceObject;
683: OleDoc_AddRef(lpOleDoc);
684: sc = S_OK;
685: }
686: #endif // INPLACE_SVR
687: #endif // OLE_SERVER
688:
689: done:
690: OleDbgQueryInterfaceMethod(*lplpvObj);
691:
692: return ResultFromScode(sc);
693: }
694:
695:
696: /* OleDoc_Close
697: * ------------
698: *
699: * Close the document.
700: * This functions performs the actions that are in common to all
701: * document types which derive from OleDoc (eg. ContainerDoc and
702: * ServerDoc) which are required to close a document.
703: *
704: * Returns:
705: * FALSE -- user canceled the closing of the doc.
706: * TRUE -- the doc was successfully closed
707: */
708:
709: BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption)
710: {
711: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
712: LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
713: LPOLEDOC lpClipboardDoc;
714: LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
715:
716: if (! lpOleDoc)
717: return TRUE; // active doc's are already destroyed
718:
719: if (lpOleDoc->m_fObjIsClosing)
720: return TRUE; // Closing is already in progress
721:
722: OLEDBG_BEGIN3("OleDoc_Close\r\n")
723:
724: if (! OutlineDoc_CheckSaveChanges((LPOUTLINEDOC)lpOleDoc, dwSaveOption)) {
725: OLEDBG_END3
726: return FALSE; // cancel closing the doc
727: }
728:
729: lpOleDoc->m_fObjIsClosing = TRUE; // guard against recursive call
730:
731: /* OLE2NOTE: in order to have a stable app and doc during the
732: ** process of closing, we intially AddRef the App and Doc ref
733: ** cnts and later Release them. These initial AddRefs are
734: ** artificial; they simply guarantee that these objects do not
735: ** get destroyed until the end of this routine.
736: */
737: OleApp_AddRef(lpOleApp);
738: OleDoc_AddRef(lpOleDoc);
739:
740: #if defined( OLE_CNTR )
741: {
742: LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
743:
744: /* OLE2NOTE: force all OLE objects to close. this forces all
745: ** OLE object to transition from running to loaded. we can
746: ** NOT exit if any embeddings are still running.
747: ** if an object can't be closed then we will abort closing
748: ** our document.
749: */
750: if (! ContainerDoc_CloseAllOleObjects(lpContainerDoc)) {
751: OleDoc_Release(lpOleDoc); // release artificial AddRef above
752: OleApp_Release(lpOleApp); // release artificial AddRef above
753: lpOleDoc->m_fObjIsClosing = FALSE; // guard against recursive call
754:
755: OLEDBG_END3
756: return FALSE;
757: }
758: }
759: #endif
760:
761: #if defined( INPLACE_SVR )
762: /* OLE2NOTE: if the server is currently in-place active we must
763: ** deactivate it now before closing
764: */
765: ServerDoc_DoInPlaceDeactivate((LPSERVERDOC)lpOleDoc);
766: #endif
767:
768: /* OLE2NOTE: if this document is the source of data for the
769: ** clipboard, then flush the clipboard. it is important to flush
770: ** the clipboard BEFORE calling sending any notifications to
771: ** clients (eg. IOleClientSite::OnShowWindow(FALSE)) which could
772: ** give them a chance to run and try to get our clipboard data
773: ** object that we want to destroy. (eg. our app tries to
774: ** update the paste button of the toolbar when
775: ** WM_ACTIVATEAPP is received.)
776: */
777: lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
778: if (lpClipboardDoc &&
779: lpClipboardDoc->m_lpSrcDocOfCopy == lpOleDoc) {
780: OleApp_FlushClipboard(lpOleApp);
781: }
782:
783: /* OLE2NOTE: Revoke the object from the Running Object Table. it is
784: ** best if the object is revoke prior to calling
785: ** COLockObjectExternal(FALSE,TRUE) which is called when the
786: ** document window is hidden from the user.
787: */
788: OLEDBG_BEGIN3("OleStdRevokeAsRunning called\r\n")
789: OleStdRevokeAsRunning(&lpOleDoc->m_dwRegROT);
790: OLEDBG_END3
791:
792: /* OLE2NOTE: if the user is in control of the document, the user
793: ** accounts for one refcnt on the document. Closing the
794: ** document is achieved by releasing the object on behalf of
795: ** the user. if the document is not referenced by any other
796: ** clients, then the document will also be destroyed. if it
797: ** is referenced by other clients, then it will remain until
798: ** they release it. it is important to hide the window and call
799: ** IOleClientSite::OnShowWindow(FALSE) BEFORE sending OnClose
800: ** notification.
801: */
802: OleDoc_HideWindow(lpOleDoc, TRUE);
803:
804: #if defined( OLE_SERVER )
805: {
806: LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
807: LPSERVERNAMETABLE lpServerNameTable =
808: (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpOleDoc)->m_lpNameTable;
809:
810: /* OLE2NOTE: force all pseudo objects to close. this informs all
811: ** linking clients of pseudo objects to release their PseudoObj.
812: */
813: ServerNameTable_CloseAllPseudoObjs(lpServerNameTable);
814:
815: /* OLE2NOTE: send last OnDataChange notification to clients
816: ** that have registered for data notifications when object
817: ** stops running (ADVF_DATAONSTOP), if the data in our
818: ** object has ever changed. it is best to only send this
819: ** notification if necessary.
820: */
821: if (lpServerDoc->m_fSendDataOnStop
822: && lpServerDoc->m_lpDataAdviseHldr) {
823: ServerDoc_SendAdvise(
824: (LPSERVERDOC)lpOleDoc,
825: OLE_ONDATACHANGE,
826: NULL, /* lpmkDoc -- not relevant here */
827: ADVF_DATAONSTOP
828: );
829:
830: /* OLE2NOTE: we just sent the last data notification that we
831: ** need to send; release our DataAdviseHolder. we SHOULD be
832: ** the only one using it.
833: */
834:
835: OleStdVerifyRelease(
836: (LPUNKNOWN)lpServerDoc->m_lpDataAdviseHldr,
837: "DataAdviseHldr not released properly"
838: );
839: lpServerDoc->m_lpDataAdviseHldr = NULL;
840: }
841:
842: // OLE2NOTE: inform all of our linking clients that we are closing.
843:
844:
845: if (lpServerDoc->m_lpOleAdviseHldr) {
846: ServerDoc_SendAdvise(
847: (LPSERVERDOC)lpOleDoc,
848: OLE_ONCLOSE,
849: NULL, /* lpmkDoc -- not relevant here */
850: 0 /* advf -- not relevant here */
851: );
852:
853: /* OLE2NOTE: OnClose is the last notification that we need to
854: ** send; release our OleAdviseHolder. we SHOULD be the only
855: ** one using it. this will make our destructor realize that
856: ** OnClose notification has already been sent.
857: */
858: OleStdVerifyRelease(
859: (LPUNKNOWN)lpServerDoc->m_lpOleAdviseHldr,
860: "OleAdviseHldr not released properly"
861: );
862: lpServerDoc->m_lpOleAdviseHldr = NULL;
863: }
864:
865: /* release our Container's ClientSite. */
866: if(lpServerDoc->m_lpOleClientSite) {
867: OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);
868: lpServerDoc->m_lpOleClientSite = NULL;
869: }
870: }
871: #endif
872:
873: /* OLE2NOTE: this call forces all external connections to our
874: ** object to close down and therefore guarantees that we receive
875: ** all releases associated with those external connections.
876: */
877: OLEDBG_BEGIN2("CoDisconnectObject(lpDoc) called\r\n")
878: CoDisconnectObject((LPUNKNOWN)&lpOleDoc->m_Unknown, 0);
879: OLEDBG_END2
880:
881: OleDoc_Release(lpOleDoc); // release artificial AddRef above
882: OleApp_Release(lpOleApp); // release artificial AddRef above
883:
884: OLEDBG_END3
885: return TRUE;
886: }
887:
888:
889: /* OleDoc_Destroy
890: * --------------
891: *
892: * Free all OLE related resources that had been allocated for a document.
893: */
894: void OleDoc_Destroy(LPOLEDOC lpOleDoc)
895: {
896: LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
897: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
898:
899: if (lpOleDoc->m_fObjIsDestroying)
900: return; // Doc destruction is already in progress
901:
902: lpOleDoc->m_fObjIsDestroying = TRUE; // guard against recursive call
903:
904: /* OLE2NOTE: if the document destructor is called directly because
905: ** the object's refcnt went to 0 (ie. without OleDoc_Close first
906: ** being called), then we need to make sure that the document is
907: ** properly closed before destroying the object. this scenario
908: ** could arise during a silent-update of a link. calling
909: ** OleDoc_Close here guarantees that the clipboard will be
910: ** properly flushed, the doc's moniker will be properly revoked,
911: ** the document will be saved if necessary, etc.
912: */
913: if (!lpOutlineDoc->m_fDataTransferDoc && !lpOleDoc->m_fObjIsClosing)
914: OleDoc_Close(lpOleDoc, OLECLOSE_SAVEIFDIRTY);
915:
916: #if defined( OLE_SERVER )
917: {
918: LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
919: /* OLE2NOTE: perform processing specific for an OLE server */
920:
921: #if defined( SVR_TREATAS )
922: if (lpServerDoc->m_lpszTreatAsType) {
923: OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);
924: lpServerDoc->m_lpszTreatAsType = NULL;
925: }
926: #endif // SVR_TREATAS
927:
928: #if defined( INPLACE_SVR )
929: if (IsWindow(lpServerDoc->m_hWndHatch))
930: DestroyWindow(lpServerDoc->m_hWndHatch);
931: #endif // INPLACE_SVR
932: }
933: #endif // OLE_SERVER
934:
935:
936: #if defined( OLE_CNTR )
937: {
938: LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
939: /* OLE2NOTE: perform processing specific for an OLE container */
940:
941: if (lpContainerDoc->m_lpStg) {
942: /* release our doc storage. */
943: OleStdRelease((LPUNKNOWN)lpContainerDoc->m_lpStg);
944: lpContainerDoc->m_lpStg = NULL;
945: }
946: }
947: #endif // OLE_CNTR
948:
949: if (lpOleDoc->m_lpFileMoniker) {
950: OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);
951: lpOleDoc->m_lpFileMoniker = NULL;
952: }
953:
954: /*****************************************************************
955: ** OLE2NOTE: each document addref's the app object in order to **
956: ** guarentee that the app does not shut down while the doc **
957: ** is still open. since this doc is now destroyed, we will **
958: ** release this refcnt now. if there are now more open **
959: ** documents AND the app is not under the control of the **
960: ** user (ie. launched by OLE) then the app will revoke its **
961: ** ClassFactory. if there are no more references to the **
962: ** ClassFactory after it is revoked, then the app will shut **
963: ** down. this whole procedure is triggered by calling **
964: ** OutlineApp_DocUnlockApp. **
965: *****************************************************************/
966:
967: OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc);
968: }
969:
970:
971: /* OleDoc_SetUpdateEditMenuFlag
972: * ----------------------------
973: *
974: * Purpose:
975: * Set/clear the UpdateEditMenuFlag in OleDoc.
976: *
977: * Parameters:
978: * fUpdate new value of the flag
979: *
980: * Returns:
981: */
982: void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate)
983: {
984: if (!lpOleDoc)
985: return;
986:
987: lpOleDoc->m_fUpdateEditMenu = fUpdate;
988: }
989:
990:
991: /* OleDoc_GetUpdateEditMenuFlag
992: * ----------------------------
993: *
994: * Purpose:
995: * Get the value of the UpdateEditMenuFlag in OleDoc
996: *
997: * Parameters:
998: *
999: * Returns:
1000: * value of the flag
1001: */
1002: BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc)
1003: {
1004: if (!lpOleDoc)
1005: return FALSE;
1006:
1007: return lpOleDoc->m_fUpdateEditMenu;
1008: }
1009:
1010:
1011:
1012: /*************************************************************************
1013: ** OleDoc::IUnknown interface implementation
1014: *************************************************************************/
1015:
1016: STDMETHODIMP OleDoc_Unk_QueryInterface(
1017: LPUNKNOWN lpThis,
1018: REFIID riid,
1019: LPVOID FAR* lplpvObj
1020: )
1021: {
1022: LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
1023:
1024: return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
1025: }
1026:
1027:
1028: STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis)
1029: {
1030: LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
1031:
1032: OleDbgAddRefMethod(lpThis, "IUnknown");
1033:
1034: return OleDoc_AddRef(lpOleDoc);
1035: }
1036:
1037:
1038: STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis)
1039: {
1040: LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
1041:
1042: OleDbgReleaseMethod(lpThis, "IUnknown");
1043:
1044: return OleDoc_Release(lpOleDoc);
1045: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.