Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2018 lines
57 KiB

  1. /*************************************************************************
  2. **
  3. ** OLE 2 Server Sample Code
  4. **
  5. ** svrbase.c
  6. **
  7. ** This file contains all interfaces, methods and related support
  8. ** functions for the basic OLE Object (Server) application. The
  9. ** basic OLE Object application supports embedding an object and
  10. ** linking to a file-based or embedded object as a whole. The basic
  11. ** Object application includes the following implementation objects:
  12. **
  13. ** ClassFactory (aka. ClassObject) Object (see file classfac.c)
  14. ** exposed interfaces:
  15. ** IClassFactory interface
  16. **
  17. ** ServerDoc Object
  18. ** exposed interfaces:
  19. ** IUnknown
  20. ** IOleObject interface
  21. ** IPersistStorage interface
  22. ** IDataObject interface
  23. **
  24. ** ServerApp Object
  25. ** exposed interfaces:
  26. ** IUnknown
  27. **
  28. ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
  29. **
  30. *************************************************************************/
  31. #include "outline.h"
  32. OLEDBGDATA
  33. extern LPOUTLINEAPP g_lpApp;
  34. extern IOleObjectVtbl g_SvrDoc_OleObjectVtbl;
  35. extern IPersistStorageVtbl g_SvrDoc_PersistStorageVtbl;
  36. #if defined( INPLACE_SVR )
  37. extern IOleInPlaceObjectVtbl g_SvrDoc_OleInPlaceObjectVtbl;
  38. extern IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl;
  39. #endif // INPLACE_SVR
  40. #if defined( SVR_TREATAS )
  41. extern IStdMarshalInfoVtbl g_SvrDoc_StdMarshalInfoVtbl;
  42. #endif // SVR_TREATAS
  43. // REVIEW: should use string resource for messages
  44. extern char ErrMsgSaving[];
  45. extern char ErrMsgFormatNotSupported[];
  46. static char ErrMsgPSSaveFail[] = "PSSave failed";
  47. static char ErrMsgLowMemNClose[] = "Warning OUT OF MEMORY! We must close down";
  48. extern char g_szUpdateCntrDoc[] = "&Update %s";
  49. extern char g_szExitNReturnToCntrDoc[] = "E&xit && Return to %s";
  50. /*************************************************************************
  51. ** ServerDoc::IOleObject interface implementation
  52. *************************************************************************/
  53. // IOleObject::QueryInterface method
  54. STDMETHODIMP SvrDoc_OleObj_QueryInterface(
  55. LPOLEOBJECT lpThis,
  56. REFIID riid,
  57. LPVOID FAR* lplpvObj
  58. )
  59. {
  60. LPSERVERDOC lpServerDoc =
  61. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  62. return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  63. }
  64. // IOleObject::AddRef method
  65. STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis)
  66. {
  67. LPSERVERDOC lpServerDoc =
  68. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  69. OleDbgAddRefMethod(lpThis, "IOleObject");
  70. return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  71. }
  72. // IOleObject::Release method
  73. STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis)
  74. {
  75. LPSERVERDOC lpServerDoc =
  76. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  77. OleDbgReleaseMethod(lpThis, "IOleObject");
  78. return OleDoc_Release((LPOLEDOC)lpServerDoc);
  79. }
  80. // IOleObject::SetClientSite method
  81. STDMETHODIMP SvrDoc_OleObj_SetClientSite(
  82. LPOLEOBJECT lpThis,
  83. LPOLECLIENTSITE lpclientSite
  84. )
  85. {
  86. LPSERVERDOC lpServerDoc =
  87. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  88. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  89. OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSite\r\n")
  90. // SetClientSite is only valid to call on an embedded object
  91. if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
  92. OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED);
  93. OLEDBG_END2
  94. return ResultFromScode(E_UNEXPECTED);
  95. }
  96. /* if we currently have a client site ptr, then release it. */
  97. if (lpServerDoc->m_lpOleClientSite)
  98. OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);
  99. lpServerDoc->m_lpOleClientSite = (LPOLECLIENTSITE) lpclientSite;
  100. // OLE2NOTE: to be able to hold onto clientSite pointer, we must AddRef it
  101. if (lpclientSite)
  102. lpclientSite->lpVtbl->AddRef(lpclientSite);
  103. OLEDBG_END2
  104. return NOERROR;
  105. }
  106. // IOleObject::GetClientSite method
  107. STDMETHODIMP SvrDoc_OleObj_GetClientSite(
  108. LPOLEOBJECT lpThis,
  109. LPOLECLIENTSITE FAR* lplpClientSite
  110. )
  111. {
  112. LPSERVERDOC lpServerDoc =
  113. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  114. OleDbgOut2("SvrDoc_OleObj_GetClientSite\r\n");
  115. /* OLE2NOTE: we MUST AddRef this interface pointer to give the
  116. ** caller a personal copy of the pointer
  117. */
  118. lpServerDoc->m_lpOleClientSite->lpVtbl->AddRef(
  119. lpServerDoc->m_lpOleClientSite
  120. );
  121. *lplpClientSite = lpServerDoc->m_lpOleClientSite;
  122. return NOERROR;
  123. }
  124. // IOleObject::SetHostNames method
  125. STDMETHODIMP SvrDoc_OleObj_SetHostNamesA(
  126. LPOLEOBJECT lpThis,
  127. LPCSTR szContainerApp,
  128. LPCSTR szContainerObj
  129. )
  130. {
  131. LPSERVERDOC lpServerDoc =
  132. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  133. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  134. OleDbgOut2("SvrDoc_OleObj_SetHostNames\r\n");
  135. LSTRCPYN((LPSTR)lpServerDoc->m_szContainerApp, szContainerApp,
  136. sizeof(lpServerDoc->m_szContainerApp));
  137. LSTRCPYN((LPSTR)lpServerDoc->m_szContainerObj, szContainerObj,
  138. sizeof(lpServerDoc->m_szContainerObj));
  139. /* The Window title for an embedded object is constructed as
  140. ** follows:
  141. ** <server app name> - <obj short type> in <cont. doc name>
  142. **
  143. ** here we construct the current document title portion of the
  144. ** name which follows the '-'. OutlineDoc_SetTitle prepends the
  145. ** "<server app name> - " to the document title.
  146. */
  147. // REVIEW: this string should be loaded from string resource
  148. wsprintf(lpOutlineDoc->m_szFileName, "%s in %s",
  149. (LPSTR)SHORTUSERTYPENAME, (LPSTR)lpServerDoc->m_szContainerObj);
  150. lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  151. OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  152. /* OLE2NOTE: update the application menus correctly for an embedded
  153. ** object. the changes include:
  154. ** 1 Remove File/New and File/Open (SDI ONLY)
  155. ** 2 Change File/Save As.. to File/Save Copy As..
  156. ** 3 Change File menu so it contains "Update" instead of "Save"
  157. ** 4 Change File/Exit to File/Exit & Return to <client doc>"
  158. */
  159. ServerDoc_UpdateMenu(lpServerDoc);
  160. return NOERROR;
  161. }
  162. STDMETHODIMP SvrDoc_OleObj_SetHostNames(
  163. LPOLEOBJECT lpThis,
  164. LPCOLESTR szContainerApp,
  165. LPCOLESTR szContainerObj
  166. )
  167. {
  168. CREATESTR(pstrApp, szContainerApp)
  169. CREATESTR(pstrObj, szContainerObj)
  170. HRESULT hr = SvrDoc_OleObj_SetHostNamesA(lpThis, pstrApp, pstrObj);
  171. FREESTR(pstrApp)
  172. FREESTR(pstrObj)
  173. return hr;
  174. }
  175. // IOleObject::Close method
  176. STDMETHODIMP SvrDoc_OleObj_Close(
  177. LPOLEOBJECT lpThis,
  178. DWORD dwSaveOption
  179. )
  180. {
  181. LPSERVERDOC lpServerDoc =
  182. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  183. BOOL fStatus;
  184. OLEDBG_BEGIN2("SvrDoc_OleObj_Close\r\n")
  185. /* OLE2NOTE: the OLE 2.0 user model is that embedded objects should
  186. ** always be saved when closed WITHOUT any prompting to the
  187. ** user. this is the recommendation irregardless of whether the
  188. ** object is activated in-place or open in its own window.
  189. ** this is a CHANGE from the OLE 1.0 user model where it
  190. ** was the guideline that servers always prompt to save changes.
  191. ** thus OLE 2.0 compound document oriented container's should
  192. ** always pass dwSaveOption==OLECLOSE_SAVEIFDIRTY. it is
  193. ** possible that for programmatic uses a container may want to
  194. ** specify a different dwSaveOption. the implementation of
  195. ** various save options can be tricky, particularly considering
  196. ** cases involving in-place activation. the following would be
  197. ** reasonable behavior:
  198. **
  199. ** (1) OLECLOSE_SAVEIFDIRTY: if dirty, save. close.
  200. ** (2) OLECLOSE_NOSAVE: close.
  201. ** (3) OLECLOSE_PROMPTSAVE:
  202. ** (a) object visible, but not in-place:
  203. ** if not dirty, close.
  204. ** switch(prompt)
  205. ** case IDYES: save. close.
  206. ** case IDNO: close.
  207. ** case IDCANCEL: return OLE_E_PROMPTSAVECANCELLED
  208. ** (b) object invisible (includes UIDeactivated object)
  209. ** if dirty, save. close.
  210. ** NOTE: NO PROMPT. it is not appropriate to prompt
  211. ** if the object is not visible.
  212. ** (c) object is in-place active:
  213. ** if dirty, save. close.
  214. ** NOTE: NO PROMPT. it is not appropriate to prompt
  215. ** if the object is active in-place.
  216. */
  217. fStatus = OutlineDoc_Close((LPOUTLINEDOC)lpServerDoc, dwSaveOption);
  218. OleDbgAssertSz(fStatus == TRUE, "SvrDoc_OleObj_Close failed\r\n");
  219. OLEDBG_END2
  220. return (fStatus ? NOERROR : ResultFromScode(E_FAIL));
  221. }
  222. // IOleObject::SetMoniker method
  223. STDMETHODIMP SvrDoc_OleObj_SetMoniker(
  224. LPOLEOBJECT lpThis,
  225. DWORD dwWhichMoniker,
  226. LPMONIKER lpmk
  227. )
  228. {
  229. LPSERVERDOC lpServerDoc =
  230. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  231. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  232. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  233. LPMONIKER lpmkFull = NULL;
  234. HRESULT hrErr;
  235. SCODE sc;
  236. OLEDBG_BEGIN2("SvrDoc_OleObj_SetMoniker\r\n")
  237. /* OLE2NOTE: if our full moniker is passed then we can use it,
  238. ** otherwise we must call back to our ClientSite to get our full
  239. ** moniker.
  240. */
  241. if (dwWhichMoniker == OLEWHICHMK_OBJFULL) {
  242. /* Register the document as running with the new moniker and
  243. ** notify any clients that our moniker has changed.
  244. */
  245. OleDoc_DocRenamedUpdate(lpOleDoc, lpmk);
  246. if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
  247. IBindCtx FAR *pbc = NULL;
  248. LPSTR lpszName = NULL;
  249. /* OLE2NOTE: if this is a FILE-based or untitled document
  250. ** then we should accept this new moniker as our document's
  251. ** moniker. we will remember this moniker instead of the
  252. ** FileMoniker that we have by default. this allows
  253. ** systems that use special monikers to track the
  254. ** location of documents to inform a document that is a
  255. ** link source of its special moniker. this enables the
  256. ** document to use this special moniker when building
  257. ** composite monikers to identify contained objects and
  258. ** pseudo objects (ranges).
  259. **
  260. ** we should also use the DisplayName form of this
  261. ** moniker as our document name in our window title.
  262. */
  263. if (lpOleDoc->m_lpFileMoniker) {
  264. lpOleDoc->m_lpFileMoniker->lpVtbl->Release(
  265. lpOleDoc->m_lpFileMoniker);
  266. }
  267. lpOleDoc->m_lpFileMoniker = lpmk;
  268. // we must AddRef the moniker to hold on to it
  269. lpmk->lpVtbl->AddRef(lpmk);
  270. /* we should also use the DisplayName form of this
  271. ** moniker as our document name in our window title.
  272. */
  273. CreateBindCtx(0, (LPBC FAR*)&pbc);
  274. CallIMonikerGetDisplayNameA(lpmk,pbc,NULL,&lpszName);
  275. pbc->lpVtbl->Release(pbc);
  276. if (lpszName) {
  277. LSTRCPYN(lpOutlineDoc->m_szFileName, lpszName,
  278. sizeof(lpOutlineDoc->m_szFileName));
  279. lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  280. OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  281. OleStdFreeString(lpszName, NULL);
  282. }
  283. }
  284. OLEDBG_END2
  285. return NOERROR;
  286. }
  287. /* if the passed moniker was NOT a full moniker then we must call
  288. ** back to our ClientSite to get our full moniker. this is
  289. ** needed in order to register in the RunningObjectTable. if we
  290. ** don't have a ClientSite then this is an error.
  291. */
  292. if (lpServerDoc->m_lpOleClientSite == NULL) {
  293. sc = E_FAIL;
  294. goto error;
  295. }
  296. hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
  297. lpServerDoc->m_lpOleClientSite,
  298. OLEGETMONIKER_ONLYIFTHERE,
  299. OLEWHICHMK_OBJFULL,
  300. &lpmkFull
  301. );
  302. if (hrErr != NOERROR) {
  303. sc = GetScode(hrErr);
  304. goto error;
  305. }
  306. /* Register the document as running with the new moniker and
  307. ** notify any clients that our moniker has changed.
  308. */
  309. OleDoc_DocRenamedUpdate(lpOleDoc, lpmkFull);
  310. if (lpmkFull)
  311. OleStdRelease((LPUNKNOWN)lpmkFull);
  312. OLEDBG_END2
  313. return NOERROR;
  314. error:
  315. OLEDBG_END2
  316. return ResultFromScode(sc);
  317. }
  318. // IOleObject::GetMoniker method
  319. STDMETHODIMP SvrDoc_OleObj_GetMoniker(
  320. LPOLEOBJECT lpThis,
  321. DWORD dwAssign,
  322. DWORD dwWhichMoniker,
  323. LPMONIKER FAR* lplpmk
  324. )
  325. {
  326. LPSERVERDOC lpServerDoc =
  327. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  328. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  329. SCODE sc;
  330. OLEDBG_BEGIN2("SvrDoc_OleObj_GetMoniker\r\n")
  331. /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
  332. *lplpmk = NULL;
  333. if (lpServerDoc->m_lpOleClientSite) {
  334. /* document is an embedded object. retrieve our moniker from
  335. ** our container.
  336. */
  337. OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n")
  338. sc = GetScode( lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
  339. lpServerDoc->m_lpOleClientSite,
  340. dwAssign,
  341. dwWhichMoniker,
  342. lplpmk
  343. ) );
  344. OLEDBG_END2
  345. } else if (lpOleDoc->m_lpFileMoniker) {
  346. /* document is a top-level user document (either
  347. ** file-based or untitled). return the FileMoniker stored
  348. ** with the document; it uniquely identifies the document.
  349. */
  350. if (dwWhichMoniker == OLEWHICHMK_CONTAINER)
  351. sc = E_INVALIDARG; // file-based object has no CONTAINER moniker
  352. else {
  353. *lplpmk = lpOleDoc->m_lpFileMoniker;
  354. (*lplpmk)->lpVtbl->AddRef(*lplpmk); // must AddRef to pass out ptr
  355. sc = S_OK;
  356. }
  357. } else {
  358. // document is not yet fully initialized => no moniker
  359. sc = E_FAIL;
  360. }
  361. OLEDBG_END2
  362. return ResultFromScode(sc);
  363. }
  364. // IOleObject::InitFromData method
  365. STDMETHODIMP SvrDoc_OleObj_InitFromData(
  366. LPOLEOBJECT lpThis,
  367. LPDATAOBJECT lpDataObject,
  368. BOOL fCreation,
  369. DWORD reserved
  370. )
  371. {
  372. LPSERVERDOC lpServerDoc =
  373. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  374. OLEDBG_BEGIN2("SvrDoc_OleObj_InitFromData\r\n")
  375. // REVIEW: NOT YET IMPLEMENTED
  376. OLEDBG_END2
  377. return ResultFromScode(E_NOTIMPL);
  378. }
  379. // IOleObject::GetClipboardData method
  380. STDMETHODIMP SvrDoc_OleObj_GetClipboardData(
  381. LPOLEOBJECT lpThis,
  382. DWORD reserved,
  383. LPDATAOBJECT FAR* lplpDataObject
  384. )
  385. {
  386. LPSERVERDOC lpServerDoc =
  387. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  388. OLEDBG_BEGIN2("SvrDoc_OleObj_GetClipboardData\r\n")
  389. // REVIEW: NOT YET IMPLEMENTED
  390. OLEDBG_END2
  391. return ResultFromScode(E_NOTIMPL);
  392. }
  393. // IOleObject::DoVerb method
  394. STDMETHODIMP SvrDoc_OleObj_DoVerb(
  395. LPOLEOBJECT lpThis,
  396. LONG lVerb,
  397. LPMSG lpmsg,
  398. LPOLECLIENTSITE lpActiveSite,
  399. LONG lindex,
  400. HWND hwndParent,
  401. LPCRECT lprcPosRect
  402. )
  403. {
  404. LPSERVERDOC lpServerDoc =
  405. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  406. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  407. SCODE sc = S_OK;
  408. OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerb\r\n")
  409. switch (lVerb) {
  410. default:
  411. /* OLE2NOTE: when an unknown verb number is given, the
  412. ** server must take careful action:
  413. ** 1. if it is one of the specially defined OLEIVERB
  414. ** (negative numbered) verbs, the app should return an
  415. ** error (E_NOTIMPL) and perform no action.
  416. **
  417. ** 2. if the verb is a application specific verb
  418. ** (positive numbered verb), then the app should
  419. ** return the special scode (OLEOBJ_S_INVALIDVERB). BUT,
  420. ** we should still perform our normal primary verb action.
  421. */
  422. if (lVerb < 0) {
  423. OLEDBG_END2
  424. return ResultFromScode(E_NOTIMPL);
  425. } else {
  426. sc = OLEOBJ_S_INVALIDVERB;
  427. }
  428. // deliberatly fall through to Primary Verb
  429. #if !defined( INPLACE_SVR )
  430. case 0:
  431. case OLEIVERB_SHOW:
  432. case OLEIVERB_OPEN:
  433. OutlineDoc_ShowWindow(lpOutlineDoc);
  434. break;
  435. case OLEIVERB_HIDE:
  436. OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
  437. break;
  438. #endif // ! INPLACE_SVR
  439. #if defined( INPLACE_SVR )
  440. case 0:
  441. case OLEIVERB_SHOW:
  442. /* OLE2NOTE: if our window is already open (visible) then
  443. ** we should simply surface the open window. if not,
  444. ** then we can do our primary action of in-place
  445. ** activation.
  446. */
  447. if ( lpServerDoc->m_lpOleClientSite
  448. && ! (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
  449. ! lpServerDoc->m_fInPlaceActive) ) {
  450. ServerDoc_DoInPlaceActivate(
  451. lpServerDoc, lVerb, lpmsg, lpActiveSite);
  452. }
  453. OutlineDoc_ShowWindow(lpOutlineDoc);
  454. break;
  455. case 1:
  456. case OLEIVERB_OPEN:
  457. ServerDoc_DoInPlaceDeactivate(lpServerDoc);
  458. OutlineDoc_ShowWindow(lpOutlineDoc);
  459. break;
  460. case OLEIVERB_HIDE:
  461. if (lpServerDoc->m_fInPlaceActive) {
  462. SvrDoc_IPObj_UIDeactivate(
  463. (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);
  464. #if defined( SVR_INSIDEOUT )
  465. /* OLE2NOTE: an inside-out style in-place server will
  466. ** NOT hide its window in UIDeactive (an outside-in
  467. ** style object will hide its window in
  468. ** UIDeactivate). thus we need to explicitly hide
  469. ** our window now.
  470. */
  471. ServerDoc_DoInPlaceHide(lpServerDoc);
  472. #endif // INSIEDOUT
  473. } else {
  474. OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
  475. }
  476. break;
  477. case OLEIVERB_UIACTIVATE:
  478. #if defined( SVR_INSIDEOUT )
  479. /* OLE2NOTE: only an inside-out style object supports
  480. ** INPLACEACTIVATE verb
  481. */
  482. case OLEIVERB_INPLACEACTIVATE:
  483. #endif // SVR_INSIDEOUT
  484. /* OLE2NOTE: if our window is already open (visible) then
  485. ** we can NOT activate in-place.
  486. */
  487. if (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
  488. ! lpServerDoc->m_fInPlaceActive ) {
  489. sc = OLE_E_NOT_INPLACEACTIVE;
  490. } else {
  491. sc = GetScode( ServerDoc_DoInPlaceActivate(
  492. lpServerDoc, lVerb, lpmsg, lpActiveSite) );
  493. if (SUCCEEDED(sc))
  494. OutlineDoc_ShowWindow(lpOutlineDoc);
  495. }
  496. break;
  497. #endif // INPLACE_SVR
  498. }
  499. OLEDBG_END2
  500. return ResultFromScode(sc);
  501. }
  502. // IOleObject::EnumVerbs method
  503. STDMETHODIMP SvrDoc_OleObj_EnumVerbs(
  504. LPOLEOBJECT lpThis,
  505. LPENUMOLEVERB FAR* lplpenumOleVerb
  506. )
  507. {
  508. OleDbgOut2("SvrDoc_OleObj_EnumVerbs\r\n");
  509. /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
  510. *lplpenumOleVerb = NULL;
  511. /* An object implemented as a server EXE (as this sample
  512. ** is) may simply return OLE_S_USEREG to instruct the OLE
  513. ** DefHandler to call the OleReg* helper API which uses info in
  514. ** the registration database. Alternatively, the OleRegEnumVerbs
  515. ** API may be called directly. Objects implemented as a server
  516. ** DLL may NOT return OLE_S_USEREG; they must call the OleReg*
  517. ** API or provide their own implementation. For EXE based
  518. ** objects it is more efficient to return OLE_S_USEREG, because
  519. ** in then the verb enumerator is instantiated in the callers
  520. ** process space and no LRPC remoting is required.
  521. */
  522. return ResultFromScode(OLE_S_USEREG);
  523. }
  524. // IOleObject::Update method
  525. STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis)
  526. {
  527. OleDbgOut2("SvrDoc_OleObj_Update\r\n");
  528. /* OLE2NOTE: a server-only app is always "up-to-date".
  529. ** a container-app which contains links where the link source
  530. ** has changed since the last update of the link would be
  531. ** considered "out-of-date". the "Update" method instructs the
  532. ** object to get an update from any out-of-date links.
  533. */
  534. return NOERROR;
  535. }
  536. // IOleObject::IsUpToDate method
  537. STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis)
  538. {
  539. OleDbgOut2("SvrDoc_OleObj_IsUpToDate\r\n");
  540. /* OLE2NOTE: a server-only app is always "up-to-date".
  541. ** a container-app which contains links where the link source
  542. ** has changed since the last update of the link would be
  543. ** considered "out-of-date".
  544. */
  545. return NOERROR;
  546. }
  547. // IOleObject::GetUserClassID method
  548. STDMETHODIMP SvrDoc_OleObj_GetUserClassID(
  549. LPOLEOBJECT lpThis,
  550. LPCLSID lpClassID
  551. )
  552. {
  553. LPSERVERDOC lpServerDoc =
  554. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  555. OleDbgOut2("SvrDoc_OleObj_GetClassID\r\n");
  556. /* OLE2NOTE: we must be carefull to return the correct CLSID here.
  557. ** if we are currently preforming a "TreatAs (aka. ActivateAs)"
  558. ** operation then we need to return the class of the object
  559. ** written in the storage of the object. otherwise we would
  560. ** return our own class id.
  561. */
  562. return ServerDoc_GetClassID(lpServerDoc, lpClassID);
  563. }
  564. // IOleObject::GetUserType method
  565. STDMETHODIMP SvrDoc_OleObj_GetUserTypeA(
  566. LPOLEOBJECT lpThis,
  567. DWORD dwFormOfType,
  568. LPSTR FAR* lpszUserType
  569. )
  570. {
  571. LPSERVERDOC lpServerDoc =
  572. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  573. OleDbgOut2("SvrDoc_OleObj_GetUserType\r\n");
  574. /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
  575. *lpszUserType = NULL;
  576. /* OLE2NOTE: we must be carefull to return the correct user type here.
  577. ** if we are currently preforming a "TreatAs (aka. ActivateAs)"
  578. ** operation then we need to return the user type name that
  579. ** corresponds to the class of the object we are currently
  580. ** emmulating. otherwise we should return our normal user type
  581. ** name corresponding to our own class. This routine determines
  582. ** the current clsid in effect.
  583. **
  584. ** An object implemented as a server EXE (as this sample
  585. ** is) may simply return OLE_S_USEREG to instruct the OLE
  586. ** DefHandler to call the OleReg* helper API which uses info in
  587. ** the registration database. Alternatively, the OleRegGetUserType
  588. ** API may be called directly. Objects implemented as a server
  589. ** DLL may NOT return OLE_S_USEREG; they must call the OleReg*
  590. ** API or provide their own implementation. For EXE based
  591. ** objects it is more efficient to return OLE_S_USEREG, because
  592. ** in then the return string is instantiated in the callers
  593. ** process space and no LRPC remoting is required.
  594. */
  595. #if defined( SVR_TREATAS )
  596. if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )
  597. return OleRegGetUserTypeA(
  598. &lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);
  599. else
  600. #endif // SVR_TREATAS
  601. return ResultFromScode(OLE_S_USEREG);
  602. }
  603. STDMETHODIMP SvrDoc_OleObj_GetUserType(
  604. LPOLEOBJECT lpThis,
  605. DWORD dwFormOfType,
  606. LPOLESTR FAR* lpszUserType
  607. )
  608. {
  609. LPSTR pstr;
  610. HRESULT hr = SvrDoc_OleObj_GetUserTypeA(lpThis, dwFormOfType, &pstr);
  611. CopyAndFreeSTR(pstr, lpszUserType);
  612. return hr;
  613. }
  614. // IOleObject::SetExtent method
  615. STDMETHODIMP SvrDoc_OleObj_SetExtent(
  616. LPOLEOBJECT lpThis,
  617. DWORD dwDrawAspect,
  618. LPSIZEL lplgrc
  619. )
  620. {
  621. OleDbgOut2("SvrDoc_OleObj_SetExtent\r\n");
  622. /* SVROUTL does NOT allow the object's size to be set by its
  623. ** container. the size of the ServerDoc object is determined by
  624. ** the data contained within the document.
  625. */
  626. return ResultFromScode(E_FAIL);
  627. }
  628. // IOleObject::GetExtent method
  629. STDMETHODIMP SvrDoc_OleObj_GetExtent(
  630. LPOLEOBJECT lpThis,
  631. DWORD dwDrawAspect,
  632. LPSIZEL lpsizel
  633. )
  634. {
  635. LPOLEDOC lpOleDoc =
  636. (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  637. OleDbgOut2("SvrDoc_OleObj_GetExtent\r\n");
  638. /* OLE2NOTE: it is VERY important to check which aspect the caller
  639. ** is asking about. an object implemented by a server EXE MAY
  640. ** fail to return extents when asked for DVASPECT_ICON.
  641. */
  642. if (dwDrawAspect == DVASPECT_CONTENT) {
  643. OleDoc_GetExtent(lpOleDoc, lpsizel);
  644. return NOERROR;
  645. }
  646. #if defined( LATER )
  647. else if (dwDrawAspect == DVASPECT_THUMBNAIL)
  648. {
  649. /* as our thumbnail we will render only the first page of the
  650. ** document. calculate extents of our thumbnail rendering.
  651. **
  652. ** OLE2NOTE: thumbnails are most often used by applications in
  653. ** FindFile or FileOpen type dialogs to give the user a
  654. ** quick view of the contents of the file or object.
  655. */
  656. OleDoc_GetThumbnailExtent(lpOleDoc, lpsizel);
  657. return NOERROR;
  658. }
  659. #endif
  660. else
  661. {
  662. return ResultFromScode(E_FAIL);
  663. }
  664. }
  665. // IOleObject::Advise method
  666. STDMETHODIMP SvrDoc_OleObj_Advise(
  667. LPOLEOBJECT lpThis,
  668. LPADVISESINK lpAdvSink,
  669. LPDWORD lpdwConnection
  670. )
  671. {
  672. LPSERVERDOC lpServerDoc =
  673. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  674. HRESULT hrErr;
  675. SCODE sc;
  676. OLEDBG_BEGIN2("SvrDoc_OleObj_Advise\r\n");
  677. if (lpServerDoc->m_OleDoc.m_fObjIsClosing)
  678. {
  679. // We don't accept any more Advise's once we're closing
  680. sc = OLE_E_ADVISENOTSUPPORTED;
  681. goto error;
  682. }
  683. if (lpServerDoc->m_lpOleAdviseHldr == NULL &&
  684. CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) {
  685. sc = E_OUTOFMEMORY;
  686. goto error;
  687. }
  688. OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")
  689. hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise(
  690. lpServerDoc->m_lpOleAdviseHldr,
  691. lpAdvSink,
  692. lpdwConnection
  693. );
  694. OLEDBG_END2
  695. OLEDBG_END2
  696. return hrErr;
  697. error:
  698. OLEDBG_END2
  699. *lpdwConnection = 0;
  700. return ResultFromScode(sc);
  701. }
  702. // IOleObject::Unadvise method
  703. STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)
  704. {
  705. LPSERVERDOC lpServerDoc =
  706. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  707. HRESULT hrErr;
  708. SCODE sc;
  709. OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvise\r\n");
  710. if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
  711. sc = E_FAIL;
  712. goto error;
  713. }
  714. OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n")
  715. hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise(
  716. lpServerDoc->m_lpOleAdviseHldr,
  717. dwConnection
  718. );
  719. OLEDBG_END2
  720. OLEDBG_END2
  721. return hrErr;
  722. error:
  723. OLEDBG_END2
  724. return ResultFromScode(sc);
  725. }
  726. // IOleObject::EnumAdvise method
  727. STDMETHODIMP SvrDoc_OleObj_EnumAdvise(
  728. LPOLEOBJECT lpThis,
  729. LPENUMSTATDATA FAR* lplpenumAdvise
  730. )
  731. {
  732. LPSERVERDOC lpServerDoc =
  733. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  734. HRESULT hrErr;
  735. SCODE sc;
  736. OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvise\r\n");
  737. /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
  738. *lplpenumAdvise = NULL;
  739. if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
  740. sc = E_FAIL;
  741. goto error;
  742. }
  743. OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")
  744. hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(
  745. lpServerDoc->m_lpOleAdviseHldr,
  746. lplpenumAdvise
  747. );
  748. OLEDBG_END2
  749. OLEDBG_END2
  750. return hrErr;
  751. error:
  752. OLEDBG_END2
  753. return ResultFromScode(sc);
  754. }
  755. // IOleObject::GetMiscStatus method
  756. STDMETHODIMP SvrDoc_OleObj_GetMiscStatus(
  757. LPOLEOBJECT lpThis,
  758. DWORD dwAspect,
  759. DWORD FAR* lpdwStatus
  760. )
  761. {
  762. LPSERVERDOC lpServerDoc =
  763. ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  764. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  765. OleDbgOut2("SvrDoc_OleObj_GetMiscStatus\r\n");
  766. /* Get our default MiscStatus for the given Aspect. this
  767. ** information is registered in the RegDB. We query the RegDB
  768. ** here to guarantee that the value returned from this method
  769. ** agrees with the values in RegDB. in this way we only have to
  770. ** maintain the info in one place (in the RegDB). Alternatively
  771. ** we could have the values hard coded here.
  772. */
  773. OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);
  774. /* OLE2NOTE: check if the data copied is compatible to be
  775. ** linked by an OLE 1.0 container. it is compatible if
  776. ** either the data is an untitled document, a file, or a
  777. ** selection of data within a file. if the data is part of
  778. ** an embedded object, then it is NOT compatible to be
  779. ** linked by an OLE 1.0 container. if it is compatible then
  780. ** we must include OLEMISC_CANLINKBYOLE1 as part of the
  781. ** dwStatus flags transfered via CF_OBJECTDESCRIPTOR or
  782. ** CF_LINKSRCDESCRIPTOR.
  783. */
  784. if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW ||
  785. lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE)
  786. *lpdwStatus |= OLEMISC_CANLINKBYOLE1;
  787. #if defined( INPLACE_SVR )
  788. if (dwAspect == DVASPECT_CONTENT)
  789. *lpdwStatus |= (OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE);
  790. #endif // INPLACE_SVR
  791. return NOERROR;
  792. }
  793. // IOleObject::SetColorScheme method
  794. STDMETHODIMP SvrDoc_OleObj_SetColorScheme(
  795. LPOLEOBJECT lpThis,
  796. LPLOGPALETTE lpLogpal
  797. )
  798. {
  799. OleDbgOut2("SvrDoc_OleObj_SetColorScheme\r\n");
  800. // REVIEW: NOT YET IMPLEMENTED
  801. return ResultFromScode(E_NOTIMPL);
  802. }
  803. /*************************************************************************
  804. ** ServerDoc::IPersistStorage interface implementation
  805. *************************************************************************/
  806. // IPersistStorage::QueryInterface method
  807. STDMETHODIMP SvrDoc_PStg_QueryInterface(
  808. LPPERSISTSTORAGE lpThis,
  809. REFIID riid,
  810. LPVOID FAR* lplpvObj
  811. )
  812. {
  813. LPSERVERDOC lpServerDoc =
  814. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  815. return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  816. }
  817. // IPersistStorage::AddRef method
  818. STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis)
  819. {
  820. LPSERVERDOC lpServerDoc =
  821. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  822. OleDbgAddRefMethod(lpThis, "IPersistStorage");
  823. return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  824. }
  825. // IPersistStorage::Release method
  826. STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis)
  827. {
  828. LPSERVERDOC lpServerDoc =
  829. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  830. OleDbgReleaseMethod(lpThis, "IPersistStorage");
  831. return OleDoc_Release((LPOLEDOC)lpServerDoc);
  832. }
  833. // IPersistStorage::GetClassID method
  834. STDMETHODIMP SvrDoc_PStg_GetClassID(
  835. LPPERSISTSTORAGE lpThis,
  836. LPCLSID lpClassID
  837. )
  838. {
  839. LPSERVERDOC lpServerDoc =
  840. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  841. OleDbgOut2("SvrDoc_PStg_GetClassID\r\n");
  842. /* OLE2NOTE: we must be carefull to return the correct CLSID here.
  843. ** if we are currently preforming a "TreatAs (aka. ActivateAs)"
  844. ** operation then we need to return the class of the object
  845. ** written in the storage of the object. otherwise we would
  846. ** return our own class id.
  847. */
  848. return ServerDoc_GetClassID(lpServerDoc, lpClassID);
  849. }
  850. // IPersistStorage::IsDirty method
  851. STDMETHODIMP SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE lpThis)
  852. {
  853. LPSERVERDOC lpServerDoc =
  854. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  855. OleDbgOut2("SvrDoc_PStg_IsDirty\r\n");
  856. if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc))
  857. return NOERROR;
  858. else
  859. return ResultFromScode(S_FALSE);
  860. }
  861. // IPersistStorage::InitNew method
  862. STDMETHODIMP SvrDoc_PStg_InitNew(
  863. LPPERSISTSTORAGE lpThis,
  864. LPSTORAGE lpStg
  865. )
  866. {
  867. LPSERVERDOC lpServerDoc =
  868. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  869. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  870. LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  871. LPSTR lpszUserType = (LPSTR)FULLUSERTYPENAME;
  872. HRESULT hrErr;
  873. SCODE sc;
  874. OLEDBG_BEGIN2("SvrDoc_PStg_InitNew\r\n")
  875. #if defined( SVR_TREATAS )
  876. {
  877. LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  878. CLSID clsid;
  879. CLIPFORMAT cfFmt;
  880. LPSTR lpszType;
  881. /* OLE2NOTE: if the Server is capable of supporting "TreatAs"
  882. ** (aka. ActivateAs), it must read the class that is written
  883. ** into the storage. if this class is NOT the app's own
  884. ** class ID, then this is a TreatAs operation. the server
  885. ** then must faithfully pretend to be the class that is
  886. ** written into the storage. it must also faithfully write
  887. ** the data back to the storage in the SAME format as is
  888. ** written in the storage.
  889. **
  890. ** SVROUTL and ISVROTL can emulate each other. they have the
  891. ** simplification that they both read/write the identical
  892. ** format. thus for these apps no actual conversion of the
  893. ** native bits is actually required.
  894. */
  895. lpServerDoc->m_clsidTreatAs = CLSID_NULL;
  896. if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpStg, &clsid,
  897. (CLIPFORMAT FAR*)&cfFmt, (LPSTR FAR*)&lpszType)) {
  898. if (cfFmt == lpOutlineApp->m_cfOutline) {
  899. // We should perform TreatAs operation
  900. if (lpServerDoc->m_lpszTreatAsType)
  901. OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);
  902. lpServerDoc->m_clsidTreatAs = clsid;
  903. ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt;
  904. lpServerDoc->m_lpszTreatAsType = lpszType;
  905. lpszUserType = lpServerDoc->m_lpszTreatAsType;
  906. OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '");
  907. OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);
  908. OleDbgOutNoPrefix3("'\r\n");
  909. } else {
  910. // ERROR: we ONLY support TreatAs for CF_OUTLINE format
  911. OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n");
  912. OleStdFreeString(lpszType, NULL);
  913. }
  914. }
  915. }
  916. #endif // SVR_TREATAS
  917. /* OLE2NOTE: a server EXE object should write its format tag to its
  918. ** storage in InitNew so that the DefHandler can know the format
  919. ** of the object. this is particularly important if the objects
  920. ** uses CF_METATFILE or CF_DIB as its format. the DefHandler
  921. ** automatically avoids separately storing presentation cache
  922. ** data when the object's native data is a standard presentation
  923. ** format.
  924. */
  925. WriteFmtUserTypeStgA(lpStg,lpOutlineApp->m_cfOutline,lpszUserType);
  926. // set the doc to a new embedded object.
  927. if (! ServerDoc_InitNewEmbed(lpServerDoc)) {
  928. sc = E_FAIL;
  929. goto error;
  930. }
  931. /* OLE2NOTE: An embedded object must guarantee that it can save
  932. ** even in low memory situations. it must be able to
  933. ** successfully save itself without consuming any additional
  934. ** memory. this means that a server is NOT supposed to open or
  935. ** create any streams or storages when
  936. ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  937. ** embedded object should hold onto its storage and pre-open and
  938. ** hold open any streams that it will need later when it is time
  939. ** to save.
  940. */
  941. hrErr = CallIStorageCreateStreamA(
  942. lpStg,
  943. "LineList",
  944. STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  945. 0,
  946. 0,
  947. &lpOleDoc->m_lpLLStm
  948. );
  949. if (hrErr != NOERROR) {
  950. OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  951. OleDbgOutHResult("LineList CreateStream returned", hrErr);
  952. sc = GetScode(hrErr);
  953. goto error;
  954. }
  955. hrErr = CallIStorageCreateStreamA(
  956. lpStg,
  957. "NameTable",
  958. STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  959. 0,
  960. 0,
  961. &lpOleDoc->m_lpNTStm
  962. );
  963. if (hrErr != NOERROR) {
  964. OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  965. OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  966. sc = GetScode(hrErr);
  967. goto error;
  968. }
  969. lpOleDoc->m_lpStg = lpStg;
  970. // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
  971. lpStg->lpVtbl->AddRef(lpStg);
  972. OLEDBG_END2
  973. return NOERROR;
  974. error:
  975. OLEDBG_END2
  976. return ResultFromScode(sc);
  977. }
  978. // IPersistStorage::Load method
  979. STDMETHODIMP SvrDoc_PStg_Load(
  980. LPPERSISTSTORAGE lpThis,
  981. LPSTORAGE lpStg
  982. )
  983. {
  984. LPSERVERDOC lpServerDoc =
  985. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  986. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  987. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  988. SCODE sc;
  989. HRESULT hrErr;
  990. OLEDBG_BEGIN2("SvrDoc_PStg_Load\r\n")
  991. if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) {
  992. ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED;
  993. /* OLE2NOTE: we need to check if the ConvertStg bit is on. if
  994. ** so, we need to clear the ConvertStg bit and mark the
  995. ** document as dirty so as to force a save when the document
  996. ** is closed. the actual conversion of the bits should be
  997. ** performed when the data is loaded from the IStorage*. in
  998. ** our case any conversion of data formats would be done in
  999. ** OutlineDoc_LoadFromStg function. in reality both SVROUTL
  1000. ** and ISVROTL read and write the same format so no actual
  1001. ** conversion of data bits is necessary.
  1002. */
  1003. if (GetConvertStg(lpStg) == NOERROR) {
  1004. SetConvertStg(lpStg, FALSE);
  1005. OleDbgOut3("SvrDoc_PStg_Load: ConvertStg==TRUE\r\n");
  1006. OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
  1007. }
  1008. } else {
  1009. sc = E_FAIL;
  1010. goto error;
  1011. }
  1012. /* OLE2NOTE: An embedded object must guarantee that it can save
  1013. ** even in low memory situations. it must be able to
  1014. ** successfully save itself without consuming any additional
  1015. ** memory. this means that a server is NOT supposed to open or
  1016. ** create any streams or storages when
  1017. ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1018. ** embedded object should hold onto its storage and pre-open and
  1019. ** hold open any streams that it will need later when it is time
  1020. ** to save.
  1021. */
  1022. if (lpOleDoc->m_lpLLStm)
  1023. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1024. hrErr = CallIStorageOpenStreamA(
  1025. lpStg,
  1026. "LineList",
  1027. NULL,
  1028. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1029. 0,
  1030. &lpOleDoc->m_lpLLStm
  1031. );
  1032. if (hrErr != NOERROR) {
  1033. OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  1034. OleDbgOutHResult("LineList CreateStream returned", hrErr);
  1035. sc = GetScode(hrErr);
  1036. goto error;
  1037. }
  1038. if (lpOleDoc->m_lpNTStm)
  1039. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1040. hrErr = CallIStorageOpenStreamA(
  1041. lpStg,
  1042. "NameTable",
  1043. NULL,
  1044. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1045. 0,
  1046. &lpOleDoc->m_lpNTStm
  1047. );
  1048. if (hrErr != NOERROR) {
  1049. OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  1050. OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  1051. sc = GetScode(hrErr);
  1052. goto error;
  1053. }
  1054. lpOleDoc->m_lpStg = lpStg;
  1055. // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
  1056. lpStg->lpVtbl->AddRef(lpStg);
  1057. OLEDBG_END2
  1058. return NOERROR;
  1059. error:
  1060. OLEDBG_END2
  1061. return ResultFromScode(sc);
  1062. }
  1063. // IPersistStorage::Save method
  1064. STDMETHODIMP SvrDoc_PStg_Save(
  1065. LPPERSISTSTORAGE lpThis,
  1066. LPSTORAGE lpStg,
  1067. BOOL fSameAsLoad
  1068. )
  1069. {
  1070. LPSERVERDOC lpServerDoc =
  1071. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1072. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1073. BOOL fStatus;
  1074. SCODE sc;
  1075. OLEDBG_BEGIN2("SvrDoc_PStg_Save\r\n")
  1076. fStatus = OutlineDoc_SaveSelToStg(
  1077. (LPOUTLINEDOC)lpServerDoc,
  1078. NULL,
  1079. lpOutlineDoc->m_cfSaveFormat,
  1080. lpStg,
  1081. fSameAsLoad,
  1082. FALSE
  1083. );
  1084. if (! fStatus) {
  1085. OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail);
  1086. sc = E_FAIL;
  1087. goto error;
  1088. }
  1089. lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad;
  1090. lpServerDoc->m_fNoScribbleMode = TRUE;
  1091. OLEDBG_END2
  1092. return NOERROR;
  1093. error:
  1094. OLEDBG_END2
  1095. return ResultFromScode(sc);
  1096. }
  1097. // IPersistStorage::SaveCompleted method
  1098. STDMETHODIMP SvrDoc_PStg_SaveCompleted(
  1099. LPPERSISTSTORAGE lpThis,
  1100. LPSTORAGE lpStgNew
  1101. )
  1102. {
  1103. LPSERVERDOC lpServerDoc =
  1104. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1105. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1106. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1107. HRESULT hrErr;
  1108. OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompleted\r\n")
  1109. /* OLE2NOTE: this sample application is a pure server application.
  1110. ** a container/server application would have to call SaveCompleted
  1111. ** for each of its contained compound document objects. if a new
  1112. ** storage was given, then the container/server would have to
  1113. ** open the corresponding new sub-storage for each compound
  1114. ** document object and pass as an argument in the SaveCompleted
  1115. ** call.
  1116. */
  1117. /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation
  1118. ** on an embedded object. if the document is a file-based document
  1119. ** then we can not be changed to a IStorage-base object.
  1120. **
  1121. ** fSameAsLoad lpStgNew Type of Save Send OnSave
  1122. ** ---------------------------------------------------------
  1123. ** TRUE NULL SAVE YES
  1124. ** TRUE ! NULL SAVE * YES
  1125. ** FALSE ! NULL SAVE AS YES
  1126. ** FALSE NULL SAVE COPY AS NO
  1127. **
  1128. ** * this is a strange case that is possible. it is inefficient
  1129. ** for the caller; it would be better to pass lpStgNew==NULL for
  1130. ** the Save operation.
  1131. */
  1132. if ( ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew)
  1133. && (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) ) {
  1134. OLEDBG_END2
  1135. return ResultFromScode(E_INVALIDARG);
  1136. }
  1137. /* OLE2NOTE: inform any linking clients that the document has been
  1138. ** saved. in addition, any currently active pseudo objects
  1139. ** should also inform their clients. we should only broadcast an
  1140. ** OnSave notification if a Save or SaveAs operation was
  1141. ** performed. we do NOT want to send the notification if a
  1142. ** SaveCopyAs operation was performed.
  1143. */
  1144. if (lpStgNew || lpServerDoc->m_fSaveWithSameAsLoad) {
  1145. /* OLE2NOTE: if IPersistStorage::Save has been called, then we
  1146. ** need to clear the dirty bit and send OnSave notification.
  1147. ** if HandsOffStorage is called directly without first
  1148. ** calling Save, then we do NOT want to clear the dirty bit
  1149. ** and send OnSave when SaveCompleted is called.
  1150. */
  1151. if (lpServerDoc->m_fNoScribbleMode) {
  1152. OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);
  1153. ServerDoc_SendAdvise (
  1154. lpServerDoc,
  1155. OLE_ONSAVE,
  1156. NULL, /* lpmkDoc -- not relevant here */
  1157. 0 /* advf -- not relevant here */
  1158. );
  1159. }
  1160. lpServerDoc->m_fSaveWithSameAsLoad = FALSE;
  1161. }
  1162. lpServerDoc->m_fNoScribbleMode = FALSE;
  1163. /* OLE2NOTE: An embedded object must guarantee that it can save
  1164. ** even in low memory situations. it must be able to
  1165. ** successfully save itself without consuming any additional
  1166. ** memory. this means that a server is NOT supposed to open or
  1167. ** create any streams or storages when
  1168. ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1169. ** embedded object should hold onto its storage and pre-open and
  1170. ** hold open any streams that it will need later when it is time
  1171. ** to save. if this is a SaveAs situtation, then we want to
  1172. ** pre-open and hold open our streams to guarantee that a
  1173. ** subsequent save will be successful in low-memory. if we fail
  1174. ** to open these streams then we want to force ourself to close
  1175. ** to make sure the can't make editing changes that can't be
  1176. ** later saved.
  1177. */
  1178. if ( lpStgNew && !lpServerDoc->m_fSaveWithSameAsLoad ) {
  1179. // release previous streams
  1180. if (lpOleDoc->m_lpLLStm) {
  1181. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1182. lpOleDoc->m_lpLLStm = NULL;
  1183. }
  1184. if (lpOleDoc->m_lpNTStm) {
  1185. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1186. lpOleDoc->m_lpNTStm = NULL;
  1187. }
  1188. if (lpOleDoc->m_lpStg) {
  1189. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
  1190. lpOleDoc->m_lpStg = NULL;
  1191. }
  1192. hrErr = CallIStorageOpenStreamA(
  1193. lpStgNew,
  1194. "LineList",
  1195. NULL,
  1196. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1197. 0,
  1198. &lpOleDoc->m_lpLLStm
  1199. );
  1200. if (hrErr != NOERROR) {
  1201. OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  1202. OleDbgOutHResult("LineList CreateStream returned", hrErr);
  1203. goto error;
  1204. }
  1205. hrErr = CallIStorageOpenStreamA(
  1206. lpStgNew,
  1207. "NameTable",
  1208. NULL,
  1209. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1210. 0,
  1211. &lpOleDoc->m_lpNTStm
  1212. );
  1213. if (hrErr != NOERROR) {
  1214. OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  1215. OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  1216. goto error;
  1217. }
  1218. lpOleDoc->m_lpStg = lpStgNew;
  1219. // OLE2NOTE: to hold onto IStorage* pointer, we must AddRef it
  1220. lpStgNew->lpVtbl->AddRef(lpStgNew);
  1221. }
  1222. OLEDBG_END2
  1223. return NOERROR;
  1224. error:
  1225. OLEDBG_END2
  1226. return ResultFromScode(E_OUTOFMEMORY);
  1227. }
  1228. // IPersistStorage::HandsOffStorage method
  1229. STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis)
  1230. {
  1231. LPSERVERDOC lpServerDoc =
  1232. ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1233. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1234. OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStorage\r\n")
  1235. /* OLE2NOTE: An embedded object must guarantee that it can save
  1236. ** even in low memory situations. it must be able to
  1237. ** successfully save itself without consuming any additional
  1238. ** memory. this means that a server is NOT supposed to open or
  1239. ** create any streams or storages when
  1240. ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1241. ** embedded object should hold onto its storage and pre-open and
  1242. ** hold open any streams that it will need later when it is time
  1243. ** to save. Now when HandsOffStorage is called the object must
  1244. ** release its storage and any streams that is holds open.
  1245. ** later when SaveCompleted is called, it will be given back its
  1246. ** storage.
  1247. */
  1248. if (lpOleDoc->m_lpLLStm) {
  1249. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1250. lpOleDoc->m_lpLLStm = NULL;
  1251. }
  1252. if (lpOleDoc->m_lpNTStm) {
  1253. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1254. lpOleDoc->m_lpNTStm = NULL;
  1255. }
  1256. if (lpOleDoc->m_lpStg) {
  1257. OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
  1258. lpOleDoc->m_lpStg = NULL;
  1259. }
  1260. OLEDBG_END2
  1261. return NOERROR;
  1262. }
  1263. #if defined( SVR_TREATAS )
  1264. /*************************************************************************
  1265. ** ServerDoc::IStdMarshalInfo interface implementation
  1266. *************************************************************************/
  1267. // IStdMarshalInfo::QueryInterface method
  1268. STDMETHODIMP SvrDoc_StdMshl_QueryInterface(
  1269. LPSTDMARSHALINFO lpThis,
  1270. REFIID riid,
  1271. LPVOID FAR* lplpvObj
  1272. )
  1273. {
  1274. LPSERVERDOC lpServerDoc =
  1275. ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1276. return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  1277. }
  1278. // IStdMarshalInfo::AddRef method
  1279. STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis)
  1280. {
  1281. LPSERVERDOC lpServerDoc =
  1282. ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1283. OleDbgAddRefMethod(lpThis, "IStdMarshalInfo");
  1284. return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  1285. }
  1286. // IStdMarshalInfo::Release method
  1287. STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis)
  1288. {
  1289. LPSERVERDOC lpServerDoc =
  1290. ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1291. OleDbgReleaseMethod(lpThis, "IStdMarshalInfo");
  1292. return OleDoc_Release((LPOLEDOC)lpServerDoc);
  1293. }
  1294. // IStdMarshalInfo::GetClassForHandler
  1295. STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler(
  1296. LPSTDMARSHALINFO lpThis,
  1297. DWORD dwDestContext,
  1298. LPVOID pvDestContext,
  1299. LPCLSID lpClassID
  1300. )
  1301. {
  1302. LPSERVERDOC lpServerDoc =
  1303. ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1304. OleDbgOut2("SvrDoc_StdMshl_GetClassForHandler\r\n");
  1305. // OLE2NOTE: we only handle LOCAL marshal context.
  1306. if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL)
  1307. return ResultFromScode(E_INVALIDARG);
  1308. /* OLE2NOTE: we must return our REAL clsid, NOT the clsid that we
  1309. ** are pretending to be if a "TreatAs" is in effect.
  1310. */
  1311. *lpClassID = CLSID_APP;
  1312. return NOERROR;
  1313. }
  1314. #endif // SVR_TREATAS
  1315. /*************************************************************************
  1316. ** ServerDoc Support Functions
  1317. *************************************************************************/
  1318. /* ServerDoc_Init
  1319. * --------------
  1320. *
  1321. * Initialize the fields of a new ServerDoc object. The object is initially
  1322. * not associated with a file or an (Untitled) document. This function sets
  1323. * the docInitType to DOCTYPE_UNKNOWN. After calling this function the
  1324. * caller should call:
  1325. * 1.) OutlineDoc_InitNewFile to set the ServerDoc to (Untitled)
  1326. * 2.) OutlineDoc_LoadFromFile to associate the ServerDoc with a file.
  1327. * This function creates a new window for the document.
  1328. *
  1329. * NOTE: the window is initially created with a NIL size. it must be
  1330. * sized and positioned by the caller. also the document is initially
  1331. * created invisible. the caller must call OutlineDoc_ShowWindow
  1332. * after sizing it to make the document window visible.
  1333. */
  1334. BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc)
  1335. {
  1336. lpServerDoc->m_cPseudoObj = 0;
  1337. lpServerDoc->m_lpOleClientSite = NULL;
  1338. lpServerDoc->m_lpOleAdviseHldr = NULL;
  1339. lpServerDoc->m_lpDataAdviseHldr = NULL;
  1340. // initialy doc does not have any storage
  1341. lpServerDoc->m_fNoScribbleMode = FALSE;
  1342. lpServerDoc->m_fSaveWithSameAsLoad = FALSE;
  1343. lpServerDoc->m_szContainerApp[0] = '\0';
  1344. lpServerDoc->m_szContainerObj[0] = '\0';
  1345. lpServerDoc->m_nNextRangeNo = 0L;
  1346. lpServerDoc->m_lrSrcSelOfCopy.m_nStartLine = -1;
  1347. lpServerDoc->m_lrSrcSelOfCopy.m_nEndLine = -1;
  1348. lpServerDoc->m_fDataChanged = FALSE;
  1349. lpServerDoc->m_fSizeChanged = FALSE;
  1350. lpServerDoc->m_fSendDataOnStop = FALSE;
  1351. #if defined( SVR_TREATAS )
  1352. lpServerDoc->m_clsidTreatAs = CLSID_NULL;
  1353. lpServerDoc->m_lpszTreatAsType = NULL;
  1354. #endif // SVR_TREATAS
  1355. #if defined( INPLACE_SVR )
  1356. lpServerDoc->m_hWndHatch =
  1357. CreateHatchWindow(
  1358. OutlineApp_GetWindow(g_lpApp),
  1359. OutlineApp_GetInstance(g_lpApp)
  1360. );
  1361. if (!lpServerDoc->m_hWndHatch)
  1362. return FALSE;
  1363. lpServerDoc->m_fInPlaceActive = FALSE;
  1364. lpServerDoc->m_fInPlaceVisible = FALSE;
  1365. lpServerDoc->m_fUIActive = FALSE;
  1366. lpServerDoc->m_lpIPData = NULL;
  1367. lpServerDoc->m_fMenuHelpMode = FALSE; // F1 pressed in menu
  1368. INIT_INTERFACEIMPL(
  1369. &lpServerDoc->m_OleInPlaceObject,
  1370. &g_SvrDoc_OleInPlaceObjectVtbl,
  1371. lpServerDoc
  1372. );
  1373. INIT_INTERFACEIMPL(
  1374. &lpServerDoc->m_OleInPlaceActiveObject,
  1375. &g_SvrDoc_OleInPlaceActiveObjectVtbl,
  1376. lpServerDoc
  1377. );
  1378. #endif // INPLACE_SVR
  1379. INIT_INTERFACEIMPL(
  1380. &lpServerDoc->m_OleObject,
  1381. &g_SvrDoc_OleObjectVtbl,
  1382. lpServerDoc
  1383. );
  1384. INIT_INTERFACEIMPL(
  1385. &lpServerDoc->m_PersistStorage,
  1386. &g_SvrDoc_PersistStorageVtbl,
  1387. lpServerDoc
  1388. );
  1389. #if defined( SVR_TREATAS )
  1390. INIT_INTERFACEIMPL(
  1391. &lpServerDoc->m_StdMarshalInfo,
  1392. &g_SvrDoc_StdMarshalInfoVtbl,
  1393. lpServerDoc
  1394. );
  1395. #endif // SVR_TREATAS
  1396. return TRUE;
  1397. }
  1398. /* ServerDoc_InitNewEmbed
  1399. * ----------------------
  1400. *
  1401. * Initialize the ServerDoc object to be a new embedded object document.
  1402. * This function sets the docInitType to DOCTYPE_EMBED.
  1403. */
  1404. BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc)
  1405. {
  1406. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1407. OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);
  1408. lpOutlineDoc->m_docInitType = DOCTYPE_EMBEDDED;
  1409. /* The Window title for an embedded object is constructed as
  1410. ** follows:
  1411. ** <server app name> - <obj short type> in <cont. doc name>
  1412. **
  1413. ** here we construct the current document title portion of the
  1414. ** name which follows the '-'. OutlineDoc_SetTitle prepends the
  1415. ** "<server app name> - " to the document title.
  1416. */
  1417. // REVIEW: this string should be loaded from string resource
  1418. wsprintf(lpOutlineDoc->m_szFileName, "%s in %s",
  1419. (LPSTR)SHORTUSERTYPENAME,
  1420. (LPSTR)DEFCONTAINERNAME);
  1421. lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  1422. /* OLE2NOTE: an embedding should be marked as initially dirty so
  1423. ** that on close we always call IOleClientSite::SaveObject.
  1424. */
  1425. OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
  1426. OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  1427. return TRUE;
  1428. }
  1429. /* ServerDoc_SendAdvise
  1430. * --------------------
  1431. *
  1432. * This function sends an advise notification on behalf of a specific
  1433. * doc object to all its clients.
  1434. */
  1435. void ServerDoc_SendAdvise(
  1436. LPSERVERDOC lpServerDoc,
  1437. WORD wAdvise,
  1438. LPMONIKER lpmkDoc,
  1439. DWORD dwAdvf
  1440. )
  1441. {
  1442. LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1443. LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1444. switch (wAdvise) {
  1445. case OLE_ONDATACHANGE:
  1446. // inform clients that the data of the object has changed
  1447. if (lpOutlineDoc->m_nDisableDraw == 0) {
  1448. /* drawing is currently enabled. inform clients that
  1449. ** the data of the object has changed
  1450. */
  1451. lpServerDoc->m_fDataChanged = FALSE;
  1452. /* OLE2NOTE: we must note the time of last change
  1453. ** for our object in the RunningObjectTable.
  1454. ** this is used as the basis to answer
  1455. ** IOleObject::IsUpToDate. we only want to note
  1456. ** the change time when an actual change takes
  1457. ** place. we do NOT want to set it when we are
  1458. ** notifying clients of ADVF_DATAONSTOP
  1459. */
  1460. if (dwAdvf == 0)
  1461. OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT);
  1462. if (lpServerDoc->m_lpDataAdviseHldr) {
  1463. OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n");
  1464. lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(
  1465. lpServerDoc->m_lpDataAdviseHldr,
  1466. (LPDATAOBJECT)&lpOleDoc->m_DataObject,
  1467. 0,
  1468. dwAdvf
  1469. );
  1470. OLEDBG_END2
  1471. }
  1472. #if defined( INPLACE_SVR )
  1473. /* OLE2NOTE: if the ServerDoc is currently in-place UI active,
  1474. ** then is it important to renegotiate the size for the
  1475. ** in-place document window BEFORE sending OnDataChange
  1476. ** (which will cause the window to repaint).
  1477. */
  1478. if (lpServerDoc->m_fSizeChanged) {
  1479. lpServerDoc->m_fSizeChanged = FALSE;
  1480. if (lpServerDoc->m_fInPlaceActive)
  1481. ServerDoc_UpdateInPlaceWindowOnExtentChange(lpServerDoc);
  1482. }
  1483. #endif
  1484. /* OLE2NOTE: we do NOT need to tell our pseudo objects to
  1485. ** broadcast OnDataChange notification because
  1486. ** they will do it automatically when an editing
  1487. ** change in the document affects a PseudoObj.
  1488. ** (see OutlineNameTable_AddLineUpdate,
  1489. ** OutlineNameTable_DeleteLineUpdate,
  1490. ** and ServerNameTable_EditLineUpdate)
  1491. */
  1492. } else {
  1493. /* drawing is currently disabled. do not send
  1494. ** notifications or call
  1495. ** IOleInPlaceObject::OnPosRectChange until drawing
  1496. ** is re-enabled.
  1497. */
  1498. }
  1499. break;
  1500. case OLE_ONCLOSE:
  1501. // inform clients that the document is shutting down
  1502. if (lpServerDoc->m_lpOleAdviseHldr) {
  1503. OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");
  1504. lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose(
  1505. lpServerDoc->m_lpOleAdviseHldr
  1506. );
  1507. OLEDBG_END2
  1508. }
  1509. /* OLE2NOTE: we do NOT need to tell our pseudo objects to
  1510. ** broadcast OnClose notification because they will do
  1511. ** it automatically when the pseudo object is closed.
  1512. ** (see PseudoObj_Close)
  1513. */
  1514. break;
  1515. case OLE_ONSAVE:
  1516. // inform clients that the object has been saved
  1517. OLEDBG_BEGIN3("ServerDoc_SendAdvise ONSAVE\r\n");
  1518. if (lpServerDoc->m_lpOleAdviseHldr) {
  1519. OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave called\r\n");
  1520. lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave(
  1521. lpServerDoc->m_lpOleAdviseHldr
  1522. );
  1523. OLEDBG_END2
  1524. }
  1525. /* OLE2NOTE: inform any clients of pseudo objects
  1526. ** within our document, that our document has been
  1527. ** saved.
  1528. */
  1529. ServerNameTable_InformAllPseudoObjectsDocSaved(
  1530. (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,
  1531. lpmkDoc
  1532. );
  1533. OLEDBG_END3
  1534. break;
  1535. case OLE_ONRENAME:
  1536. // inform clients that the object's name has changed
  1537. OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAME\r\n");
  1538. if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) {
  1539. OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n");
  1540. lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename(
  1541. lpServerDoc->m_lpOleAdviseHldr,
  1542. lpmkDoc
  1543. );
  1544. OLEDBG_END2
  1545. }
  1546. OLEDBG_END3
  1547. break;
  1548. }
  1549. }
  1550. /* ServerDoc_GetClassID
  1551. ** --------------------
  1552. ** Return the class ID corresponding to the bits in the storage.
  1553. ** normally this will be our application's given CLSID. but if a
  1554. ** "TreateAs (aka. ActivateAs)" operation is taking place, then our
  1555. ** application needs to pretend to be the class of the object that
  1556. ** we are emulating. this is also the class that will be written
  1557. ** into the storage.
  1558. */
  1559. HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid)
  1560. {
  1561. #if defined( SVR_TREATAS )
  1562. if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL))
  1563. *lpclsid = lpServerDoc->m_clsidTreatAs;
  1564. else
  1565. #endif // SVR_TREATAS
  1566. *lpclsid = CLSID_APP;
  1567. return NOERROR;
  1568. }
  1569. /* ServerDoc_UpdateMenu
  1570. * --------------------
  1571. *
  1572. * Update menu for embedding mode. the changes include:
  1573. * 1 Remove File/New and File/Open (SDI ONLY)
  1574. * 2 Change File/Save As.. to File/Save Copy As..
  1575. * 3 Change File menu so it contains "Update" instead of "Save"
  1576. * 4 Change File/Exit to File/Exit & Return to <client doc>"
  1577. */
  1578. void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc)
  1579. {
  1580. char str[256];
  1581. HWND hWndMain;
  1582. HMENU hMenu;
  1583. OleDbgOut2("ServerDoc_UpdateMenu\r\n");
  1584. hWndMain=g_lpApp->m_hWndApp;
  1585. hMenu=GetMenu(hWndMain);
  1586. #if defined( SDI_VERSION )
  1587. /* SDI ONLY: Remove File/New and File/Open */
  1588. DeleteMenu(hMenu, IDM_F_NEW, MF_BYCOMMAND);
  1589. DeleteMenu(hMenu, IDM_F_OPEN, MF_BYCOMMAND);
  1590. #endif
  1591. // Change File.Save As.. to File.Save Copy As.. */
  1592. ModifyMenu(hMenu,IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save Copy As..");
  1593. // Change File.Save to "&Update <container doc>"
  1594. wsprintf(str, g_szUpdateCntrDoc, lpServerDoc->m_szContainerObj);
  1595. ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str);
  1596. // Change File/Exit to File/Exit & Return to <container doc>" */
  1597. wsprintf(str, g_szExitNReturnToCntrDoc, lpServerDoc->m_szContainerObj);
  1598. ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, str);
  1599. DrawMenuBar(hWndMain);
  1600. }
  1601. #if defined( MDI_VERSION )
  1602. // NOTE: ServerDoc_RestoreMenu is actually redundant because the
  1603. // app is dying when the function is called. (In SDI, the
  1604. // app will terminate when the ref counter of the server doc
  1605. // is zero). However, it is important for MDI.
  1606. /* ServerDoc_RestoreMenu
  1607. * ---------------------
  1608. *
  1609. * Reset the menu to non-embedding mode
  1610. */
  1611. void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc)
  1612. {
  1613. LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  1614. HWND hWndMain;
  1615. HMENU hMenu;
  1616. OleDbgOut2("ServerDoc_RestoreMenu\r\n");
  1617. hWndMain = lpOutlineApp->m_hWndApp;
  1618. hMenu = GetMenu(hWndMain);
  1619. /* Add back File/New, File/Open.. and File/Save */
  1620. InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,
  1621. IDM_F_NEW, "&New");
  1622. InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,
  1623. IDM_F_OPEN, "&Open...");
  1624. /* Change File menu so it contains "Save As..." instead of */
  1625. /* "Save Copy As..." */
  1626. ModifyMenu(hMenu, IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save &As..");
  1627. /* Change File menu so it contains "Save" instead of "Update" */
  1628. ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, "&Save");
  1629. /* Change File menu so it contains "Exit" */
  1630. /* instead of just "Exit & Return to <client doc>" */
  1631. ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, "E&xit");
  1632. DrawMenuBar (hWndMain);
  1633. }
  1634. #endif // MDI_VERSION