|
|
1.1 root 1: /*
2: OLE SERVER DEMO
3: SrvrDemo.c
4:
5: This file contains the window handlers, and various initialization and
6: utility functions.
7:
8: (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
9: */
10:
11:
12: #define SERVERONLY
13: #include <windows.h>
14: #include <ole.h>
15:
16: #include "srvrdemo.h"
17:
18: /* Global variable definitions */
19:
20: HWND hwndMain = NULL;
21:
22: // Since this is a not an MDI app, there can be only one server and one doc.
23: SRVR srvrMain;
24: DOC docMain;
25: CHAR szClient[cchFilenameMax];
26: CHAR szClientDoc[cchFilenameMax];
27:
28: // Has the user made changes to the document?
29: BOOL fDocChanged = FALSE;
30:
31: // Is this the first instance of this application currently running?
32: BOOL fFirstInstance = TRUE;
33:
34: // This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE,
35: // and we must wait until DocRelease is called.
36: BOOL fWaitingForDocRelease = FALSE;
37:
38: // This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE,
39: // and we must wait until SrvrRelease is called.
40: BOOL fWaitingForSrvrRelease = FALSE;
41:
42: // This flag is set to TRUE after an application has called OleBlockServer
43: // and now wishes to unblock the queued messages. See WinMain.
44: // Server Demo never sets fUnblock to TRUE because it never calls
45: // OleBlockServer.
46: BOOL fUnblock = FALSE;
47:
48: // Set this to FALSE if you want to guarantee that the server will not revoke
49: // itself when SrvrRelease is called. This is used in the IDM_NEW case and
50: // the IDM_OPEN case (in OpenDoc).
51: BOOL fRevokeSrvrOnSrvrRelease = TRUE;
52:
53: // Version number, which is stored in the native data.
54: VERSION version = 1;
55:
56: HBRUSH hbrColor[chbrMax];
57:
58: // Clipboard formats
59: OLECLIPFORMAT cfObjectLink;
60: OLECLIPFORMAT cfOwnerLink;
61: OLECLIPFORMAT cfNative;
62:
63: // Method tables.
64: OLESERVERDOCVTBL docvtbl;
65: OLEOBJECTVTBL objvtbl;
66: OLESERVERVTBL srvrvtbl;
67:
68: HANDLE hInst;
69: HANDLE hAccelTable;
70: HMENU hMainMenu = NULL;
71:
72: // Window dimensions saved in private profile.
73: static struct
74: {
75: INT nX;
76: INT nY;
77: INT nWidth;
78: INT nHeight;
79: } dimsSaved, dimsCurrent;
80:
81:
82: static enum
83: {
84: // Corresponds to the order of the menus in the .rc file.
85: menuposFile,
86: menuposEdit,
87: menuposColor,
88: menuposObject
89: };
90:
91:
92: // Static functions.
93: static VOID DeleteInstance (VOID);
94: static BOOL ExitApplication (BOOL);
95: static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst);
96: static BOOL InitApplication( HANDLE hInstance);
97: static BOOL InitInstance (HANDLE hInstance);
98: static BOOL ProcessCmdLine (LPSTR,HWND);
99: static VOID SaveDimensions (VOID);
100: static VOID SkipBlanks (LPSTR *plpsz);
101: static VOID UpdateObjMenus (VOID);
102: static BOOL FailedUpdate(HWND);
103:
104: /* WinMain
105: * -------
106: *
107: * Standard windows entry point
108: *
109: * CUSTOMIZATION: None
110: *
111: */
112: int WinMain(
113: HANDLE hInstance,
114: HANDLE hPrevInstance,
115: LPSTR lpCmdLine,
116: INT nCmdShow
117: ){
118: MSG msg;
119:
120: if (!InitApplication(hInstance))
121: return FALSE;
122:
123: msg.wParam = FALSE;
124:
125: if (!InitInstance(hInstance))
126: goto errRtn;
127:
128: if (!InitServer (hwndMain, hInstance))
129: goto errRtn;
130:
131: if (!ProcessCmdLine(lpCmdLine,hwndMain))
132: {
133: ExitApplication(FALSE);
134: goto errRtn;
135: }
136:
137: for (;;)
138: {
139: // Your application should set fUnblock to TRUE when it decides
140: // to unblock.
141: if (fUnblock)
142: {
143: BOOL fMoreMsgs = TRUE;
144: while (fMoreMsgs)
145: {
146: OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
147: }
148: // We have taken care of all the messages in the OLE queue
149: fUnblock = FALSE;
150: }
151:
152: if (!GetMessage(&msg, NULL, NULL, NULL))
153: break;
154: if( !TranslateAccelerator(hwndMain, hAccelTable, &msg))
155: {
156: TranslateMessage(&msg);
157: DispatchMessage(&msg);
158: }
159: }
160:
161:
162: errRtn:
163:
164: DeleteInstance ();
165: return (msg.wParam);
166: }
167:
168:
169:
170: /* InitApplication
171: * ---------------
172: *
173: * Initialize the application - register the window classes
174: *
175: * HANDLE hInstance
176: *
177: * RETURNS: TRUE if classes are properly registered.
178: * FALSE otherwise
179: *
180: * CUSTOMIZATION: Re-implement
181: *
182: */
183: static BOOL InitApplication( HANDLE hInstance )
184: {
185: WNDCLASS wc;
186:
187: wc.lpszClassName = "MainClass";
188: wc.lpfnWndProc = (WNDPROC)MainWndProc;
189: wc.style = NULL;
190: wc.cbClsExtra = 4;
191: wc.cbWndExtra = 0;
192: wc.hInstance = hInstance;
193: wc.hIcon = LoadIcon(hInstance, "DocIcon");
194: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
195: wc.hbrBackground = GetStockObject(WHITE_BRUSH);
196: wc.lpszMenuName = "MainMenu";
197:
198: if (!RegisterClass(&wc))
199: return FALSE;
200:
201: wc.lpszClassName = "ObjClass";
202: wc.lpfnWndProc = (WNDPROC)ObjWndProc;
203: wc.hIcon = NULL;
204: wc.cbWndExtra = cbWindExtra;
205: wc.lpszMenuName = NULL;
206: wc.hCursor = LoadCursor(NULL, IDC_CROSS);
207:
208: if (!RegisterClass(&wc))
209: return FALSE;
210:
211: return TRUE;
212: }
213:
214:
215:
216: /* InitInstance
217: * ------------
218: *
219: * Create brushes used by the program, the main window, and
220: * do any other per-instance initialization.
221: *
222: * HANDLE hInstance
223: *
224: * RETURNS: TRUE if successful
225: * FALSE otherwise.
226: *
227: * CUSTOMIZATION: Re-implement
228: *
229: */
230: static BOOL InitInstance (HANDLE hInstance)
231: {
232: LONG rglColor [chbrMax] =
233: {
234: 0x000000ff, // Red
235: 0x0000ff00, // Green
236: 0x00ff0000, // Blue
237: 0x00ffffff, // White
238: 0x00808080, // Gray
239: 0x00ffff00, // Cyan
240: 0x00ff00ff, // Magenta
241: 0x0000ffff // Yellow
242: };
243:
244:
245: INT iColor;
246:
247: hInst = hInstance;
248:
249: // Initialize the method tables.
250: InitVTbls ();
251:
252: // Initialize the brushes used.
253: for (iColor = 0; iColor < chbrMax; iColor++)
254: hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]);
255:
256: // Register clipboard formats.
257: cfObjectLink= RegisterClipboardFormat ("ObjectLink");
258: cfOwnerLink = RegisterClipboardFormat ("OwnerLink");
259: cfNative = RegisterClipboardFormat ("Native");
260:
261: hAccelTable = LoadAccelerators(hInst, "Accelerators");
262: // hMainMenu = LoadMenu(hInst, "MainMenu");
263:
264:
265: hwndMain = CreateWindow(
266: "MainClass",
267: szAppName,
268: WS_OVERLAPPEDWINDOW,
269: CW_USEDEFAULT, CW_USEDEFAULT,
270: 3*OBJECT_WIDTH, 3*OBJECT_HEIGHT,
271: NULL,
272: NULL,
273: hInstance,
274: NULL
275: );
276:
277:
278: if (!hwndMain)
279: return FALSE;
280:
281: szClient[0] = NULL;
282: lstrcpy (szClientDoc, "Client Document");
283:
284: // Initialize global variables with LOGPIXELSX and LOGPIXELSY
285:
286: return TRUE;
287:
288: }
289:
290:
291:
292: /* DeleteInstance
293: * --------------
294: *
295: * Deallocate the VTables, and the brushes created for this instance
296: *
297: *
298: * CUSTOMIZATION: The call to FreeVTbls must remain.
299: *
300: */
301: static VOID DeleteInstance (VOID)
302: {
303: INT i;
304:
305: for (i = 0; i < chbrMax; i++)
306: DeleteObject (hbrColor[i]);
307:
308: }
309:
310:
311:
312: /* ExitApplication
313: * ---------------
314: *
315: * Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages.
316: *
317: * RETURNS: TRUE if application should really terminate
318: * FALSE if not
319: *
320: *
321: * CUSTOMIZATION: None
322: *
323: */
324: static BOOL ExitApplication (BOOL fUpdateLater)
325: {
326:
327: if (fUpdateLater)
328: {
329: // The non-standard OLE client did not accept the update
330: // when we requested it, so we are sending the client
331: // OLE_CLOSED now that we are closing the document.
332: SendDocMsg (OLE_CLOSED);
333: }
334:
335: if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE)
336: Wait (&fWaitingForSrvrRelease);
337: /* SrvrRelease will not necessarily post a WM_QUIT message.
338: If the document is not embedded, SrvrRelease by itself does
339: not cause the application to terminate. But now we want it to.
340: */
341: if (docMain.doctype != doctypeEmbedded)
342: PostQuitMessage(0);
343: SaveDimensions();
344: return TRUE;
345: }
346:
347:
348:
349: /* MainWndProc
350: * -----------
351: *
352: * Main window message handler.
353: *
354: *
355: * CUSTOMIZATION: Remove the color menu and the object menu entirely.
356: * Add handlers for your application's menu items and any
357: * Windows messages your application needs to handle.
358: * The handlers for the menu items that involve OLE
359: * can be added to, but no logic should be removed.
360: *
361: *
362: */
363: LONG APIENTRY MainWndProc
364: (HWND hwnd, UINT message, DWORD wParam, LONG lParam )
365: {
366: LPOBJ lpobj;
367:
368: switch (message)
369: {
370: case WM_COMMAND:
371: {
372: WORD wID = LOWORD(wParam);
373:
374: if (fWaitingForDocRelease)
375: {
376: ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
377: return NULL;
378: }
379:
380: switch (wID)
381: {
382: case IDM_EXIT:
383: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
384: break;
385:
386: case IDM_ABOUT:
387: DialogBox(hInst, "AboutBox", hwnd, (DLGPROC)About);
388: break;
389:
390: case IDM_NEW:
391: {
392: BOOL fUpdateLater;
393: OLESTATUS olestatus;
394:
395: if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
396: break;
397: else if (fUpdateLater)
398: SendDocMsg (OLE_CLOSED);
399:
400: // We want to revoke the doc but not the server, so if
401: // SrvrRelease is called, do not revoke server.
402: fRevokeSrvrOnSrvrRelease = FALSE;
403:
404: if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
405: {
406: ErrorBox ("Serious Error: Cannot revoke document.");
407: break;
408: }
409: else if (olestatus == OLE_WAIT_FOR_RELEASE)
410: Wait (&fWaitingForDocRelease);
411:
412: fRevokeSrvrOnSrvrRelease = TRUE;
413:
414: if (!CreateNewDoc (NULL, "(Untitled)", doctypeNew))
415: {
416: ErrorBox ("Serious Error: Cannot create new document.");
417: break;
418: }
419: // Your application need not create a default object.
420: CreateNewObj (FALSE);
421: EmbeddingModeOff();
422: break;
423: }
424: case IDM_OPEN:
425: OpenDoc();
426: UpdateObjMenus();
427: break;
428:
429: case IDM_SAVE:
430: SaveDoc();
431: break;
432:
433: case IDM_SAVEAS:
434: if (!SaveDocAs ())
435: break;
436: if (docMain.doctype != doctypeEmbedded)
437: EmbeddingModeOff();
438: break;
439:
440: case IDM_UPDATE:
441: switch (OleSavedServerDoc (docMain.lhdoc))
442: {
443: case OLE_ERROR_CANT_UPDATE_CLIENT:
444: if (!FailedUpdate(hwnd))
445: ExitApplication(TRUE);
446: break;
447: case OLE_OK:
448: break;
449: default:
450: ErrorBox ("Serious Error: Cannot update.");
451: }
452: break;
453:
454: /* Color menu */
455:
456: case IDM_RED:
457: case IDM_GREEN:
458: case IDM_BLUE:
459: case IDM_WHITE:
460: case IDM_GRAY:
461: case IDM_CYAN:
462: case IDM_MAGENTA:
463: case IDM_YELLOW:
464: lpobj = SelectedObject();
465: lpobj->native.idmColor = wID;
466: // Recolor the object on the screen.
467: InvalidateRect (lpobj->hwnd, (LPRECT)NULL, TRUE);
468: UpdateWindow (lpobj->hwnd);
469: fDocChanged = TRUE;
470: if (docMain.doctype == doctypeFromFile)
471: // If object is linked, update it in client now.
472: SendObjMsg (lpobj, OLE_CHANGED);
473: break;
474:
475: /* Edit menu */
476:
477: case IDM_COPY:
478: CutOrCopyObj (TRUE);
479: break;
480:
481: case IDM_CUT:
482: CutOrCopyObj (FALSE);
483: // Fall through.
484:
485: case IDM_DELETE:
486: RevokeObj (SelectedObject());
487: DestroyWindow (SelectedObjectWindow());
488: UpdateObjMenus();
489: break;
490:
491: /* Object menu */
492:
493: case IDM_NEXTOBJ:
494: lpobj = SelectedObject();
495: /* The 1 in the second parameter puts the current window
496: at the bottom of the current window list. */
497: SetWindowPos(lpobj->hwnd, (HANDLE)1, 0,0,0,0,
498: SWP_NOMOVE | SWP_NOSIZE);
499: break;
500:
501: case IDM_NEWOBJ:
502: lpobj = CreateNewObj (TRUE);
503: BringWindowToTop(lpobj->hwnd);
504: break;
505:
506: default:
507: ErrorBox ("Unknown Command.");
508: break;
509: }
510: break;
511: }
512:
513: case WM_NCCALCSIZE:
514: if (!IsIconic(hwnd) && !IsZoomed(hwnd))
515: {
516: dimsCurrent.nX = ((LPRECT)lParam)->left;
517: dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX;
518: dimsCurrent.nY = ((LPRECT)lParam)->top;
519: dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY;
520: }
521: return DefWindowProc(hwnd, message, wParam, lParam);
522: break;
523:
524: case WM_QUERYENDSESSION:
525: {
526: BOOL fUpdateLater;
527:
528: if (SaveChangesOption(&fUpdateLater) == IDCANCEL)
529: return FALSE;
530:
531: if (fUpdateLater)
532: {
533: // The non-standard OLE client did not accept the update
534: // when we requested it, so we are sending the client
535: // OLE_CLOSED now that we are closing the document.
536: SendDocMsg (OLE_CLOSED);
537: }
538: return TRUE;
539: }
540:
541: case WM_CLOSE:
542: {
543: BOOL fUpdateLater;
544:
545: if (SaveChangesOption(&fUpdateLater) != IDCANCEL)
546: ExitApplication(fUpdateLater);
547: break;
548: }
549:
550: default:
551: return DefWindowProc(hwnd, message, wParam, lParam);
552: }
553: return NULL;
554: }
555:
556:
557:
558: /* About
559: * -----
560: *
561: * "About Box" dialog handler.
562: *
563: * CUSTOMIZATION: None
564: *
565: */
566: BOOL APIENTRY About (HWND hDlg, UINT message, DWORD wParam, LONG lParam)
567: {
568: switch (message)
569: {
570: case WM_INITDIALOG:
571: return TRUE;
572:
573: case WM_COMMAND:
574: {
575: WORD wID = LOWORD(wParam);
576:
577: if (wID == IDOK || wID == IDCANCEL)
578: {
579: EndDialog(hDlg, TRUE);
580: return TRUE;
581: }
582: break;
583: }
584: }
585: return FALSE;
586: }
587:
588:
589:
590:
591: /* ObjWndProc
592: * ----------
593: *
594: * Message handler for the object windows.
595: *
596: *
597: * CUSTOMIZATION: Server Demo specific
598: *
599: */
600: LONG APIENTRY ObjWndProc
601: (HWND hwnd, UINT message, DWORD wParam, LONG lParam)
602: {
603: static BOOL fCapture = FALSE;
604: static struct {RECT rect; POINT pt;} drag;
605: static RECT rectMain;
606:
607: switch (message)
608: {
609: case WM_CREATE:
610: {
611: LPOBJ lpobj;
612: LPCREATESTRUCT lpcs;
613: // The call to CreateWindow puts lpobj into lpCreateParams
614: lpcs = (LPCREATESTRUCT) lParam;
615: lpobj = (LPOBJ) lpcs->lpCreateParams;
616: // Associate the window just created with the object.
617: lpobj->hwnd = hwnd;
618: /* Store pointer to object in the window structure. */
619: SetWindowLong(hwnd, ibLpobj, (LONG) lpobj);
620: UpdateObjMenus ();
621: break;
622: }
623: case WM_SIZE:
624: {
625: RECT rect;
626: if (fWaitingForDocRelease)
627: {
628: ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
629: return NULL;
630: }
631: // Get coordinates of object relative to main window's client area.
632: GetWindowRect (hwnd, (LPRECT)&rect);
633: ScreenToClient (hwndMain, (LPPOINT)&rect);
634: ScreenToClient (hwndMain, (LPPOINT)&rect.right);
635: SizeObj (hwnd, rect, TRUE);
636: // Fall through.
637: }
638: case WM_PAINT:
639: PaintObj (hwnd);
640: break;
641:
642: case WM_LBUTTONDOWN:
643: if (fWaitingForDocRelease)
644: {
645: ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
646: return NULL;
647: }
648: BringWindowToTop (hwnd);
649:
650: GetWindowRect (hwnd, (LPRECT) &drag.rect);
651: ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left);
652: ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right);
653:
654: drag.pt.x = LOWORD(lParam);
655: drag.pt.y = HIWORD(lParam);
656:
657: // Convert drag.pt to the main window's client coordinates.
658: ClientToScreen (hwnd, (LPPOINT)&drag.pt);
659: ScreenToClient (hwndMain, (LPPOINT)&drag.pt);
660:
661: // Remember the coordinates of the main window so we do not drag
662: // an object outside the main window.
663: GetClientRect (hwndMain, (LPRECT) &rectMain);
664:
665: SetCapture (hwnd);
666: fCapture = TRUE;
667: break;
668:
669: case WM_MOUSEMOVE:
670: {
671: HDC hdc;
672: POINT pt;
673:
674: if (!fCapture)
675: break;
676:
677: fDocChanged = TRUE;
678: pt.x = LOWORD(lParam);
679: pt.y = HIWORD(lParam);
680:
681: // Convert pt to the main window's client coordinates.
682: ClientToScreen (hwnd, (LPPOINT)&pt);
683: ScreenToClient (hwndMain, (LPPOINT)&pt);
684:
685: if (!PtInRect (&rectMain, pt))
686: break;
687:
688: hdc = GetDC(hwndMain);
689:
690: // Erase old drag rectangle
691: InvertRect (hdc, (LPRECT)&drag.rect);
692:
693: // Update drag.rect
694: OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y);
695:
696: // Update drag.pt
697: drag.pt.x = pt.x;
698: drag.pt.y = pt.y;
699:
700: // Show new drag rectangle
701: InvertRect (hdc, (LPRECT)&drag.rect);
702: ReleaseDC (hwndMain, hdc);
703: break;
704: }
705:
706: case WM_LBUTTONUP:
707: {
708: LPOBJ lpobj;
709: if (!fCapture)
710: return TRUE;
711:
712: fCapture = FALSE;
713: ReleaseCapture ();
714:
715: MoveWindow (hwnd, drag.rect.left, drag.rect.top,
716: drag.rect.right - drag.rect.left,
717: drag.rect.bottom - drag.rect.top, TRUE);
718: InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
719: lpobj = HwndToLpobj (hwnd);
720: lpobj->native.nX = drag.rect.left;
721: lpobj->native.nY = drag.rect.top;
722: break;
723: }
724: case WM_DESTROY:
725: DestroyObj (hwnd);
726: return DefWindowProc(hwnd, message, wParam, lParam);
727:
728: default:
729: return DefWindowProc(hwnd, message, wParam, lParam);
730: }
731: return NULL;
732: }
733:
734:
735:
736: /* DeviceToHiMetric
737: * ----------------
738: *
739: * Converts a point from device units to HiMetric units.
740: * This function is designed to be generic enough to be reused.
741: *
742: * HWND hwnd - The window whose display context is to be used
743: * LPPOINT lppt - The point to be converted.
744: *
745: * CUSTOMIZATION: None
746: *
747: */
748: VOID DeviceToHiMetric (HWND hwnd, LPPOINT lppt)
749: {
750: HDC hdc = GetDC(hwnd);
751:
752: SetMapMode(hdc, MM_HIMETRIC);
753: DPtoLP (hdc, lppt, 1);
754:
755: lppt->y *= -1;
756:
757: ReleaseDC(hwnd,hdc);
758:
759: }
760:
761:
762: /* UpdateFileMenu
763: * --------------
764: *
765: * Updates the "Update <Client doc>" and "Exit & Return to <Client doc>"
766: * with the currently set client document name
767: *
768: * CUSTOMIZATION: Re-implement
769: *
770: */
771: VOID UpdateFileMenu (INT iSaveUpdateId)
772: {
773: CHAR str[cchFilenameMax];
774: HMENU hMenu = GetMenu(hwndMain);
775:
776: /* Change File menu so it contains "Update" instead of "Save". */
777:
778: lstrcpy (str, "&Update ");
779: lstrcat (str, szClientDoc);
780: ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str);
781:
782: /* Change File menu so it contains "Exit & Return to <client doc>" */
783: /* instead of just "Exit" */
784:
785: lstrcpy (str, "E&xit && Return to ");
786: lstrcat (str, szClientDoc);
787: ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str);
788: }
789:
790:
791:
792: /* EmbeddingModeOn
793: * ---------------
794: *
795: * Do whatever is necessary for the application to start "embedding mode."
796: *
797: * CUSTOMIZATION: Re-implement
798: *
799: */
800: VOID EmbeddingModeOn(VOID)
801: {
802: HMENU hMenu = GetMenu(hwndMain);
803:
804: UpdateFileMenu (IDM_SAVE);
805:
806: /* Change File menu so it contains "Save Copy As..." instead of */
807: /* "Save As..." */
808: ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
809: "Save Copy As..");
810:
811: /* In embedded mode, the user can edit only the embedded object, not
812: create new ones. */
813: EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED);
814: EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
815: EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
816: DrawMenuBar (hwndMain);
817: }
818:
819:
820:
821:
822: /* EmbeddingModeOff
823: * ----------------
824: *
825: * Do whatever is necessary for the application to end "embedding mode."
826: *
827: * CUSTOMIZATION: Re-implement
828: *
829: */
830: VOID EmbeddingModeOff (VOID)
831: {
832: HMENU hMenu = GetMenu(hwndMain);
833:
834: /* Change File menu so it contains "Save" instead of "Update". */
835: ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save");
836: /* Change File menu so it contains "Exit & Return to <client doc>" */
837: /* instead of just "Exit" */
838: ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit");
839:
840: /* Change File menu so it contains "Save As..." instead of */
841: /* "Save Copy As..." */
842: ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
843: "Save As..");
844:
845: /* In non-embedded mode, the user can create new objects. */
846: EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED);
847:
848: lstrcpy (szClientDoc, "Client Document");
849: DrawMenuBar (hwndMain);
850: }
851:
852:
853:
854: /* ErrorBox
855: * --------
856: *
857: * char *szMessage - String to display inside message box.
858: *
859: * CUSTOMIZATION: Server Demo specific
860: *
861: */
862: VOID ErrorBox (CHAR *szMessage)
863: {
864: MessageBox (hwndMain, szMessage, szAppName, MB_OK);
865: }
866:
867:
868:
869: /* GetWord
870: * -------
871: *
872: * LPSTR *plpszSrc - Pointer to a pointer to a source string
873: * LPSTR lpszDst - Pointer to destination buffer
874: *
875: * Will copy one space-terminated or null-terminated word from the source
876: * string to the destination buffer.
877: * When done, *plpszSrc will point to the character after the word.
878: *
879: * CUSTOMIZATION: Server Demo specific
880: *
881: */
882: static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst)
883: {
884: INT i = 0;
885: while (**plpszSrc && **plpszSrc != ' ')
886: {
887: lpszDst[i++] = *(*plpszSrc)++;
888: }
889: lpszDst[i] = '\0';
890: }
891:
892:
893:
894: /* HiMetricToDevice
895: * ----------------
896: *
897: * Converts a point from HiMetric units to device units.
898: * This function is designed to be generic enough to be reused.
899: *
900: * HWND hwnd - The window whose display context is to be used
901: * LPPOINT lppt - The point to be converted.
902: *
903: * CUSTOMIZATION: None
904: *
905: */
906: VOID HiMetricToDevice (HWND hwnd, LPPOINT lppt)
907: {
908: HDC hdc = GetDC(hwnd);
909:
910: SetMapMode(hdc, MM_HIMETRIC);
911:
912: LPtoDP (hdc, lppt, 1);
913:
914: ReleaseDC(hwnd,hdc);
915: }
916:
917:
918:
919: /* HwndToLpobj
920: * -----------
921: *
922: * Given an object's window, return a pointer to the object.
923: * The GetWindowLong call extracts an LPOBJ from the extra data stored with
924: * the window.
925: *
926: * HWND hwndObj - Handle to the object's window
927: *
928: * RETURNS: A pointer to the object
929: *
930: * CUSTOMIZATION: Server Demo specific
931: *
932: */
933: LPOBJ HwndToLpobj (HWND hwndObj)
934: {
935: return (LPOBJ) GetWindowLong (hwndObj, ibLpobj);
936: }
937:
938:
939:
940: /* CreateUntitledDoc
941: * -----------------
942: *
943: * Create a fresh document with one object.
944: *
945: * RETURNS: TRUE if successful
946: * FALSE otherwise
947: *
948: * CUSTOMIZATION: Re-implement
949: *
950: */
951: static BOOL CreateUntitledDoc (INT nCmdShow)
952: {
953: if (!CreateNewDoc (NULL, "(Untitled)", doctypeNew))
954: return FALSE;
955: CreateNewObj (FALSE);
956: ShowWindow(hwndMain, nCmdShow);
957: UpdateWindow(hwndMain);
958: return TRUE;
959: }
960:
961:
962: /* ProcessCmdLine
963: * --------------
964: *
965: * Parses the Windows command line which was passed to WinMain.
966: *
967: * Case One: SrvrDemo.exe
968: * fEmbedding = FALSE
969: * Create an untitled document.
970: *
971: * Case two: SrvrDemo.exe filename
972: * fEmbedding = FALSE
973: * Create a new document from the file.
974: *
975: * Case three: SrvrDemo.exe -Embedding
976: * fEmbedding = TRUE
977: * Do not create or register a document.
978: * Do not show window until client requests it.
979: *
980: * Case four: SrvrDemo.exe -Embedding filename
981: * fEmbedding = TRUE
982: * Load file.
983: * Call OleRegisterServerDoc.
984: * Do not show window until client requests it.
985: *
986: *
987: * LPSTR lpszLine - The Windows command line
988: * int nCmdShow - Parameter to WinMain
989: * HWND hwndMain - The application's main window
990: *
991: * RETURNS: TRUE if the command line was processed correctly.
992: * FALSE if a filename was specified which did not
993: * contain a proper document.
994: *
995: * CUSTOMIZATION: None.
996: *
997: */
998:
999: static BOOL ProcessCmdLine (LPSTR lpszLine, HWND hwndMain)
1000: {
1001: CHAR szBuf[cchFilenameMax];
1002: BOOL fEmbedding = FALSE; // Is "-Embedding" on the command line?
1003: INT i=0;
1004: OFSTRUCT of;
1005:
1006: if (!*lpszLine) // No filename or options, so start a fresh document.
1007: {
1008: return CreateUntitledDoc(SW_SHOWNORMAL);
1009: }
1010:
1011: SkipBlanks (&lpszLine);
1012:
1013: // Check for "-Embedding" or "/Embedding" and set fEmbedding.
1014: if(*lpszLine == '-' || *lpszLine == '/')
1015: {
1016: lpszLine++;
1017: GetWord (&lpszLine, szBuf);
1018: fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag);
1019: }
1020:
1021: SkipBlanks (&lpszLine);
1022:
1023: if (*lpszLine) // if there is a filename
1024: {
1025: // Put filename into szBuf.
1026: GetWord (&lpszLine, szBuf);
1027:
1028: if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST))
1029: {
1030: // File not found
1031: if (fEmbedding)
1032: return FALSE;
1033: else
1034: {
1035: CHAR sz[100];
1036: wsprintf (sz, "File %s not found.", (LPSTR) szBuf);
1037: ErrorBox (sz);
1038: return CreateUntitledDoc(SW_SHOWNORMAL);
1039: }
1040: }
1041:
1042: if (!CreateDocFromFile (szBuf, NULL, doctypeFromFile))
1043: {
1044: // File not in proper format.
1045: if (fEmbedding)
1046: return FALSE;
1047: else
1048: {
1049: CHAR sz[100];
1050: wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf);
1051: ErrorBox (sz);
1052: return CreateUntitledDoc(SW_SHOWNORMAL);
1053: }
1054: }
1055: }
1056:
1057: if (fEmbedding)
1058: {
1059: /* Do not show window until told to do so by client. */
1060: ShowWindow(hwndMain, SW_HIDE);
1061: }
1062: else
1063: {
1064: ShowWindow(hwndMain, SW_SHOWNORMAL);
1065: UpdateWindow(hwndMain);
1066: }
1067: return TRUE;
1068: }
1069:
1070:
1071:
1072: /* SaveDimensions
1073: * --------------
1074: *
1075: * Save the dimensions of the main window in a private profile file.
1076: *
1077: * CUSTOMIZATION: This function may be removed. If you wish to support
1078: * intelligent window placement, then the only necessary
1079: * change is to change the string "SrvrDemo.Ini" to a filename
1080: * appropriate for your application.
1081: */
1082: static VOID SaveDimensions (VOID)
1083: {
1084: if ((dimsCurrent.nX != dimsSaved.nX) ||
1085: (dimsCurrent.nY != dimsSaved.nY) ||
1086: (dimsCurrent.nWidth != dimsSaved.nWidth) ||
1087: (dimsCurrent.nHeight != dimsSaved.nHeight) )
1088: {
1089: // Save current window dimensions to private profile.
1090: CHAR szBuf[7];
1091: wsprintf (szBuf, "%d", dimsCurrent.nX);
1092: WritePrivateProfileString
1093: (szAppName, "x", szBuf, "SrvrDemo.Ini");
1094: wsprintf (szBuf, "%d", dimsCurrent.nY);
1095: WritePrivateProfileString
1096: (szAppName, "y", szBuf, "SrvrDemo.Ini");
1097: wsprintf (szBuf, "%d", dimsCurrent.nWidth);
1098: WritePrivateProfileString
1099: (szAppName, "w", szBuf, "SrvrDemo.Ini");
1100: wsprintf (szBuf, "%d", dimsCurrent.nHeight);
1101: WritePrivateProfileString
1102: (szAppName, "h", szBuf, "SrvrDemo.Ini");
1103: }
1104: }
1105:
1106:
1107:
1108: /* SelectedObject
1109: * --------------
1110: *
1111: * Return a pointer to the currently selected object.
1112: *
1113: * CUSTOMIZATION: What a "selected object" is will vary from application
1114: * to application. You may find it useful to have a function
1115: * like this. In your application it may be necessary to
1116: * actually create an OBJ structure based on what data the
1117: * user has selected from the document (by highlighting some
1118: * text for example).
1119: *
1120: */
1121: LPOBJ SelectedObject (VOID)
1122: {
1123: return HwndToLpobj (SelectedObjectWindow());
1124: }
1125:
1126:
1127:
1128:
1129: /* SelectedObjectWindow
1130: * --------------------
1131: *
1132: * Return a handle to the window for the currently selected object.
1133: * The GetWindow calls returns a handle to the main window's first child,
1134: * which is the selected object's window.
1135: *
1136: * CUSTOMIZATION: Server Demo specific
1137: *
1138: */
1139: HWND SelectedObjectWindow (VOID)
1140: {
1141: return GetWindow (hwndMain, GW_CHILD);
1142: }
1143:
1144:
1145:
1146: /* SetHiMetricFields
1147: * -----------------
1148: *
1149: * Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure
1150: * so that they are equivalent to the nWidth and nHeight fields.
1151: * The negative sign in the last line is necessary because the positive
1152: * y direction is toward the top of the screen in MM_HIMETRIC mode.
1153: *
1154: * LPOBJ lpobj - Pointer to the object whose native data will be adjusted
1155: *
1156: * CUSTOMIZATION: Server Demo specific, although you may need a function like
1157: * this if you keep track of the size of an object, and an
1158: * object handler needs to know the object's size in
1159: * HiMetric units.
1160: *
1161: *
1162: */
1163: VOID SetHiMetricFields (LPOBJ lpobj)
1164: {
1165: POINT pt;
1166:
1167: pt.x = lpobj->native.nWidth;
1168: pt.y = lpobj->native.nHeight;
1169: DeviceToHiMetric (hwndMain, &pt);
1170: lpobj->native.nHiMetricWidth = pt.x;
1171: lpobj->native.nHiMetricHeight = pt.y;
1172: }
1173:
1174:
1175:
1176: /* SkipBlanks
1177: * ----------
1178: *
1179: * LPSTR *plpsz - Pointer to a pointer to a character
1180: *
1181: * Increment *plpsz past any blanks in the character string.
1182: * This function is used in ProcessCmdLine.
1183: *
1184: */
1185: static VOID SkipBlanks (LPSTR *plpsz)
1186: {
1187: while (**plpsz && **plpsz == ' ')
1188: (*plpsz)++;
1189: }
1190:
1191:
1192:
1193: /* UpdateObjMenus
1194: * ---------------
1195: *
1196: * Grey or Ungrey menu items depending on the existence of at least one
1197: * object in the document.
1198: *
1199: * CUSTOMIZATION: Server Demo specific
1200: *
1201: */
1202: static VOID UpdateObjMenus (VOID)
1203: {
1204: static BOOL fObjMenusEnabled = TRUE;
1205: BOOL fOneObjExists; // Does at least one object exist?
1206: WORD wEnable;
1207: HMENU hMenu;
1208:
1209: fOneObjExists = (SelectedObjectWindow() != NULL);
1210: if (fOneObjExists == fObjMenusEnabled)
1211: {
1212: // Nothing has changed.
1213: return;
1214: }
1215:
1216: wEnable = (WORD)(fOneObjExists ? MF_ENABLED : MF_GRAYED);
1217:
1218: hMenu = GetMenu(hwndMain);
1219: EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);
1220:
1221: hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);
1222: EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable);
1223: EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);
1224:
1225: hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);
1226: EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable);
1227: EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable);
1228: EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable);
1229:
1230: hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);
1231: EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);
1232:
1233: DrawMenuBar (hwndMain);
1234: fObjMenusEnabled = fOneObjExists;
1235: }
1236:
1237:
1238:
1239: /* Wait
1240: * ----
1241: *
1242: * Dispatch messages until the given flag is set to FALSE.
1243: * One use of this function is to wait until a Release method is called
1244: * after a function has returned OLE_WAIT_FOR_RELEASE.
1245: *
1246: * BOOL *pf - Pointer to the flag being waited on.
1247: *
1248: * CUSTOMIZATION: The use of OleUnblockServer is for illustration only.
1249: * Since Server Demo does not call OleBlockServer, there
1250: * will never be any messages in the OLE queue.
1251: *
1252: */
1253: VOID Wait (BOOL *pf)
1254: {
1255: MSG msg;
1256: BOOL fMoreMsgs = FALSE;
1257:
1258: *pf = TRUE;
1259: while (*pf==TRUE)
1260: {
1261: OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
1262: if (!fMoreMsgs)
1263: // if there are no more messages in the OLE queue, go to system queue
1264: {
1265: if (GetMessage (&msg, NULL, NULL, NULL))
1266: {
1267: TranslateMessage (&msg);
1268: DispatchMessage (&msg);
1269: }
1270: }
1271: }
1272: }
1273:
1274: static BOOL FailedUpdate(HWND hwnd)
1275: {
1276:
1277: return(DialogBox(hInst, "FailedUpdate", hwnd, (DLGPROC)fnFailedUpdate));
1278:
1279: }
1280:
1281: BOOL APIENTRY fnFailedUpdate (HWND hDlg, UINT message, DWORD wParam, LONG lParam)
1282: {
1283:
1284: switch (message)
1285: {
1286: case WM_COMMAND:
1287: {
1288: WORD wID = LOWORD(wParam);
1289:
1290: switch (wID)
1291: {
1292: case IDCANCEL:
1293: case IDD_CONTINUEEDIT:
1294: EndDialog(hDlg, TRUE);
1295: break;
1296:
1297: case IDD_UPDATEEXIT:
1298: EndDialog(hDlg, FALSE);
1299: break;
1300:
1301: default:
1302: break;
1303: }
1304: break;
1305: }
1306:
1307: case WM_INITDIALOG:
1308: {
1309: CHAR szMsg[200];
1310:
1311: szMsg[0] = NULL;
1312:
1313: wsprintf(
1314: szMsg,
1315: "This %s document can only be updated when you exit %s.",
1316: (LPSTR) szClient,
1317: (LPSTR) szAppName
1318: );
1319:
1320: SetDlgItemText(hDlg, IDD_TEXT, szMsg);
1321: return TRUE;
1322: }
1323:
1324: default:
1325: break;
1326: }
1327:
1328: return FALSE;
1329: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.