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