|
|
1.1 root 1: /*
2: OLE SERVER DEMO
3: Doc.c
4:
5: This file contains document methods and various document-related support
6: functions.
7:
8: (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
9: */
10:
11: /*
12: Important Note:
13:
14: No method should ever dispatch a DDE message or allow a DDE message to
15: be dispatched.
16: Therefore, no method should ever enter a message dispatch loop.
17: Also, a method should not show a dialog or message box, because the
18: processing of the dialog box messages will allow DDE messages to be
19: dispatched.
20: */
21:
22:
23:
24: #define SERVERONLY
25: #include <windows.h>
26: #include <ole.h>
27:
28: #include "srvrdemo.h"
29:
30: /* AssociateClient
31: * ---------------
32: *
33: * Add a client to the list of clients associated with an object.
34: *
35: * This function is necessary only because ServerDemo does not create object
36: * structures as they are requested, but rather has a fixed set of objects.
37: * When DocGetObject is called with a NULL object name, the entire
38: * document is requested, but ServerDemo does not currently support making
39: * the entire document an object, so DocGetObject returns one object.
40: * That object now goes by two names: NULL and its real name. Therefore
41: * we need to keep track of both lpoleclient's that were passed to
42: * DocGetObject. Ideally, DocGetObject should always create a new OBJ
43: * structure containing a pointer (or some reference) to the object's native
44: * data and also containing one lpoleclient.
45: *
46: * LPOLECLIENT lpoleclient - the client to be associated with the object.
47: * LPOBJ lpobj - the object
48: *
49: * RETURNS: TRUE if successful
50: * FALSE if out of memory
51: *
52: * CUSTOMIZATION: Server Demo specific
53: *
54: */
55: static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
56: {
57: INT i;
58: for (i=0; i < clpoleclient; i++)
59: {
60: if (lpobj->lpoleclient[i]==lpoleclient)
61: {
62: return TRUE;
63: }
64: if (lpobj->lpoleclient[i]==NULL)
65: {
66: lpobj->lpoleclient[i]=lpoleclient;
67: return TRUE;
68: }
69: }
70: return FALSE;
71: }
72:
73:
74:
75: /* CreateNewDoc
76: * ------------
77: *
78: * If lhdoc == NULL then we must register the new document by calling
79: * OleRegisterServerDoc, which will return a new handle which will be stored
80: * in docMain.lhdoc.
81: * Also if lhdoc==NULL then this document is being created at the request of
82: * the user, not of the client library.
83: *
84: * LONG lhdoc - Document handle
85: * LPSTR lpszDoc - Title of the new document
86: * DOCTYPE doctype - What type of document is being created
87: *
88: * RETURNS: TRUE if successful, FALSE otherwise.
89: *
90: * CUSTOMIZATION: Re-implement
91: *
92: */
93: BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
94: {
95: INT i;
96:
97: // Fill in the fields of the document structure.
1.1.1.3 ! root 98:
! 99: docMain.doctype = doctype;
! 100: docMain.oledoc.lpvtbl= &docvtbl;
! 101:
! 102: if (lhdoc == 0)
1.1 root 103: {
104: if (OLE_OK != OleRegisterServerDoc
105: (srvrMain.lhsrvr,
106: lpszDoc,
107: (LPOLESERVERDOC) &docMain,
108: (LHSERVERDOC FAR *) &docMain.lhdoc))
109: return FALSE;
110: }
111: else
112: docMain.lhdoc = lhdoc;
113:
114: // Reset all the flags because no object numbers have been used.
115: for (i=1; i <= cfObjNums; i++)
116: docMain.rgfObjNums[i] = FALSE;
117:
118: fDocChanged = FALSE;
119:
120: SetTitle (lpszDoc, doctype == doctypeEmbedded);
121: return TRUE;
122: }
123:
124:
125:
126: /* DestroyDoc
127: * ----------
128: *
129: * Free all memory that had been allocated for a document.
130: *
131: *
132: * CUSTOMIZATION: Re-implement. Your application will probably use some
133: * other method for enumerating all the objects in a document.
134: * ServerDemo enumerates the child windows, but if each object
135: * does not have its own window, this will not work.
136: *
137: */
138: VOID DestroyDoc (VOID)
139: {
140: HWND hwnd;
141: HWND hwndNext;
142:
143: // Delete all object windows.
144: hwnd = SelectedObjectWindow();
145: while (hwnd)
146: {
147: hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
148: // Each object window frees its own memory upon receiving WM_DESTROY.
149: DestroyWindow (hwnd);
150: hwnd = hwndNext;
151: }
152:
153: if (docMain.aName)
154: {
155: GlobalDeleteAtom (docMain.aName);
1.1.1.3 ! root 156: docMain.aName = '\0';
1.1 root 157: }
158:
159: if (docMain.hpal)
160: DeleteObject (docMain.hpal);
161: }
162:
163:
164:
165: /* DocClose DOCUMENT "Close" METHOD
166: * --------
167: *
168: * The library calls this method to unconditionally close the document.
169: *
170: * LPOLESERVERDOC lpoledoc - The server document to close
171: *
172: * RETURNS: Return value from RevokeDoc.
173: *
174: * CUSTOMIZATION: None
175: *
176: */
177: OLESTATUS APIENTRY DocClose (LPOLESERVERDOC lpoledoc)
178: {
179: return RevokeDoc();
180: }
181:
182:
183:
184: /* DocExecute DOCUMENT "Execute" METHOD
185: * ----------
186: *
187: * This application does not support the execution of DDE execution commands.
188: *
189: * LPOLESERVERDOC lpoledoc - The server document
190: * HANDLE hCommands - DDE execute commands
191: *
192: * RETURNS: OLE_ERROR_COMMAND
193: *
194: * CUSTOMIZATION: Re-implement if your application supports the execution of
195: * DDE commands.
196: *
197: */
198: OLESTATUS APIENTRY DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
199: {
200: return OLE_ERROR_COMMAND;
201: }
202:
203:
204:
205: /* DocGetObject DOCUMENT "GetObject" METHOD
206: * ------------
207: *
208: * The library uses this method to get an object's structure for the
209: * client. Memory needs to be allocated and initialized here for this.
210: * A NULL string indicates that the client has an embedded object
211: * which was started from Create, CreateFromTemplate, or Edit, but not Open.
212: *
213: * First see if the object name is NULL. If so, you would ordinarily
214: * return the entire document, but Server Demo returns the selected object.
215: * If the object name is not NULL, then go through the list of objects,
216: * searching for one with that name. Return an error if there is not one.
217: *
218: * LPOLESERVERDOC lpoledoc - The server document
1.1.1.3 ! root 219: * OLE_LPCSTR lpszObjectName - The name of the object to get data for
1.1 root 220: * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
221: * LPOLECLIENT lpoleclient - The client structure
222: *
223: * RETURNS: OLE_OK
224: * OLE_ERROR_NAME if object not found
225: * OLE_ERROR_MEMORY if no more memory to store lpoleclient
226: *
227: * CUSTOMIZATION: Re-implement.
228: * lpszObjectName == "" indicates that the whole document
229: * should be the object returned.
230: *
231: */
232: OLESTATUS APIENTRY DocGetObject
1.1.1.3 ! root 233: (LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpszObjectName,
1.1 root 234: LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
235: {
236: HWND hwnd;
237: ATOM aName;
238: LPOBJ lpobj;
239:
240:
241: if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
242: {
243: // Return a new object or the selected object.
244: hwnd = SelectedObjectWindow();
245: lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
246: *lplpoleobject = (LPOLEOBJECT) lpobj;
247: // Associate client with object.
248: if (!AssociateClient (lpoleclient, lpobj))
249: return OLE_ERROR_MEMORY;
250: return OLE_OK;
251: }
252:
253: if (!(aName = GlobalFindAtom (lpszObjectName)))
254: return OLE_ERROR_NAME;
255:
256: hwnd = SelectedObjectWindow();
257:
258: // Go through all the child windows and find the window whose name
259: // matches the given object name.
260:
261: while (hwnd)
262: {
263: lpobj = HwndToLpobj (hwnd);
264:
265: if (aName == lpobj->aName)
266: {
267: // Return the object with the matching name.
268: *lplpoleobject = (LPOLEOBJECT) lpobj;
269: // Associate client with the object.
270: if (!AssociateClient (lpoleclient, lpobj))
271: return OLE_ERROR_MEMORY;
272: return OLE_OK;
273: }
274: hwnd = GetWindow (hwnd, GW_HWNDNEXT);
275: }
276:
277: if (((DOCPTR)lpoledoc)->doctype == doctypeEmbedded)
278: {
279: lpobj = CreateNewObj (FALSE);
280: *lplpoleobject = (LPOLEOBJECT) lpobj;
281:
282: // Associate client with object.
283: if (!AssociateClient (lpoleclient, lpobj))
284: return OLE_ERROR_MEMORY;
285: return OLE_OK;
286: }
287:
288: // Object with name lpszObjName was not found.
289: return OLE_ERROR_NAME;
290: }
291:
292: /* DocRelease DOCUMENT "Release" METHOD
293: * ----------
294: *
295: * The library uses this method to notify the server that a revoked
296: * document has finally finished all conversations, and can be
297: * destroyed.
298: * It sets fWaitingForDocRelease to FALSE so a new document can be created
299: * and the user can continue working.
300: *
301: * LPOLESERVERDOC lpoledoc - The server document
302: *
303: * RETURNS: OLE_OK
304: *
305: * CUSTOMIZATION: None
306: *
307: */
308: OLESTATUS APIENTRY DocRelease (LPOLESERVERDOC lpoledoc)
309: {
310: fWaitingForDocRelease = FALSE;
311: // Free all memory that has been allocated for the document.
312: DestroyDoc();
313:
314: return OLE_OK;
315: }
316:
317:
318:
319: /* DocSave DOCUMENT "Save" METHOD
320: * -------
321: *
322: * Save document to a file.
323: *
324: * LPOLESERVERDOC lpoledoc - The document to save
325: *
326: * RETURNS: OLE_OK
327: *
328: * CUSTOMIZATION: None
329: *
330: */
331: OLESTATUS APIENTRY DocSave (LPOLESERVERDOC lpoledoc)
332: {
333: if (docMain.doctype == doctypeFromFile)
334: {
335: // No "File Save As" dialog box will be brought up because the
336: // file name is already known.
337: return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
338: }
339: else
340: return OLE_ERROR_GENERIC;
341: }
342:
343:
344:
345: /* DocSetDocDimensions DOCUMENT "SetDocDimensions" METHOD
346: * -------------------
347: *
348: * The library calls this method to tell the server the bounds on
349: * the target device for rendering the document.
350: * A call to this method is ignored for linked objects because the size of
351: * a linked document depends only on the source file.
352: *
353: * LPOLESERVERDOC lpoledoc - The server document
1.1.1.3 ! root 354: * CONST LPRECT lprect - The target size in MM_HIMETRIC units
1.1 root 355: *
356: * RETURNS: OLE_OK
357: *
358: * CUSTOMIZATION: Re-implement
359: * How an object is sized is application-specific. (Server Demo
360: * uses MoveWindow.)
361: *
362: */
363: OLESTATUS APIENTRY DocSetDocDimensions
1.1.1.3 ! root 364: (LPOLESERVERDOC lpoledoc, OLE_CONST RECT FAR * lprect)
1.1 root 365: {
366: if (docMain.doctype == doctypeEmbedded)
367: {
368: RECT rect = *lprect;
369:
370: // the units are in HIMETRIC
371: rect.right = rect.right - rect.left;
1.1.1.2 root 372: // the following was bottom - top
373: rect.bottom = rect.top - rect.bottom;
1.1 root 374:
1.1.1.2 root 375: HiMetricToDevice ( (LPPOINT) &rect.right );
1.1 root 376: MoveWindow (SelectedObjectWindow(), 0, 0,
377: rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
378: rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
379: TRUE);
380: /* If for some reason your application needs to notify the client that
381: the data has changed because DocSetDocDimensions has been called,
382: then notify the client here.
383: SendDocMsg (OLE_CHANGED);
384: */
385: }
386: return OLE_OK;
387: }
388:
389:
390:
391: /* DocSetHostNames DOCUMENT "SetHostNames" METHOD
392: * ---------------
393: *
394: * The library uses this method to set the name of the document
395: * window.
396: * All this function does is change the title bar text, although it could
397: * do more if necesary.
398: * This function is only called for embedded objects; linked objects
399: * use their filenames for the title bar text.
400: *
401: * LPOLESERVERDOC lpoledoc - The server document
1.1.1.3 ! root 402: * OLE_LPCSTR lpszClient - The name of the client
! 403: * OLE_LPCSTR lpszDoc - The client's name for the document
1.1 root 404: *
405: * RETURNS: OLE_OK
406: *
407: * CUSTOMIZATION: None
408: *
409: */
410: OLESTATUS APIENTRY DocSetHostNames
1.1.1.3 ! root 411: (LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpszClient, OLE_LPCSTR lpszDoc)
1.1 root 412: {
1.1.1.3 ! root 413: SetTitle ((LPSTR)lpszDoc, TRUE);
1.1 root 414: lstrcpy ((LPSTR) szClient, lpszClient);
1.1.1.3 ! root 415: lstrcpy ((LPSTR) szClientDoc, Abbrev((LPSTR)lpszDoc));
1.1 root 416: UpdateFileMenu (IDM_UPDATE);
417: return OLE_OK;
418: }
419:
420:
421:
422: /* DocSetColorScheme DOCUMENT "SetColorScheme" METHOD
423: * -----------------
424: *
425: * The client calls this method to suggest a color scheme (palette) for
426: * the server to use.
427: * In Server Demo the document's palette is never actually used because each
428: * object has its own palette. See ObjSetColorScheme.
429: *
430: * LPOLESERVERDOC lpoledoc - The server document
1.1.1.3 ! root 431: * CONST LOGPALETTE FAR * lppal - Suggested palette
1.1 root 432: *
433: * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
434: * OLE_OK otherwise
435: *
436: *
437: * CUSTOMIZATION: If your application supports color schemes, then this
438: * function is a good example of how to create and store
439: * a palette.
440: */
441: OLESTATUS APIENTRY DocSetColorScheme
1.1.1.3 ! root 442: (LPOLESERVERDOC lpoledoc, OLE_CONST LOGPALETTE FAR * lppal)
1.1 root 443: {
444: HPALETTE hpal = CreatePalette (lppal);
445:
446: if (hpal==NULL)
447: return OLE_ERROR_PALETTE;
448:
449: if (docMain.hpal)
450: {
451: // Delete old palette
452: DeleteObject (docMain.hpal);
453: }
454: // Store handle to new palette
455: docMain.hpal = hpal;
456: return OLE_OK;
457: }
458:
459:
460:
461: /* RevokeDoc
462: * ---------
463: *
464: * Call OleRevokeServerDoc.
465: * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
466: * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
467: * As long as fWaitingForDocRelease is set, the user interface will be
468: * disabled so that the user will not be able to manipulate the document.
469: * When the DocRelease method is called, it will reset fWaitingForDocRelease,
470: * allowing RevokeDoc to free the document's memory and return.
471: *
472: * This is essentially a way to make an asynchronous operation synchronous.
473: * We need to wait until the old document is revoked before we can delete
474: * its data and create a new one.
475: *
476: * Note that we cannot call RevokeDoc from a method because it is illegal to
477: * enter a message-dispatch loop within a method.
478: *
479: * RETURNS: The return value of OleRevokeServerDoc.
480: *
481: * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your
482: * application does not have a global variable corresponding
483: * to docMain.
484: *
485: */
486: OLESTATUS RevokeDoc (VOID)
487: {
488: OLESTATUS olestatus;
489:
490: if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
491: DestroyDoc();
492:
1.1.1.3 ! root 493: docMain.lhdoc = 0; // A NULL handle indicates that the document
1.1 root 494: // has been revoked or is being revoked.
495: return olestatus;
496:
497: }
498:
499:
500:
501: /* SaveChangesOption
502: * -----------------
503: *
504: * Give the user the opportunity to save changes to the current document
505: * before continuing.
506: *
507: * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
508: * the update and needs to be updated when the document
509: * is closed. In that case, OLE_CLOSED will be sent.
510: *
511: * RETURNS: IDYES, IDNO, or IDCANCEL
512: *
513: * CUSTOMIZATION: None
514: *
515: */
516: INT SaveChangesOption (BOOL *pfUpdateLater)
517: {
518: INT nReply;
519: CHAR szBuf[cchFilenameMax];
520:
521: *pfUpdateLater = FALSE;
522:
523: if (fDocChanged)
524: {
525: CHAR szTmp[cchFilenameMax];
526:
527: if (docMain.aName)
528: GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
529: else
1.1.1.3 ! root 530: szTmp[0] = '\0';
1.1 root 531:
532: if (docMain.doctype == doctypeEmbedded)
533: wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));
534: else
535: lstrcpy (szBuf, (LPSTR) "Save changes?");
536:
537: nReply = MessageBox (hwndMain, szBuf, szAppName,
538: MB_ICONEXCLAMATION | MB_YESNOCANCEL);
539:
540: switch (nReply)
541: {
542: case IDYES:
543: if (docMain.doctype != doctypeEmbedded)
544: SaveDoc();
545: else
546: switch (OleSavedServerDoc (docMain.lhdoc))
547: {
548: case OLE_ERROR_CANT_UPDATE_CLIENT:
549: *pfUpdateLater = TRUE;
550: break;
551: case OLE_OK:
552: break;
553: default:
554: ErrorBox ("Fatal Error: Cannot update.");
555: }
556: return IDYES;
557: case IDNO:
558: return IDNO;
559: case IDCANCEL:
560: return IDCANCEL;
561: }
562: }
563: return TRUE;
564: }
565:
566:
567:
568: /* SendDocMsg
569: * ----------
570: *
571: * This function sends messages to all the objects in a document when
572: * the document has changed.
573: *
574: * WORD wMessage - The message to send
575: *
576: * CUSTOMIZATION: The means of enumerating all the objects in a document
577: * is application specific.
578: */
579: VOID SendDocMsg (WORD wMessage)
580: {
581: HWND hwnd;
582:
583: // Get handle to first object window.
584: hwnd = SelectedObjectWindow();
585:
586: // Send message to all object windows.
587: while (hwnd)
588: {
589: SendObjMsg (HwndToLpobj(hwnd), wMessage);
590: hwnd = GetWindow (hwnd, GW_HWNDNEXT);
591: }
592: }
593:
594:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.