|
|
1.1 ! root 1: /************************************************************************* ! 2: ** ! 3: ** OLE 2 Sample Code ! 4: ** ! 5: ** linking.c ! 6: ** ! 7: ** This file contains the major interfaces, methods and related support ! 8: ** functions for implementing linking to items. The code ! 9: ** contained in this file is used by BOTH the Container and Server ! 10: ** (Object) versions of the Outline sample code. ! 11: ** ! 12: ** As a server SVROUTL supports linking to the whole document object ! 13: ** (either a file-based document or as an embedded object). It also ! 14: ** supports linking to ranges (or PseudoObjects). ! 15: ** ! 16: ** As a container CNTROUTL supports linking to embedded objects. ! 17: ** (see file svrpsobj.c for Pseudo Object implementation) ! 18: ** ! 19: ** OleDoc Object ! 20: ** exposed interfaces: ! 21: ** IPersistFile ! 22: ** IOleItemContainer ! 23: ** ! 24: ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved ! 25: ** ! 26: *************************************************************************/ ! 27: ! 28: #include "outline.h" ! 29: ! 30: OLEDBGDATA ! 31: ! 32: extern LPOUTLINEAPP g_lpApp; ! 33: ! 34: ! 35: ! 36: /************************************************************************* ! 37: ** OleDoc::IPersistFile interface implementation ! 38: *************************************************************************/ ! 39: ! 40: STDMETHODIMP OleDoc_PFile_QueryInterface( ! 41: LPPERSISTFILE lpThis, ! 42: REFIID riid, ! 43: LPVOID FAR* lplpvObj ! 44: ) ! 45: { ! 46: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 47: ! 48: return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); ! 49: } ! 50: ! 51: ! 52: STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis) ! 53: { ! 54: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 55: ! 56: OleDbgAddRefMethod(lpThis, "IPersistFile"); ! 57: ! 58: return OleDoc_AddRef(lpOleDoc); ! 59: } ! 60: ! 61: ! 62: STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis) ! 63: { ! 64: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 65: ! 66: OleDbgReleaseMethod(lpThis, "IPersistFile"); ! 67: ! 68: return OleDoc_Release(lpOleDoc); ! 69: } ! 70: ! 71: ! 72: STDMETHODIMP OleDoc_PFile_GetClassID ( ! 73: LPPERSISTFILE lpThis, ! 74: CLSID FAR* lpclsid ! 75: ) ! 76: { ! 77: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 78: LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; ! 79: ! 80: OleDbgOut2("OleDoc_PFile_GetClassID\r\n"); ! 81: ! 82: #if defined( OLE_SERVER ) && defined( SVR_TREATAS ) ! 83: ! 84: /* OLE2NOTE: we must be carefull to return the correct CLSID here. ! 85: ** if we are currently preforming a "TreatAs (aka. ActivateAs)" ! 86: ** operation then we need to return the class of the object ! 87: ** written in the storage of the object. otherwise we would ! 88: ** return our own class id. ! 89: */ ! 90: return ServerDoc_GetClassID((LPSERVERDOC)lpOleDoc, lpclsid); ! 91: #else ! 92: *lpclsid = CLSID_APP; ! 93: #endif ! 94: return NOERROR; ! 95: } ! 96: ! 97: ! 98: STDMETHODIMP OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis) ! 99: { ! 100: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 101: ! 102: OleDbgOut2("OleDoc_PFile_IsDirty\r\n"); ! 103: ! 104: if (OutlineDoc_IsModified((LPOUTLINEDOC)lpOleDoc)) ! 105: return NOERROR; ! 106: else ! 107: return ResultFromScode(S_FALSE); ! 108: } ! 109: ! 110: ! 111: STDMETHODIMP OleDoc_PFile_Load ( ! 112: LPPERSISTFILE lpThis, ! 113: LPCSTR lpszFileName, ! 114: DWORD grfMode ! 115: ) ! 116: { ! 117: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 118: SCODE sc; ! 119: ! 120: OLEDBG_BEGIN2("OleDoc_PFile_Load\r\n") ! 121: ! 122: /* OLE2NOTE: grfMode passed from the caller indicates if the caller ! 123: ** needs Read or ReadWrite permissions. if appropriate the ! 124: ** callee should open the file with the requested permissions. ! 125: ** the caller will normally not impose sharing permissions. ! 126: ** ! 127: ** the sample code currently always opens its file ReadWrite. ! 128: */ ! 129: ! 130: if (OutlineDoc_LoadFromFile((LPOUTLINEDOC)lpOleDoc, (LPSTR)lpszFileName)) ! 131: sc = S_OK; ! 132: else ! 133: sc = S_FALSE; ! 134: ! 135: OLEDBG_END2 ! 136: return ResultFromScode(sc); ! 137: } ! 138: ! 139: ! 140: STDMETHODIMP OleDoc_PFile_Save ( ! 141: LPPERSISTFILE lpThis, ! 142: LPCSTR lpszFileName, ! 143: BOOL fRemember ! 144: ) ! 145: { ! 146: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 147: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; ! 148: SCODE sc; ! 149: ! 150: OLEDBG_BEGIN2("OleDoc_PFile_Save\r\n") ! 151: ! 152: /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation ! 153: ** on a file-based document. if the document is an embedded ! 154: ** object then we can not be changed to a file-base object. ! 155: ** ! 156: ** fRemember lpszFileName Type of Save ! 157: ** ---------------------------------------------- ! 158: ** N/A NULL SAVE ! 159: ** TRUE ! NULL SAVE AS ! 160: ** FALSE ! NULL SAVE COPY AS ! 161: */ ! 162: if ( (lpszFileName==NULL || (lpszFileName != NULL && fRemember)) ! 163: && ((lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE ! 164: && lpOutlineDoc->m_docInitType != DOCTYPE_NEW)) ) { ! 165: OLEDBG_END2 ! 166: return ResultFromScode(E_INVALIDARG); ! 167: } ! 168: ! 169: if (OutlineDoc_SaveToFile( ! 170: (LPOUTLINEDOC)lpOleDoc, ! 171: lpszFileName, ! 172: lpOutlineDoc->m_cfSaveFormat, ! 173: fRemember)) { ! 174: sc = S_OK; ! 175: } else ! 176: sc = E_FAIL; ! 177: ! 178: OLEDBG_END2 ! 179: return ResultFromScode(sc); ! 180: } ! 181: ! 182: ! 183: STDMETHODIMP OleDoc_PFile_SaveCompleted ( ! 184: LPPERSISTFILE lpThis, ! 185: LPCSTR lpszFileName ! 186: ) ! 187: { ! 188: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 189: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; ! 190: ! 191: OLEDBG_BEGIN2("OleDoc_PFile_SaveCompleted\r\n") ! 192: ! 193: /* OLE2NOTE: this method should be called in the Save or SaveAs ! 194: ** situtations. it is illegal to call this method unless we are a ! 195: ** file-based object (we should also NOT be of type DOCTYPE_NEW ! 196: ** either because IPersistFile::Save should have been called by ! 197: ** now. ! 198: */ ! 199: if (lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE) { ! 200: OLEDBG_END2 ! 201: return ResultFromScode(E_INVALIDARG); ! 202: } ! 203: ! 204: // Clear dirty flag upon save or saveAs ! 205: OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); ! 206: ! 207: #if defined( OLE_SERVER ) ! 208: ! 209: /* OLE2NOTE: this method should be called in the Save or SaveAs ! 210: ** situtations. it informs us that the caller is done with the data ! 211: ** in the file. Until SaveCompleted call is finished, we may not ! 212: ** change the contents of the file. since we do not normally ! 213: ** scribble in our file, we do not have to care about this. ! 214: */ ! 215: ServerDoc_SendAdvise ( ! 216: (LPSERVERDOC)lpOleDoc, ! 217: OLE_ONSAVE, ! 218: NULL, /* lpmkDoc -- not relevant here */ ! 219: 0 /* advf -- not relevant here */ ! 220: ); ! 221: ! 222: #endif // OLE_SERVER ! 223: ! 224: OLEDBG_END2 ! 225: return NOERROR; ! 226: } ! 227: ! 228: ! 229: STDMETHODIMP OleDoc_PFile_GetCurFile ( ! 230: LPPERSISTFILE lpThis, ! 231: LPSTR FAR* lplpszFileName ! 232: ) ! 233: { ! 234: LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; ! 235: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; ! 236: LPMALLOC lpMalloc; ! 237: LPSTR lpsz; ! 238: SCODE sc; ! 239: ! 240: OleDbgOut2("OleDoc_PFile_GetCurFile\r\n"); ! 241: ! 242: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ ! 243: *lplpszFileName = NULL; ! 244: ! 245: /********************************************************************* ! 246: ** OLE2NOTE: memory returned for the lplpszFileName must be ! 247: ** allocated appropriately using the current registered IMalloc ! 248: ** interface. the allows the ownership of the memory to be ! 249: ** passed to the caller (even if in another process). ! 250: *********************************************************************/ ! 251: ! 252: CoGetMalloc(MEMCTX_TASK, &lpMalloc); ! 253: if (! lpMalloc) { ! 254: return ResultFromScode(E_FAIL); ! 255: } ! 256: ! 257: if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) { ! 258: /* valid filename associated; return file name */ ! 259: lpsz = (LPSTR)lpMalloc->lpVtbl->Alloc( ! 260: lpMalloc, ! 261: lstrlen((LPSTR)lpOutlineDoc->m_szFileName)+1 ! 262: ); ! 263: lstrcpy(lpsz, (LPSTR)lpOutlineDoc->m_szFileName); ! 264: sc = S_OK; ! 265: } else { ! 266: /* no file associated; return default file name prompt */ ! 267: lpsz=(LPSTR)lpMalloc->lpVtbl->Alloc(lpMalloc, sizeof(DEFEXTENSION)+3); ! 268: wsprintf(lpsz, "*.%s", DEFEXTENSION); ! 269: sc = S_FALSE; ! 270: } ! 271: ! 272: OleStdRelease((LPUNKNOWN)lpMalloc); ! 273: *lplpszFileName = lpsz; ! 274: return ResultFromScode(sc); ! 275: } ! 276: ! 277: ! 278: /************************************************************************* ! 279: ** OleDoc::IOleItemContainer interface implementation ! 280: *************************************************************************/ ! 281: ! 282: STDMETHODIMP OleDoc_ItemCont_QueryInterface( ! 283: LPOLEITEMCONTAINER lpThis, ! 284: REFIID riid, ! 285: LPVOID FAR* lplpvObj ! 286: ) ! 287: { ! 288: LPOLEDOC lpOleDoc = ! 289: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 290: ! 291: return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); ! 292: } ! 293: ! 294: ! 295: STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis) ! 296: { ! 297: LPOLEDOC lpOleDoc = ! 298: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 299: ! 300: OleDbgAddRefMethod(lpThis, "IOleItemContainer"); ! 301: ! 302: return OleDoc_AddRef((LPOLEDOC)lpOleDoc); ! 303: } ! 304: ! 305: ! 306: STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis) ! 307: { ! 308: LPOLEDOC lpOleDoc = ! 309: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 310: ! 311: OleDbgReleaseMethod(lpThis, "IOleItemContainer"); ! 312: ! 313: return OleDoc_Release((LPOLEDOC)lpOleDoc); ! 314: } ! 315: ! 316: ! 317: STDMETHODIMP OleDoc_ItemCont_ParseDisplayName( ! 318: LPOLEITEMCONTAINER lpThis, ! 319: LPBC lpbc, ! 320: LPSTR lpszDisplayName, ! 321: ULONG FAR* lpchEaten, ! 322: LPMONIKER FAR* lplpmkOut ! 323: ) ! 324: { ! 325: LPOLEDOC lpOleDoc = ! 326: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 327: char szItemName[MAXNAMESIZE]; ! 328: LPUNKNOWN lpUnk; ! 329: HRESULT hrErr; ! 330: ! 331: OleDbgOut2("OleDoc_ItemCont_ParseDisplayName\r\n"); ! 332: ! 333: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ ! 334: *lplpmkOut = NULL; ! 335: ! 336: *lpchEaten = OleStdGetItemToken( ! 337: lpszDisplayName, ! 338: szItemName, ! 339: sizeof(szItemName) ! 340: ); ! 341: ! 342: /* OLE2NOTE: get a pointer to a running instance of the object. we ! 343: ** should force the object to go running if necessary (even if ! 344: ** this means launching its server EXE). this is the meaining of ! 345: ** BINDSPEED_INDEFINITE. Parsing a Moniker is known to be an ! 346: ** "EXPENSIVE" operation. ! 347: */ ! 348: hrErr = OleDoc_ItemCont_GetObject( ! 349: lpThis, ! 350: szItemName, ! 351: BINDSPEED_INDEFINITE, ! 352: lpbc, ! 353: &IID_IUnknown, ! 354: (LPVOID FAR*)&lpUnk ! 355: ); ! 356: ! 357: if (hrErr == NOERROR) { ! 358: OleStdRelease(lpUnk); // item name FOUND; don't need obj ptr. ! 359: CreateItemMoniker(OLESTDDELIM, szItemName, lplpmkOut); ! 360: } else ! 361: *lpchEaten = 0; // item name is NOT valid ! 362: ! 363: return hrErr; ! 364: } ! 365: ! 366: ! 367: STDMETHODIMP OleDoc_ItemCont_EnumObjects( ! 368: LPOLEITEMCONTAINER lpThis, ! 369: DWORD grfFlags, ! 370: LPENUMUNKNOWN FAR* lplpenumUnknown ! 371: ) ! 372: { ! 373: LPOLEDOC lpOleDoc = ! 374: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 375: ! 376: OLEDBG_BEGIN2("OleDoc_ItemCont_EnumObjects\r\n") ! 377: ! 378: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ ! 379: *lplpenumUnknown = NULL; ! 380: ! 381: /* OLE2NOTE: this method should be implemented to allow programatic ! 382: ** clients the ability to what elements the container holds. ! 383: ** this method is NOT called in the standard linking scenarios. ! 384: ** ! 385: ** grfFlags can be one of the following: ! 386: ** OLECONTF_EMBEDDINGS -- enumerate embedded objects ! 387: ** OLECONTF_LINKS -- enumerate linked objects ! 388: ** OLECONTF_OTHERS -- enumerate non-OLE compound doc objs ! 389: ** OLECONTF_ONLYUSER -- enumerate only objs named by user ! 390: ** OLECONTF_ONLYIFRUNNING-- enumerate only objs in running state ! 391: */ ! 392: ! 393: OleDbgAssertSz(0, "NOT YET IMPLEMENTED!"); ! 394: ! 395: OLEDBG_END2 ! 396: return ResultFromScode(E_NOTIMPL); ! 397: } ! 398: ! 399: ! 400: STDMETHODIMP OleDoc_ItemCont_LockContainer( ! 401: LPOLEITEMCONTAINER lpThis, ! 402: BOOL fLock ! 403: ) ! 404: { ! 405: LPOLEDOC lpOleDoc = ! 406: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 407: HRESULT hrErr; ! 408: ! 409: OLEDBG_BEGIN2("OleDoc_ItemCont_LockContainer\r\n") ! 410: ! 411: #if defined( _DEBUG ) ! 412: if (fLock) { ! 413: ++lpOleDoc->m_cLock; ! 414: ! 415: OleDbgOutRefCnt3( ! 416: "OleDoc_ItemCont_LockContainer: cLock++\r\n", ! 417: lpOleDoc, lpOleDoc->m_cLock); ! 418: } else { ! 419: ! 420: /* OLE2NOTE: when there are no open documents and the app is not ! 421: ** under the control of the user and there are no outstanding ! 422: ** locks on the app, then revoke our ClassFactory to enable the ! 423: ** app to shut down. ! 424: */ ! 425: OleDbgAssertSz (lpOleDoc->m_cLock > 0, ! 426: "OleDoc_ItemCont_LockContainer(FALSE) called with cLock == 0" ! 427: ); ! 428: ! 429: --lpOleDoc->m_cLock; ! 430: ! 431: if (lpOleDoc->m_cLock == 0) { ! 432: OleDbgOutRefCnt2( ! 433: "OleDoc_ItemCont_LockContainer: UNLOCKED\r\n", ! 434: lpOleDoc, lpOleDoc->m_cLock); ! 435: } else { ! 436: OleDbgOutRefCnt3( ! 437: "OleDoc_ItemCont_LockContainer: cLock--\r\n", ! 438: lpOleDoc, lpOleDoc->m_cLock); ! 439: } ! 440: } ! 441: #endif // _DEBUG ! 442: ! 443: /* OLE2NOTE: in order to hold the document alive we call ! 444: ** CoLockObjectExternal to add a strong reference to our Doc ! 445: ** object. this will keep the Doc alive when all other external ! 446: ** references release us. whenever an embedded object goes ! 447: ** running a LockContainer(TRUE) is called. when the embedded ! 448: ** object shuts down (ie. transitions from running to loaded) ! 449: ** LockContainer(FALSE) is called. if the user issues File.Close ! 450: ** the document will shut down in any case ignoring any ! 451: ** outstanding LockContainer locks because CoDisconnectObject is ! 452: ** called in OleDoc_Close. this will forceably break any ! 453: ** existing strong reference counts including counts that we add ! 454: ** ourselves by calling CoLockObjectExternal and guarantee that ! 455: ** the Doc object gets its final release (ie. cRefs goes to 0). ! 456: */ ! 457: hrErr = OleDoc_Lock(lpOleDoc, fLock, TRUE /* fLastUnlockReleases */); ! 458: ! 459: OLEDBG_END2 ! 460: return hrErr; ! 461: } ! 462: ! 463: ! 464: STDMETHODIMP OleDoc_ItemCont_GetObject( ! 465: LPOLEITEMCONTAINER lpThis, ! 466: LPSTR lpszItem, ! 467: DWORD dwSpeedNeeded, ! 468: LPBINDCTX lpbc, ! 469: REFIID riid, ! 470: LPVOID FAR* lplpvObject ! 471: ) ! 472: { ! 473: LPOLEDOC lpOleDoc = ! 474: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 475: HRESULT hrErr; ! 476: ! 477: OLEDBG_BEGIN2("OleDoc_ItemCont_GetObject\r\n") ! 478: ! 479: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ ! 480: *lplpvObject = NULL; ! 481: ! 482: #if defined( OLE_SERVER ) ! 483: ! 484: /* OLE2NOTE: SERVER ONLY version should return PseudoObjects with ! 485: ** BINDSPEED_IMMEDIATE, thus the dwSpeedNeeded is not important ! 486: ** in the case of a pure server. ! 487: */ ! 488: hrErr = ServerDoc_GetObject( ! 489: (LPSERVERDOC)lpOleDoc, lpszItem,riid,lplpvObject); ! 490: ! 491: #elif defined( OLE_CNTR ) ! 492: ! 493: /* OLE2NOTE: dwSpeedNeeded indicates how long the caller is willing ! 494: ** to wait for us to get the object: ! 495: ** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning ! 496: ** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning ! 497: ** BINDSPEED_INDEFINITE-- force obj to load and run if necessary ! 498: */ ! 499: hrErr = ContainerDoc_GetObject( ! 500: (LPCONTAINERDOC)lpOleDoc,lpszItem,dwSpeedNeeded,riid,lplpvObject); ! 501: #endif ! 502: ! 503: OLEDBG_END2 ! 504: return hrErr; ! 505: } ! 506: ! 507: ! 508: STDMETHODIMP OleDoc_ItemCont_GetObjectStorage( ! 509: LPOLEITEMCONTAINER lpThis, ! 510: LPSTR lpszItem, ! 511: LPBINDCTX lpbc, ! 512: REFIID riid, ! 513: LPVOID FAR* lplpvStorage ! 514: ) ! 515: { ! 516: LPOLEDOC lpOleDoc = ! 517: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 518: ! 519: OleDbgOut2("OleDoc_ItemCont_GetObjectStorage\r\n"); ! 520: ! 521: /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ ! 522: *lplpvStorage = NULL; ! 523: ! 524: #if defined( OLE_SERVER ) ! 525: ! 526: /* OLE2NOTE: in the SERVER ONLY version, item names identify pseudo ! 527: ** objects. pseudo objects, do NOT have identifiable storage. ! 528: */ ! 529: return ResultFromScode(E_FAIL); ! 530: ! 531: ! 532: #elif defined( OLE_CNTR ) ! 533: ! 534: // We can only return an IStorage* type pointer ! 535: if (! IsEqualIID(riid, &IID_IStorage)) ! 536: return ResultFromScode(E_FAIL); ! 537: ! 538: return ContainerDoc_GetObjectStorage( ! 539: (LPCONTAINERDOC)lpOleDoc, ! 540: lpszItem, ! 541: (LPSTORAGE FAR*)lplpvStorage ! 542: ); ! 543: #endif ! 544: } ! 545: ! 546: ! 547: STDMETHODIMP OleDoc_ItemCont_IsRunning( ! 548: LPOLEITEMCONTAINER lpThis, ! 549: LPSTR lpszItem ! 550: ) ! 551: { ! 552: LPOLEDOC lpOleDoc = ! 553: ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; ! 554: HRESULT hrErr; ! 555: ! 556: OLEDBG_BEGIN2("OleDoc_ItemCont_IsRunning\r\n") ! 557: ! 558: /* OLE2NOTE: Check if item name is valid. if so then return if ! 559: ** Object is running. PseudoObjects in the Server version are ! 560: ** always considered running. Ole objects in the container must ! 561: ** be checked if they are running. ! 562: */ ! 563: ! 564: #if defined( OLE_SERVER ) ! 565: ! 566: hrErr = ServerDoc_IsRunning((LPSERVERDOC)lpOleDoc, lpszItem); ! 567: ! 568: #elif defined( OLE_CNTR ) ! 569: ! 570: hrErr = ContainerDoc_IsRunning((LPCONTAINERDOC)lpOleDoc, lpszItem); ! 571: ! 572: #endif ! 573: ! 574: OLEDBG_END2 ! 575: return hrErr; ! 576: } ! 577: ! 578: ! 579: /************************************************************************* ! 580: ** OleDoc Common Support Functions ! 581: *************************************************************************/ ! 582: ! 583: ! 584: /* OleDoc_GetFullMoniker ! 585: ** --------------------- ! 586: ** Return the full, absolute moniker of the document. ! 587: ** ! 588: ** NOTE: the caller must release the pointer returned when done. ! 589: */ ! 590: LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign) ! 591: { ! 592: LPMONIKER lpMoniker = NULL; ! 593: ! 594: OLEDBG_BEGIN3("OleDoc_GetFullMoniker\r\n") ! 595: ! 596: if (lpOleDoc->m_lpSrcDocOfCopy) { ! 597: /* CASE I: this document was created for a copy or drag/drop ! 598: ** operation. generate the moniker which identifies the ! 599: ** source document of the original copy. ! 600: */ ! 601: if (! lpOleDoc->m_fLinkSourceAvail) ! 602: goto done; // we already know a moniker is not available ! 603: ! 604: lpMoniker = OleDoc_GetFullMoniker( ! 605: lpOleDoc->m_lpSrcDocOfCopy, ! 606: dwAssign ! 607: ); ! 608: } ! 609: else if (lpOleDoc->m_lpFileMoniker) { ! 610: ! 611: /* CASE II: this document is a top-level user document (either ! 612: ** file-based or untitled). return the FileMoniker stored ! 613: ** with the document; it uniquely identifies the document. ! 614: */ ! 615: ! 616: // we must AddRef the moniker to pass out a ptr ! 617: lpOleDoc->m_lpFileMoniker->lpVtbl->AddRef(lpOleDoc->m_lpFileMoniker); ! 618: ! 619: lpMoniker = lpOleDoc->m_lpFileMoniker; ! 620: } ! 621: ! 622: #if defined( OLE_SERVER ) ! 623: ! 624: else if (((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite) { ! 625: ! 626: /* CASE III: this document is an embedded object, ask our ! 627: ** container for our moniker. ! 628: */ ! 629: OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n"); ! 630: ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite->lpVtbl->GetMoniker( ! 631: ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite, ! 632: dwAssign, ! 633: OLEWHICHMK_OBJFULL, ! 634: &lpMoniker ! 635: ); ! 636: OLEDBG_END2 ! 637: } ! 638: ! 639: #endif ! 640: ! 641: else { ! 642: lpMoniker = NULL; ! 643: } ! 644: ! 645: done: ! 646: OLEDBG_END3 ! 647: return lpMoniker; ! 648: } ! 649: ! 650: ! 651: /* OleDoc_DocRenamedUpdate ! 652: ** ----------------------- ! 653: ** Update the documents registration in the running object table (ROT). ! 654: ** Also inform all embedded OLE objects (container only) and/or psedudo ! 655: ** objects (server only) that the name of the document has changed. ! 656: */ ! 657: void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc) ! 658: { ! 659: OLEDBG_BEGIN3("OleDoc_DocRenamedUpdate\r\n") ! 660: ! 661: OleDoc_AddRef(lpOleDoc); ! 662: ! 663: /* OLE2NOTE: we must re-register ourselves as running when we ! 664: ** get a new moniker assigned (ie. when we are renamed). ! 665: */ ! 666: OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n") ! 667: OleStdRegisterAsRunning( ! 668: (LPUNKNOWN)&lpOleDoc->m_Unknown, ! 669: lpmkDoc, ! 670: &lpOleDoc->m_dwRegROT ! 671: ); ! 672: OLEDBG_END3 ! 673: ! 674: #if defined( OLE_SERVER ) ! 675: { ! 676: LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; ! 677: ! 678: /* OLE2NOTE: inform any linking clients that the document has been ! 679: ** renamed. in addition, any currently active pseudo objects ! 680: ** should also inform their clients. ! 681: */ ! 682: ServerDoc_SendAdvise ( ! 683: lpServerDoc, ! 684: OLE_ONRENAME, ! 685: lpmkDoc, ! 686: 0 /* advf -- not relevant here */ ! 687: ); ! 688: } ! 689: ! 690: #elif defined( OLE_CNTR ) ! 691: { ! 692: LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; ! 693: ! 694: /* OLE2NOTE: must tell all OLE objects that our container ! 695: ** moniker changed. ! 696: */ ! 697: ContainerDoc_InformAllOleObjectsDocRenamed( ! 698: lpContainerDoc, ! 699: lpmkDoc ! 700: ); ! 701: } ! 702: #endif ! 703: ! 704: OleDoc_Release(lpOleDoc); // release artificial AddRef above ! 705: OLEDBG_END3 ! 706: } ! 707: ! 708: ! 709: ! 710: #if defined( OLE_SERVER ) ! 711: ! 712: /************************************************************************* ! 713: ** ServerDoc Supprt Functions Used by Server versions ! 714: *************************************************************************/ ! 715: ! 716: ! 717: /* ServerDoc_PseudoObjLockDoc ! 718: ** -------------------------- ! 719: ** Add a lock on the Doc on behalf of the PseudoObject. the Doc may not ! 720: ** close while the Doc exists. ! 721: ** ! 722: ** when a pseudo object is first created, it calls this method to ! 723: ** guarantee that the document stays alive (PseudoObj_Init). ! 724: ** when a pseudo object is destroyed, it call ! 725: ** ServerDoc_PseudoObjUnlockDoc to release this hold on the document. ! 726: */ ! 727: void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc) ! 728: { ! 729: LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; ! 730: ULONG cPseudoObj; ! 731: ! 732: cPseudoObj = ++lpServerDoc->m_cPseudoObj; ! 733: ! 734: OleDbgOutRefCnt3( ! 735: "ServerDoc_PseudoObjLockDoc: cPseudoObj++\r\n", ! 736: lpServerDoc, ! 737: cPseudoObj ! 738: ); ! 739: ! 740: OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */); ! 741: return; ! 742: } ! 743: ! 744: ! 745: /* ServerDoc_PseudoObjUnlockDoc ! 746: ** ---------------------------- ! 747: ** Release the lock on the Doc on behalf of the PseudoObject. if this was ! 748: ** the last lock on the Doc, then it will shutdown. ! 749: */ ! 750: void ServerDoc_PseudoObjUnlockDoc( ! 751: LPSERVERDOC lpServerDoc, ! 752: LPPSEUDOOBJ lpPseudoObj ! 753: ) ! 754: { ! 755: ULONG cPseudoObj; ! 756: LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; ! 757: ! 758: OLEDBG_BEGIN3("ServerDoc_PseudoObjUnlockDoc\r\n") ! 759: ! 760: /* OLE2NOTE: when there are no active pseudo objects in the Doc and ! 761: ** the Doc is not visible, and if there are no outstanding locks ! 762: ** on the Doc, then this is a "silent update" ! 763: ** situation. our Doc is being used programatically by some ! 764: ** client; it is NOT accessible to the user because it is ! 765: ** NOT visible. thus since all Locks have been released, we ! 766: ** will close the document. if the app is only running due ! 767: ** to the presence of this document, then the app will now ! 768: ** also shut down. ! 769: */ ! 770: OleDbgAssertSz ( ! 771: lpServerDoc->m_cPseudoObj > 0, ! 772: "PseudoObjUnlockDoc called with cPseudoObj == 0" ! 773: ); ! 774: ! 775: cPseudoObj = --lpServerDoc->m_cPseudoObj; ! 776: ! 777: OleDbgOutRefCnt3( ! 778: "ServerDoc_PseudoObjUnlockDoc: cPseudoObj--\r\n", ! 779: lpServerDoc, ! 780: cPseudoObj ! 781: ); ! 782: ! 783: OleDoc_Lock(lpOleDoc, FALSE /* fLock */, TRUE /* fLastUnlockReleases */); ! 784: ! 785: OLEDBG_END3 ! 786: return; ! 787: } ! 788: ! 789: ! 790: /* ServerDoc_GetObject ! 791: ** ------------------- ! 792: ** ! 793: ** Return a pointer to an object identified by an item string ! 794: ** (lpszItem). For a server-only app, the object returned will be a ! 795: ** pseudo object. ! 796: */ ! 797: HRESULT ServerDoc_GetObject( ! 798: LPSERVERDOC lpServerDoc, ! 799: LPSTR lpszItem, ! 800: REFIID riid, ! 801: LPVOID FAR* lplpvObject ! 802: ) ! 803: { ! 804: LPPSEUDOOBJ lpPseudoObj; ! 805: LPSERVERNAMETABLE lpServerNameTable = ! 806: (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; ! 807: ! 808: *lplpvObject = NULL; ! 809: ! 810: /* Get the PseudoObj which corresponds to an item name. if the item ! 811: ** name does NOT exist in the name table then NO object is ! 812: ** returned. the ServerNameTable_GetPseudoObj routine finds a ! 813: ** name entry corresponding to the item name, it then checks if ! 814: ** a PseudoObj has already been allocated. if so, it returns the ! 815: ** existing object, otherwise it allocates a new PseudoObj. ! 816: */ ! 817: lpPseudoObj = ServerNameTable_GetPseudoObj( ! 818: lpServerNameTable, ! 819: lpszItem, ! 820: lpServerDoc ! 821: ); ! 822: ! 823: if (! lpPseudoObj) { ! 824: *lplpvObject = NULL; ! 825: return ResultFromScode(MK_E_NOOBJECT); ! 826: } ! 827: ! 828: // return the desired interface pointer of the pseudo object. ! 829: return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObject); ! 830: } ! 831: ! 832: ! 833: /* ServerDoc_IsRunning ! 834: ** ------------------- ! 835: ** ! 836: ** Check if the object identified by an item string (lpszItem) is in ! 837: ** the running state. For a server-only app, if the item name exists in ! 838: ** in the NameTable then the item name is considered running. ! 839: ** IOleItemContainer::GetObject would succeed. ! 840: */ ! 841: ! 842: HRESULT ServerDoc_IsRunning(LPSERVERDOC lpServerDoc, LPSTR lpszItem) ! 843: { ! 844: LPOUTLINENAMETABLE lpOutlineNameTable = ! 845: ((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; ! 846: LPSERVERNAME lpServerName; ! 847: ! 848: lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( ! 849: lpOutlineNameTable, ! 850: lpszItem ! 851: ); ! 852: ! 853: if (lpServerName) ! 854: return NOERROR; ! 855: else ! 856: return ResultFromScode(MK_E_NOOBJECT); ! 857: } ! 858: ! 859: ! 860: /* ServerDoc_GetSelRelMoniker ! 861: ** -------------------------- ! 862: ** Retrieve the relative item moniker which identifies the given ! 863: ** selection (lplrSel). ! 864: ** ! 865: ** Returns NULL if a moniker can NOT be created. ! 866: */ ! 867: ! 868: LPMONIKER ServerDoc_GetSelRelMoniker( ! 869: LPSERVERDOC lpServerDoc, ! 870: LPLINERANGE lplrSel, ! 871: DWORD dwAssign ! 872: ) ! 873: { ! 874: LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; ! 875: LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; ! 876: LPSERVERNAMETABLE lpServerNameTable = ! 877: (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable; ! 878: LPOUTLINENAMETABLE lpOutlineNameTable = ! 879: (LPOUTLINENAMETABLE)lpServerNameTable; ! 880: LPOUTLINENAME lpOutlineName; ! 881: LPMONIKER lpmk; ! 882: ! 883: lpOutlineName=OutlineNameTable_FindNamedRange(lpOutlineNameTable,lplrSel); ! 884: ! 885: if (lpOutlineName) { ! 886: /* the selection range already has a name assigned */ ! 887: CreateItemMoniker(OLESTDDELIM, lpOutlineName->m_szName, &lpmk); ! 888: } else { ! 889: char szbuf[MAXNAMESIZE]; ! 890: ! 891: switch (dwAssign) { ! 892: ! 893: case GETMONIKER_FORCEASSIGN: ! 894: ! 895: /* Force the assignment of the name. This is called when a ! 896: ** Paste Link actually occurs. At this point we want to ! 897: ** create a Name and add it to the NameTable in order to ! 898: ** track the source of the link. This name (as all ! 899: ** names) will be updated upon editing of the document. ! 900: */ ! 901: wsprintf( ! 902: szbuf, ! 903: "%s %ld", ! 904: (LPSTR)DEFRANGENAMEPREFIX, ! 905: ++(lpServerDoc->m_nNextRangeNo) ! 906: ); ! 907: ! 908: lpOutlineName = OutlineApp_CreateName(lpOutlineApp); ! 909: ! 910: if (lpOutlineName) { ! 911: lstrcpy(lpOutlineName->m_szName, szbuf); ! 912: lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; ! 913: lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; ! 914: OutlineDoc_AddName(lpOutlineDoc, lpOutlineName); ! 915: } else { ! 916: // REVIEW: do we need "Out-of-Memory" error message here? ! 917: } ! 918: break; ! 919: ! 920: case GETMONIKER_TEMPFORUSER: ! 921: ! 922: /* Create a name to show to the user in the Paste ! 923: ** Special dialog but do NOT yet incur the overhead ! 924: ** of adding a Name to the NameTable. The Moniker ! 925: ** generated should be useful to display to the user ! 926: ** to indicate the source of the copy, but will NOT ! 927: ** be used to create a link directly (the caller ! 928: ** should ask again for a moniker specifying FORCEASSIGN). ! 929: ** we will generate the name that would be the next ! 930: ** auto-generated range name, BUT will NOT actually ! 931: ** increment the range counter. ! 932: */ ! 933: wsprintf( ! 934: szbuf, ! 935: "%s %ld", ! 936: (LPSTR)DEFRANGENAMEPREFIX, ! 937: (lpServerDoc->m_nNextRangeNo)+1 ! 938: ); ! 939: break; ! 940: ! 941: case GETMONIKER_ONLYIFTHERE: ! 942: ! 943: /* the caller only wants a name if one has already been ! 944: ** assigned. we have already above checked if the ! 945: ** current selection has a name, so we will simply ! 946: ** return NULL here. ! 947: */ ! 948: return NULL; // no moniker is assigned ! 949: ! 950: default: ! 951: return NULL; // unknown flag given ! 952: } ! 953: ! 954: CreateItemMoniker(OLESTDDELIM, szbuf, &lpmk); ! 955: } ! 956: return lpmk; ! 957: } ! 958: ! 959: ! 960: /* ServerDoc_GetSelFullMoniker ! 961: ** --------------------------- ! 962: ** Retrieve the full absolute moniker which identifies the given ! 963: ** selection (lplrSel). ! 964: ** this moniker is created as a composite of the absolute moniker for ! 965: ** the entire document appended with an item moniker which identifies ! 966: ** the selection relative to the document. ! 967: ** Returns NULL if a moniker can NOT be created. ! 968: */ ! 969: LPMONIKER ServerDoc_GetSelFullMoniker( ! 970: LPSERVERDOC lpServerDoc, ! 971: LPLINERANGE lplrSel, ! 972: DWORD dwAssign ! 973: ) ! 974: { ! 975: LPMONIKER lpmkDoc = NULL; ! 976: LPMONIKER lpmkItem = NULL; ! 977: LPMONIKER lpmkFull = NULL; ! 978: ! 979: lpmkDoc = OleDoc_GetFullMoniker( ! 980: (LPOLEDOC)lpServerDoc, ! 981: dwAssign ! 982: ); ! 983: if (! lpmkDoc) return NULL; ! 984: ! 985: lpmkItem = ServerDoc_GetSelRelMoniker( ! 986: lpServerDoc, ! 987: lplrSel, ! 988: dwAssign ! 989: ); ! 990: if (lpmkItem) { ! 991: CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull); ! 992: OleStdRelease((LPUNKNOWN)lpmkItem); ! 993: } ! 994: ! 995: if (lpmkDoc) ! 996: OleStdRelease((LPUNKNOWN)lpmkDoc); ! 997: ! 998: return lpmkFull; ! 999: } ! 1000: ! 1001: ! 1002: /* ServerNameTable_EditLineUpdate ! 1003: * ------------------------------- ! 1004: * ! 1005: * Update the table when a line at nEditIndex is edited. ! 1006: */ ! 1007: void ServerNameTable_EditLineUpdate( ! 1008: LPSERVERNAMETABLE lpServerNameTable, ! 1009: int nEditIndex ! 1010: ) ! 1011: { ! 1012: LPOUTLINENAMETABLE lpOutlineNameTable = ! 1013: (LPOUTLINENAMETABLE)lpServerNameTable; ! 1014: LPOUTLINENAME lpOutlineName; ! 1015: LINERANGE lrSel; ! 1016: LPPSEUDOOBJ lpPseudoObj; ! 1017: int i; ! 1018: ! 1019: for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { ! 1020: lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); ! 1021: ! 1022: lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; ! 1023: ! 1024: /* if there is a pseudo object associated with this name, then ! 1025: ** check if the line that was modified is included within ! 1026: ** the named range. ! 1027: */ ! 1028: if (lpPseudoObj) { ! 1029: OutlineName_GetSel(lpOutlineName, &lrSel); ! 1030: ! 1031: if(((int)lrSel.m_nStartLine <= nEditIndex) && ! 1032: ((int)lrSel.m_nEndLine >= nEditIndex)) { ! 1033: ! 1034: // inform linking clients data has changed ! 1035: PseudoObj_SendAdvise( ! 1036: lpPseudoObj, ! 1037: OLE_ONDATACHANGE, ! 1038: NULL, /* lpmkDoc -- not relevant here */ ! 1039: 0 /* advf -- no flags necessary */ ! 1040: ); ! 1041: } ! 1042: ! 1043: } ! 1044: } ! 1045: } ! 1046: ! 1047: ! 1048: /* ServerNameTable_InformAllPseudoObjectsDocRenamed ! 1049: * ------------------------------------------------ ! 1050: * ! 1051: * Inform all pseudo object clients that the name of the pseudo ! 1052: * object has changed. ! 1053: */ ! 1054: void ServerNameTable_InformAllPseudoObjectsDocRenamed( ! 1055: LPSERVERNAMETABLE lpServerNameTable, ! 1056: LPMONIKER lpmkDoc ! 1057: ) ! 1058: { ! 1059: LPOUTLINENAMETABLE lpOutlineNameTable = ! 1060: (LPOUTLINENAMETABLE)lpServerNameTable; ! 1061: LPOUTLINENAME lpOutlineName; ! 1062: LPPSEUDOOBJ lpPseudoObj; ! 1063: LPMONIKER lpmkObj; ! 1064: int i; ! 1065: ! 1066: OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocRenamed\r\n"); ! 1067: ! 1068: for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { ! 1069: lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); ! 1070: ! 1071: lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; ! 1072: ! 1073: /* if there is a pseudo object associated with this name, then ! 1074: ** send OnRename advise to its linking clients. ! 1075: */ ! 1076: if (lpPseudoObj && ! 1077: ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { ! 1078: ! 1079: // inform the clients that the name has changed ! 1080: PseudoObj_SendAdvise ( ! 1081: lpPseudoObj, ! 1082: OLE_ONRENAME, ! 1083: lpmkObj, ! 1084: 0 /* advf -- not relevant here */ ! 1085: ); ! 1086: } ! 1087: } ! 1088: OLEDBG_END2 ! 1089: } ! 1090: ! 1091: ! 1092: /* ServerNameTable_InformAllPseudoObjectsDocSaved ! 1093: * ------------------------------------------------ ! 1094: * ! 1095: * Inform all pseudo object clients that the name of the pseudo ! 1096: * object has changed. ! 1097: */ ! 1098: void ServerNameTable_InformAllPseudoObjectsDocSaved( ! 1099: LPSERVERNAMETABLE lpServerNameTable, ! 1100: LPMONIKER lpmkDoc ! 1101: ) ! 1102: { ! 1103: LPOUTLINENAMETABLE lpOutlineNameTable = ! 1104: (LPOUTLINENAMETABLE)lpServerNameTable; ! 1105: LPOUTLINENAME lpOutlineName; ! 1106: LPPSEUDOOBJ lpPseudoObj; ! 1107: LPMONIKER lpmkObj; ! 1108: int i; ! 1109: ! 1110: OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocSaved\r\n"); ! 1111: ! 1112: for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { ! 1113: lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); ! 1114: ! 1115: lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; ! 1116: ! 1117: /* if there is a pseudo object associated with this name, then ! 1118: ** send OnSave advise to its linking clients. ! 1119: */ ! 1120: if (lpPseudoObj && ! 1121: ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { ! 1122: ! 1123: // inform the clients that the name has been saved ! 1124: PseudoObj_SendAdvise ( ! 1125: lpPseudoObj, ! 1126: OLE_ONSAVE, ! 1127: NULL, /* lpmkDoc -- not relevant here */ ! 1128: 0 /* advf -- not relevant here */ ! 1129: ); ! 1130: } ! 1131: } ! 1132: OLEDBG_END2 ! 1133: } ! 1134: ! 1135: ! 1136: /* ServerNameTable_SendPendingAdvises ! 1137: * ---------------------------------- ! 1138: * ! 1139: * Send any pending change notifications for pseudo objects. ! 1140: * while ReDraw is diabled on the ServerDoc, then change advise ! 1141: * notifications are not sent to pseudo object clients. ! 1142: */ ! 1143: void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable) ! 1144: { ! 1145: LPOUTLINENAMETABLE lpOutlineNameTable = ! 1146: (LPOUTLINENAMETABLE)lpServerNameTable; ! 1147: LPSERVERNAME lpServerName; ! 1148: int i; ! 1149: ! 1150: for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { ! 1151: lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( ! 1152: lpOutlineNameTable, ! 1153: i ! 1154: ); ! 1155: ServerName_SendPendingAdvises(lpServerName); ! 1156: } ! 1157: } ! 1158: ! 1159: ! 1160: /* ServerNameTable_GetPseudoObj ! 1161: ** ---------------------------- ! 1162: ** ! 1163: ** Return a pointer to a pseudo object identified by an item string ! 1164: ** (lpszItem). if the pseudo object already exists, then return the ! 1165: ** existing object, otherwise allocate a new pseudo object. ! 1166: */ ! 1167: LPPSEUDOOBJ ServerNameTable_GetPseudoObj( ! 1168: LPSERVERNAMETABLE lpServerNameTable, ! 1169: LPSTR lpszItem, ! 1170: LPSERVERDOC lpServerDoc ! 1171: ) ! 1172: { ! 1173: LPSERVERNAME lpServerName; ! 1174: ! 1175: lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( ! 1176: (LPOUTLINENAMETABLE)lpServerNameTable, ! 1177: lpszItem ! 1178: ); ! 1179: ! 1180: if (lpServerName) ! 1181: return ServerName_GetPseudoObj(lpServerName, lpServerDoc); ! 1182: else ! 1183: return NULL; ! 1184: } ! 1185: ! 1186: ! 1187: /* ServerNameTable_CloseAllPseudoObjs ! 1188: * ---------------------------------- ! 1189: * ! 1190: * Force all pseudo objects to close. this results in sending OnClose ! 1191: * notification to each pseudo object's linking clients. ! 1192: */ ! 1193: void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable) ! 1194: { ! 1195: LPOUTLINENAMETABLE lpOutlineNameTable = ! 1196: (LPOUTLINENAMETABLE)lpServerNameTable; ! 1197: LPSERVERNAME lpServerName; ! 1198: int i; ! 1199: ! 1200: OLEDBG_BEGIN3("ServerNameTable_CloseAllPseudoObjs\r\n") ! 1201: ! 1202: for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { ! 1203: lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( ! 1204: lpOutlineNameTable, ! 1205: i ! 1206: ); ! 1207: ServerName_ClosePseudoObj(lpServerName); ! 1208: } ! 1209: ! 1210: OLEDBG_END3 ! 1211: } ! 1212: ! 1213: ! 1214: ! 1215: /* ServerName_SetSel ! 1216: * ----------------- ! 1217: * ! 1218: * Change the line range of a name. ! 1219: */ ! 1220: void ServerName_SetSel( ! 1221: LPSERVERNAME lpServerName, ! 1222: LPLINERANGE lplrSel, ! 1223: BOOL fRangeModified ! 1224: ) ! 1225: { ! 1226: LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpServerName; ! 1227: BOOL fPseudoObjChanged = fRangeModified; ! 1228: ! 1229: if (lpOutlineName->m_nStartLine != lplrSel->m_nStartLine) { ! 1230: lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; ! 1231: fPseudoObjChanged = TRUE; ! 1232: } ! 1233: ! 1234: if (lpOutlineName->m_nEndLine != lplrSel->m_nEndLine) { ! 1235: lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; ! 1236: fPseudoObjChanged = TRUE; ! 1237: } ! 1238: ! 1239: /* OLE2NOTE: if the range of an active pseudo object has ! 1240: ** changed, then inform any linking clients that the object ! 1241: ** has changed. ! 1242: */ ! 1243: if (lpServerName->m_lpPseudoObj && fPseudoObjChanged) { ! 1244: PseudoObj_SendAdvise( ! 1245: lpServerName->m_lpPseudoObj, ! 1246: OLE_ONDATACHANGE, ! 1247: NULL, /* lpmkDoc -- not relevant here */ ! 1248: 0 /* advf -- no flags necessary */ ! 1249: ); ! 1250: } ! 1251: } ! 1252: ! 1253: ! 1254: /* ServerName_SendPendingAdvises ! 1255: * ----------------------------- ! 1256: * ! 1257: * Send any pending change notifications for the associated ! 1258: * pseudo objects for this name (if one exists). ! 1259: * while ReDraw is diabled on the ServerDoc, then change advise ! 1260: * notifications are not sent to pseudo object clients. ! 1261: */ ! 1262: void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName) ! 1263: { ! 1264: if (! lpServerName->m_lpPseudoObj) ! 1265: return; // no associated pseudo object ! 1266: ! 1267: if (lpServerName->m_lpPseudoObj->m_fDataChanged) ! 1268: PseudoObj_SendAdvise( ! 1269: lpServerName->m_lpPseudoObj, ! 1270: OLE_ONDATACHANGE, ! 1271: NULL, /* lpmkDoc -- not relevant here */ ! 1272: 0 /* advf -- no flags necessary */ ! 1273: ); ! 1274: } ! 1275: ! 1276: ! 1277: /* ServerName_GetPseudoObj ! 1278: ** ----------------------- ! 1279: ** ! 1280: ** Return a pointer to a pseudo object associated to a ServerName. ! 1281: ** if the pseudo object already exists, then return the ! 1282: ** existing object, otherwise allocate a new pseudo object. ! 1283: ** ! 1284: ** NOTE: the PseudoObj is returned with a 0 refcnt if first created, ! 1285: ** else the existing refcnt is unchanged. ! 1286: */ ! 1287: LPPSEUDOOBJ ServerName_GetPseudoObj( ! 1288: LPSERVERNAME lpServerName, ! 1289: LPSERVERDOC lpServerDoc ! 1290: ) ! 1291: { ! 1292: // Check if a PseudoObj already exists ! 1293: if (lpServerName->m_lpPseudoObj) ! 1294: return lpServerName->m_lpPseudoObj; ! 1295: ! 1296: // A PseudoObj does NOT already exist, allocate a new one. ! 1297: lpServerName->m_lpPseudoObj=(LPPSEUDOOBJ) New((DWORD)sizeof(PSEUDOOBJ)); ! 1298: if (lpServerName->m_lpPseudoObj == NULL) { ! 1299: OleDbgAssertSz(lpServerName->m_lpPseudoObj != NULL, ! 1300: "Error allocating PseudoObj"); ! 1301: return NULL; ! 1302: } ! 1303: ! 1304: PseudoObj_Init(lpServerName->m_lpPseudoObj, lpServerName, lpServerDoc); ! 1305: return lpServerName->m_lpPseudoObj; ! 1306: } ! 1307: ! 1308: ! 1309: /* ServerName_ClosePseudoObj ! 1310: * ------------------------- ! 1311: * ! 1312: * if there is an associated pseudo objects for this name (if one ! 1313: * exists), then close it. this results in sending OnClose ! 1314: * notification to the pseudo object's linking clients. ! 1315: */ ! 1316: void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName) ! 1317: { ! 1318: if (! lpServerName->m_lpPseudoObj) ! 1319: return; // no associated pseudo object ! 1320: ! 1321: PseudoObj_Close(lpServerName->m_lpPseudoObj); ! 1322: } ! 1323: ! 1324: ! 1325: #endif // OLE_SERVER ! 1326: ! 1327: ! 1328: #if defined( OLE_CNTR ) ! 1329: ! 1330: ! 1331: /************************************************************************* ! 1332: ** ContainerDoc Supprt Functions Used by Container versions ! 1333: *************************************************************************/ ! 1334: ! 1335: ! 1336: /* ContainerDoc_InformAllOleObjectsDocRenamed ! 1337: ** ------------------------------------------ ! 1338: ** Inform all OLE objects that the name of the ContainerDoc has changed. ! 1339: */ ! 1340: void ContainerDoc_InformAllOleObjectsDocRenamed( ! 1341: LPCONTAINERDOC lpContainerDoc, ! 1342: LPMONIKER lpmkDoc ! 1343: ) ! 1344: { ! 1345: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; ! 1346: int i; ! 1347: LPLINE lpLine; ! 1348: ! 1349: for (i = 0; i < lpLL->m_nNumLines; i++) { ! 1350: lpLine=LineList_GetLine(lpLL, i); ! 1351: ! 1352: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { ! 1353: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; ! 1354: ! 1355: /* OLE2NOTE: if the OLE object is already loaded AND the ! 1356: ** object already has a moniker assigned, then we need ! 1357: ** to inform it that the moniker of the ContainerDoc has ! 1358: ** changed. of course, this means the full moniker of ! 1359: ** the object has changed. to do this we call ! 1360: ** IOleObject::SetMoniker. this will force the OLE ! 1361: ** object to re-register in the RunningObjectTable if it ! 1362: ** is currently in the running state. it is not in the ! 1363: ** running state, the object handler can make not that ! 1364: ** the object has a new moniker. if the object is not ! 1365: ** currently loaded, SetMoniker will be called ! 1366: ** automatically later when the object is loaded by the ! 1367: ** function ContainerLine_LoadOleObject. ! 1368: ** also if the object is a linked object, we always want ! 1369: ** to call SetMoniker on the link so that in case the ! 1370: ** link source is contained within our same container, ! 1371: ** the link source will be tracked. the link rebuilds ! 1372: ** its absolute moniker if it has a relative moniker. ! 1373: */ ! 1374: if (lpContainerLine->m_lpOleObj) { ! 1375: if (lpContainerLine->m_fMonikerAssigned || ! 1376: lpContainerLine->m_fIsLink) { ! 1377: OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") ! 1378: lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( ! 1379: lpContainerLine->m_lpOleObj, ! 1380: OLEWHICHMK_CONTAINER, ! 1381: lpmkDoc ! 1382: ); ! 1383: OLEDBG_END2 ! 1384: } ! 1385: ! 1386: /* OLE2NOTE: we must call IOleObject::SetHostNames so ! 1387: ** any open objects can update their window titles. ! 1388: */ ! 1389: OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n") ! 1390: lpContainerLine->m_lpOleObj->lpVtbl->SetHostNames( ! 1391: lpContainerLine->m_lpOleObj, ! 1392: (LPSTR)APPNAME, ! 1393: ((LPOUTLINEDOC)lpContainerDoc)->m_lpszDocTitle ! 1394: ); ! 1395: OLEDBG_END2 ! 1396: } ! 1397: } ! 1398: } ! 1399: } ! 1400: ! 1401: ! 1402: /* ContainerDoc_GetObject ! 1403: ** ---------------------- ! 1404: ** Return a pointer to the desired interface of an object identified ! 1405: ** by an item string (lpszItem). the object returned will be an OLE ! 1406: ** object (either link or embedding). ! 1407: ** ! 1408: ** OLE2NOTE: we must force the object to run because we are ! 1409: ** REQUIRED to return a pointer the OLE object in the ! 1410: ** RUNNING state. ! 1411: ** ! 1412: ** dwSpeedNeeded indicates how long the caller is willing ! 1413: ** to wait for us to get the object: ! 1414: ** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning ! 1415: ** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning ! 1416: ** BINDSPEED_INDEFINITE-- force obj to load and run if necessary ! 1417: */ ! 1418: HRESULT ContainerDoc_GetObject( ! 1419: LPCONTAINERDOC lpContainerDoc, ! 1420: LPSTR lpszItem, ! 1421: DWORD dwSpeedNeeded, ! 1422: REFIID riid, ! 1423: LPVOID FAR* lplpvObject ! 1424: ) ! 1425: { ! 1426: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; ! 1427: int i; ! 1428: LPLINE lpLine; ! 1429: BOOL fMatchFound = FALSE; ! 1430: DWORD dwStatus; ! 1431: HRESULT hrErr; ! 1432: ! 1433: *lplpvObject = NULL; ! 1434: ! 1435: for (i = 0; i < lpLL->m_nNumLines; i++) { ! 1436: lpLine=LineList_GetLine(lpLL, i); ! 1437: ! 1438: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { ! 1439: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; ! 1440: ! 1441: if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { ! 1442: ! 1443: fMatchFound = TRUE; // valid item name ! 1444: ! 1445: // check if object is loaded. ! 1446: if (lpContainerLine->m_lpOleObj == NULL) { ! 1447: ! 1448: // if BINDSPEED_IMMEDIATE is requested, object must ! 1449: // ALREADY be loadded. ! 1450: if (dwSpeedNeeded == BINDSPEED_IMMEDIATE) ! 1451: return ResultFromScode(MK_E_EXCEEDEDDEADLINE); ! 1452: ! 1453: ContainerLine_LoadOleObject(lpContainerLine); ! 1454: if (! lpContainerLine->m_lpOleObj) ! 1455: return ResultFromScode(E_OUTOFMEMORY); ! 1456: } ! 1457: ! 1458: /* OLE2NOTE: check if the object is allowed to be linked ! 1459: ** to from the inside (ie. we are allowed to ! 1460: ** give out a moniker which binds to the running ! 1461: ** OLE object). if the object is an OLE ! 1462: ** 2.0 embedded object then it is allowed to be ! 1463: ** linked to from the inside. if the object is ! 1464: ** either an OleLink or an OLE 1.0 embedding ! 1465: ** then it can not be linked to from the inside. ! 1466: ** if we were a container/server app then we ! 1467: ** could offer linking to the outside of the ! 1468: ** object (ie. a pseudo object within our ! 1469: ** document). we are a container only app that ! 1470: ** does not support linking to ranges of its data. ! 1471: */ ! 1472: OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n"); ! 1473: lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( ! 1474: lpContainerLine->m_lpOleObj, ! 1475: DVASPECT_CONTENT, /* aspect is not important */ ! 1476: (LPDWORD)&dwStatus ! 1477: ); ! 1478: OLEDBG_END2 ! 1479: if (dwStatus & OLEMISC_CANTLINKINSIDE) ! 1480: return ResultFromScode(MK_E_NOOBJECT); ! 1481: ! 1482: // check if object is running. ! 1483: if (! OleIsRunning(lpContainerLine->m_lpOleObj)) { ! 1484: ! 1485: // if BINDSPEED_MODERATE is requested, object must ! 1486: // ALREADY be running. ! 1487: if (dwSpeedNeeded == BINDSPEED_MODERATE) ! 1488: return ResultFromScode(MK_E_EXCEEDEDDEADLINE); ! 1489: ! 1490: /* OLE2NOTE: we have found a match for the item name. ! 1491: ** now we must return a pointer to the desired ! 1492: ** interface on the RUNNING object. we must ! 1493: ** carefully load the object and initially ask for ! 1494: ** an interface that we are sure the loaded form of ! 1495: ** the object supports. if we immediately ask the ! 1496: ** loaded object for the desired interface, the ! 1497: ** QueryInterface call might fail if it is an ! 1498: ** interface that is supported only when the object ! 1499: ** is running. thus we force the object to load and ! 1500: ** return its IUnknown*. then we force the object to ! 1501: ** run, and then finally, we can ask for the ! 1502: ** actually requested interface. ! 1503: */ ! 1504: hrErr = ContainerLine_RunOleObject(lpContainerLine); ! 1505: if (hrErr != NOERROR) { ! 1506: /* OLE2NOTE: this demonstrates an example use of ! 1507: ** PropagateResult. this allows us to return an ! 1508: ** SCODE of our choosing, but still passing ! 1509: ** along the error context of the previous ! 1510: ** error. in the future this will be used to ! 1511: ** stack up error contexts. ! 1512: */ ! 1513: return PropagateResult(hrErr, E_FAIL); ! 1514: } ! 1515: } ! 1516: ! 1517: // Retrieve the requested interface ! 1518: *lplpvObject = OleStdQueryInterface( ! 1519: (LPUNKNOWN)lpContainerLine->m_lpOleObj, riid); ! 1520: ! 1521: break; // Match FOUND! ! 1522: } ! 1523: } ! 1524: } ! 1525: ! 1526: if (*lplpvObject != NULL) { ! 1527: return NOERROR; ! 1528: } else ! 1529: return (fMatchFound ? ResultFromScode(E_NOINTERFACE) ! 1530: : ResultFromScode(MK_E_NOOBJECT)); ! 1531: } ! 1532: ! 1533: ! 1534: /* ContainerDoc_GetObjectStorage ! 1535: ** ----------------------------- ! 1536: ** Return a pointer to the IStorage* used by the object identified ! 1537: ** by an item string (lpszItem). the object identified could be either ! 1538: ** an OLE object (either link or embedding). ! 1539: */ ! 1540: HRESULT ContainerDoc_GetObjectStorage( ! 1541: LPCONTAINERDOC lpContainerDoc, ! 1542: LPSTR lpszItem, ! 1543: LPSTORAGE FAR* lplpStg ! 1544: ) ! 1545: { ! 1546: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; ! 1547: int i; ! 1548: LPLINE lpLine; ! 1549: ! 1550: *lplpStg = NULL; ! 1551: ! 1552: for (i = 0; i < lpLL->m_nNumLines; i++) { ! 1553: lpLine=LineList_GetLine(lpLL, i); ! 1554: ! 1555: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { ! 1556: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; ! 1557: ! 1558: if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { ! 1559: ! 1560: *lplpStg = lpContainerLine->m_lpStg; ! 1561: break; // Match FOUND! ! 1562: } ! 1563: } ! 1564: } ! 1565: ! 1566: if (*lplpStg != NULL) { ! 1567: return NOERROR; ! 1568: } else ! 1569: return ResultFromScode(MK_E_NOOBJECT); ! 1570: } ! 1571: ! 1572: ! 1573: /* ContainerDoc_IsRunning ! 1574: ** ---------------------- ! 1575: ** Check if the object identified by an item string (lpszItem) is in ! 1576: ** the running state. ! 1577: ** For a container-only app, a check is made if the OLE object ! 1578: ** associated with the item name is running. ! 1579: */ ! 1580: HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC lpContainerDoc, LPSTR lpszItem) ! 1581: { ! 1582: LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; ! 1583: int i; ! 1584: LPLINE lpLine; ! 1585: DWORD dwStatus; ! 1586: ! 1587: for (i = 0; i < lpLL->m_nNumLines; i++) { ! 1588: lpLine=LineList_GetLine(lpLL, i); ! 1589: ! 1590: if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { ! 1591: LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; ! 1592: ! 1593: if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { ! 1594: ! 1595: /* OLE2NOTE: we have found a match for the item name. ! 1596: ** now we must check if the OLE object is running. ! 1597: ** we will load the object if not already loaded. ! 1598: */ ! 1599: if (! lpContainerLine->m_lpOleObj) { ! 1600: ContainerLine_LoadOleObject(lpContainerLine); ! 1601: if (! lpContainerLine->m_lpOleObj) ! 1602: return ResultFromScode(E_OUTOFMEMORY); ! 1603: } ! 1604: ! 1605: /* OLE2NOTE: check if the object is allowed to be linked ! 1606: ** to from the inside (ie. we are allowed to ! 1607: ** give out a moniker which binds to the running ! 1608: ** OLE object). if the object is an OLE ! 1609: ** 2.0 embedded object then it is allowed to be ! 1610: ** linked to from the inside. if the object is ! 1611: ** either an OleLink or an OLE 1.0 embedding ! 1612: ** then it can not be linked to from the inside. ! 1613: ** if we were a container/server app then we ! 1614: ** could offer linking to the outside of the ! 1615: ** object (ie. a pseudo object within our ! 1616: ** document). we are a container only app that ! 1617: ** does not support linking to ranges of its data. ! 1618: */ ! 1619: OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") ! 1620: lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( ! 1621: lpContainerLine->m_lpOleObj, ! 1622: DVASPECT_CONTENT, /* aspect is not important */ ! 1623: (LPDWORD)&dwStatus ! 1624: ); ! 1625: OLEDBG_END2 ! 1626: if (dwStatus & OLEMISC_CANTLINKINSIDE) ! 1627: return ResultFromScode(MK_E_NOOBJECT); ! 1628: ! 1629: if (OleIsRunning(lpContainerLine->m_lpOleObj)) ! 1630: return NOERROR; ! 1631: else ! 1632: return ResultFromScode(S_FALSE); ! 1633: } ! 1634: } ! 1635: } ! 1636: ! 1637: // no object was found corresponding to the item name ! 1638: return ResultFromScode(MK_E_NOOBJECT); ! 1639: } ! 1640: ! 1641: #endif // OLE_CNTR
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.