|
|
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.