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