|
|
1.1 root 1: /****************************************************************************
2:
3: PROGRAM: Server.c
4:
5: PURPOSE: Server template for Windows applications
6:
7: FUNCTIONS:
8:
9: WinMain() - calls initialization function, processes message loop
10: InitApplication() - initializes window data and registers window
11: InitInstance() - saves instance handle and creates main window
12: MainWndProc() - processes messages
13: About() - processes messages for "About" dialog box
14:
15: COMMENTS:
16:
17: Windows can have several copies of your application running at the
18: same time. The variable hInst keeps track of which instance this
19: application is so that processing will be to the correct window.
20:
21: ****************************************************************************/
22:
23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include "server.h" /* specific to this program */
27: #include "huge.h"
28:
29: DWORD idInst = 0;
30: CONVCONTEXT CCFilter = { sizeof(CONVCONTEXT), 0, 0, 0, 0L, 0L };
31: HANDLE hInst; /* current instance */
32: HWND hwndServer;
33: RECT rcRand;
34: RECT rcCount;
35: RECT rcComment;
36: RECT rcExec;
37: RECT rcConnCount;
38: RECT rcRndrDelay;
39: RECT rcRunaway;
40: RECT rcAllBlock;
41: RECT rcNextAction;
42: RECT rcHugeSize;
43: RECT rcAppowned;
44: BOOL fAllBlocked = FALSE;
45: BOOL fAllEnabled = TRUE;
46: BOOL fEnableOneCB = FALSE;
47: BOOL fBlockNextCB = FALSE;
48: BOOL fTermNextCB = FALSE;
49: BOOL fAppowned = FALSE;
50: WORD cRunaway = 0;
51: WORD RenderDelay = 0;
52: DWORD count = 0;
53: WORD seed = 0;
54: HSZ hszAppName = 0;
55: CHAR szClass[] = "ServerWClass";
56: CHAR szTopic[MAX_TOPIC] = "Test";
57: CHAR szServer[MAX_TOPIC] = "Server";
58: CHAR szComment[MAX_COMMENT] = "";
59: CHAR szExec[MAX_EXEC] = "";
60: CHAR *pszComment = szComment;
61: WORD cyText;
62: WORD cServers = 0;
63: HDDEDATA hDataHelp[CFORMATS] = {0};
64: HDDEDATA hDataCount[CFORMATS] = {0};
65: HDDEDATA hDataRand[CFORMATS] = {0};
66: HDDEDATA hDataHuge[CFORMATS] = {0};
67: DWORD cbHuge = 0;
68:
69: char szDdeHelp[] = "DDEML test server help:\r\n\n"\
70: "The 'Server'(service) and 'Test'(topic) names may change.\r\n\n"\
71: "Items supported under the 'Test' topic are:\r\n"\
72: "\tCount:\tThis value increments on each data change.\r\n"\
73: "\tRand:\tThis value is randomly generated each data change.\r\n"\
74: "\tHuge:\tThis is randomlly generated text data >64k that the\r\n"\
75: "\t\tDDEML test client can verify.\r\n"\
76: "The above items change after any request if in Runaway mode and \r\n"\
77: "can bo POKEed in order to change their values. POKEed Huge data \r\n"\
78: "must be in a special format to verify the correctness of the data \r\n"\
79: "or it will not be accepted.\r\n"\
80: "If the server is set to use app owned data handles, all data sent \r\n"\
81: "uses HDATA_APPOWNED data handles."\
82: ;
83:
84: FORMATINFO aFormats[CFORMATS] = {
85: { 0, "CF_TEXT" }, // exception! predefined format
86: { 0, "Dummy1" },
87: { 0, "Dummy2" },
88: };
89:
90:
91: /*
92: * Topic and Item tables supported by this application.
93: */
94:
95: /* HSZ PROCEDURE PSZ */
96:
97: ITEMLIST SystemTopicItemList[CSYSTEMITEMS] = {
98:
99: { 0, TopicListXfer, SZDDESYS_ITEM_TOPICS },
100: { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS },
101: { 0, sysFormatsXfer, SZDDESYS_ITEM_FORMATS },
102: { 0, HelpXfer, SZDDESYS_ITEM_HELP},
103: };
104:
105:
106: ITEMLIST TestTopicItemList[CTESTITEMS] = {
107:
108: { 0, TestRandomXfer, "Rand" }, // 0 index
109: { 0, TestCountXfer, "Count"}, // 1 index
110: { 0, TestHugeXfer, "Huge" }, // 2 index
111: { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS }, // 3 index
112: };
113:
114:
115: /* The system topic is always assumed to be first. */
116: /* HSZ PROCEDURE #ofITEMS PSZ */
117: TOPICLIST topicList[CTOPICS] = {
118:
119: { 0, SystemTopicItemList, CSYSTEMITEMS, SZDDESYS_TOPIC}, // 0 index
120: { 0, TestTopicItemList, CTESTITEMS, szTopic}, // 1 index
121: };
122:
123:
124:
125:
126:
127:
128: /****************************************************************************
129:
130: FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
131:
132: PURPOSE: calls initialization function, processes message loop
133:
134: COMMENTS:
135:
136: Windows recognizes this function by name as the initial entry point
137: for the program. This function calls the application initialization
138: routine, if no other instance of the program is running, and always
139: calls the instance initialization routine. It then executes a message
140: retrieval and dispatch loop that is the top-level control structure
141: for the remainder of execution. The loop is terminated when a WM_QUIT
142: message is received, at which time this function exits the application
143: instance by returning the value passed by PostQuitMessage().
144:
145: If this function must abort before entering the message loop, it
146: returns the conventional value NULL.
147:
148: ****************************************************************************/
149:
150: int APIENTRY WinMain(
151: HANDLE hInstance,
152: HANDLE hPrevInstance,
153: LPSTR lpCmdLine,
154: int nCmdShow
155: )
156: {
157: MSG msg; /* message */
158:
159: if (!hPrevInstance) /* Other instances of app running? */
160: if (!InitApplication(hInstance)) /* Initialize shared things */
161: return (FALSE); /* Exits if unable to initialize */
162:
163: /* Perform initializations that apply to a specific instance */
164:
165: if (!InitInstance(hInstance, nCmdShow))
166: return (FALSE);
167:
168: /* Acquire and dispatch messages until a WM_QUIT message is received. */
169:
170: while (GetMessage(&msg, /* message structure */
171: 0, /* handle of window receiving the message */
172: 0, /* lowest message to examine */
173: 0)) /* highest message to examine */
174: {
175: TranslateMessage(&msg); /* Translates virtual key codes */
176: DispatchMessage(&msg); /* Dispatches message to window */
177: }
178:
179: UnregisterClass(szClass, hInstance);
180: return (msg.wParam); /* Returns the value from PostQuitMessage */
181: }
182:
183:
184: /****************************************************************************
185:
186: FUNCTION: InitApplication(HANDLE)
187:
188: PURPOSE: Initializes window data and registers window class
189:
190: COMMENTS:
191:
192: This function is called at initialization time only if no other
193: instances of the application are running. This function performs
194: initialization tasks that can be done once for any number of running
195: instances.
196:
197: In this case, we initialize a window class by filling out a data
198: structure of type WNDCLASS and calling the Windows RegisterClass()
199: function. Since all instances of this application use the same window
200: class, we only need to do this when the first instance is initialized.
201:
202:
203: ****************************************************************************/
204:
205: BOOL InitApplication(hInstance)
206: HANDLE hInstance; /* current instance */
207: {
208: WNDCLASS wc;
209:
210: /* Fill in window class structure with parameters that describe the */
211: /* main window. */
212:
213: wc.style = 0; /* Class style(s). */
214: wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */
215: /* windows of this class. */
216: wc.cbClsExtra = 0; /* No per-class extra data. */
217: wc.cbWndExtra = 0; /* No per-window extra data. */
218: wc.hInstance = hInstance; /* Application that owns the class. */
219: wc.hIcon = LoadIcon(hInstance, "server");
220: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
221: wc.hbrBackground = (HANDLE)(COLOR_APPWORKSPACE+1);
222: wc.lpszMenuName = "ServerMenu"; /* Name of menu resource in .RC file. */
223: wc.lpszClassName = "ServerWClass"; /* Name used in call to CreateWindow. */
224:
225: /* Register the window class and return success/failure code. */
226:
227: return (RegisterClass(&wc));
228:
229: }
230:
231:
232: /****************************************************************************
233:
234: FUNCTION: InitInstance(HANDLE, int)
235:
236: PURPOSE: Saves instance handle and creates main window
237:
238: COMMENTS:
239:
240: This function is called at initialization time for every instance of
241: this application. This function performs initialization tasks that
242: cannot be shared by multiple instances.
243:
244: In this case, we save the instance handle in a static variable and
245: create and display the main program window.
246:
247: ****************************************************************************/
248:
249: BOOL InitInstance(hInstance, nCmdShow)
250: HANDLE hInstance; /* Current instance identifier. */
251: INT nCmdShow; /* Param for first ShowWindow() call. */
252: {
253: INT i;
254: RECT Rect;
255: TEXTMETRIC metrics;
256: HDC hdc;
257:
258: /* Save the instance handle in static variable, which will be used in */
259: /* many subsequence calls from this application to Windows. */
260:
261: hInst = hInstance;
262:
263:
264: /* Create a main window for this application instance. */
265:
266: hwndServer = CreateWindow(
267: "ServerWClass", /* See RegisterClass() call. */
268: "Server|Test",
269: WS_OVERLAPPEDWINDOW, /* Window style. */
270: CW_USEDEFAULT, /* Default horizontal position. */
271: CW_USEDEFAULT, /* Default vertical position. */
272: 400,
273: 200,
274: NULL, /* Overlapped windows have no parent. */
275: NULL, /* Use the window class menu. */
276: hInstance, /* This instance owns this window. */
277: NULL /* Pointer not needed. */
278: );
279:
280: GetClientRect(hwndServer, (LPRECT) &Rect);
281:
282: /* If window could not be created, return "failure" */
283:
284: if (!hwndServer)
285: return (FALSE);
286:
287: hdc = GetDC(hwndServer);
288: GetTextMetrics(hdc, &metrics);
289: cyText = (WORD)(metrics.tmHeight + metrics.tmExternalLeading);
290: ReleaseDC(hwndServer, hdc);
291:
292: aFormats[0].atom = CF_TEXT; // exception - predefined.
293: for (i = 1; i < CFORMATS; i++) {
294: aFormats[i].atom = RegisterClipboardFormat(aFormats[i].sz);
295: }
296:
297: /* Make the window visible; update its client area; and return "success" */
298:
299: ShowWindow(hwndServer, nCmdShow); /* Show the window */
300: UpdateWindow(hwndServer); /* Sends WM_PAINT message */
301: seed = 1;
302: srand(1);
303: CCFilter.iCodePage = CP_WINANSI; // initial default codepage
304: if (!DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback,
305: hInstance), APPCMD_FILTERINITS, 0)) {
306: Hszize();
307: DdeNameService(idInst, hszAppName, 0, DNS_REGISTER);
308: return(TRUE);
309: }
310: return (FALSE);
311:
312: }
313:
314: /****************************************************************************
315:
316: FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
317:
318: PURPOSE: Processes messages
319:
320: MESSAGES:
321:
322: WM_COMMAND - application menu (About dialog box)
323: WM_DESTROY - destroy window
324:
325: COMMENTS:
326:
327: To process the IDM_ABOUT message, call MakeProcInstance() to get the
328: current instance address of the About() function. Then call Dialog
329: box which will create the box according to the information in your
330: server.rc file and turn control over to the About() function. When
331: it returns, free the intance address.
332:
333: ****************************************************************************/
334:
335: LONG APIENTRY MainWndProc(hWnd, message, wParam, lParam)
336: HWND hWnd; /* window handle */
337: UINT message; /* type of message */
338: WPARAM wParam; /* additional information */
339: LONG lParam; /* additional information */
340: {
341: switch (message) {
342: case WM_INITMENU:
343: if (GetMenu(hWnd) != (HMENU)wParam)
344: break;
345:
346: CheckMenuItem((HMENU)wParam, IDM_BLOCKALLCBS,
347: fAllBlocked ? MF_CHECKED : MF_UNCHECKED);
348: CheckMenuItem((HMENU)wParam, IDM_UNBLOCKALLCBS,
349: fAllEnabled ? MF_CHECKED : MF_UNCHECKED);
350: CheckMenuItem((HMENU)wParam, IDM_BLOCKNEXTCB,
351: fBlockNextCB ? MF_CHECKED : MF_UNCHECKED);
352: CheckMenuItem((HMENU)wParam, IDM_TERMNEXTCB,
353: fTermNextCB ? MF_CHECKED : MF_UNCHECKED);
354: CheckMenuItem((HMENU)wParam, IDM_RUNAWAY,
355: cRunaway ? MF_CHECKED : MF_UNCHECKED);
356: CheckMenuItem((HMENU)wParam, IDM_APPOWNED,
357: fAppowned ? MF_CHECKED : MF_UNCHECKED);
358: break;
359:
360: case WM_COMMAND: /* message: command from application menu */
361: switch (GET_WM_COMMAND_ID(wParam, lParam)) {
362: case IDM_ENABLEONECB:
363: DdeEnableCallback(idInst, 0, EC_ENABLEONE);
364: fAllBlocked = FALSE;
365: fAllEnabled = FALSE;
366: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
367: break;
368:
369: case IDM_TERMNEXTCB:
370: fTermNextCB = !fTermNextCB;
371: InvalidateRect(hwndServer, &rcNextAction, TRUE);
372: break;
373:
374: case IDM_BLOCKNEXTCB:
375: fBlockNextCB = !fBlockNextCB;
376: InvalidateRect(hwndServer, &rcNextAction, TRUE);
377: break;
378:
379: case IDM_BLOCKALLCBS:
380: DdeEnableCallback(idInst, 0, EC_DISABLE);
381: fAllBlocked = TRUE;
382: fAllEnabled = FALSE;
383: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
384: break;
385:
386: case IDM_UNBLOCKALLCBS:
387: DdeEnableCallback(idInst, 0, EC_ENABLEALL);
388: fAllEnabled = TRUE;
389: fAllBlocked = FALSE;
390: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
391: break;
392:
393: case IDM_APPOWNED:
394: fAppowned = !fAppowned;
395: if (!fAppowned) {
396: WORD iFmt;
397: for (iFmt = 0; iFmt < CFORMATS; iFmt++) {
398: if (hDataHuge[iFmt]) {
399: DdeFreeDataHandle(hDataHuge[iFmt]);
400: hDataHuge[iFmt] = 0;
401: InvalidateRect(hwndServer, &rcHugeSize, TRUE);
402: }
403: if (hDataCount[iFmt]) {
404: DdeFreeDataHandle(hDataCount[iFmt]);
405: hDataCount[iFmt] = 0;
406: }
407: if (hDataRand[iFmt]) {
408: DdeFreeDataHandle(hDataRand[iFmt]);
409: hDataRand[iFmt] = 0;
410: }
411: if (hDataHelp[iFmt]) {
412: DdeFreeDataHandle(hDataHelp[iFmt]);
413: hDataHelp[iFmt] = 0;
414: }
415: }
416: }
417: InvalidateRect(hwndServer, &rcAppowned, TRUE);
418: break;
419:
420: case IDM_RUNAWAY:
421: cRunaway = !cRunaway;
422: InvalidateRect(hwndServer, &rcRunaway, TRUE);
423: if (!cRunaway) {
424: break;
425: }
426: // fall through
427:
428: case IDM_CHANGEDATA:
429: PostMessage(hwndServer, UM_CHGDATA, 1, 0); // rand
430: PostMessage(hwndServer, UM_CHGDATA, 1, 1); // count
431: break;
432:
433: case IDM_RENDERDELAY:
434: DoDialog("VALUEENTRY", (FARPROC)RenderDelayDlgProc, 0, TRUE);
435: InvalidateRect(hwndServer, &rcRndrDelay, TRUE);
436: break;
437:
438: case IDM_SETSERVER:
439: DoDialog("VALUEENTRY", (FARPROC)SetServerDlgProc, 0, TRUE);
440: break;
441:
442: case IDM_SETTOPIC:
443: DoDialog("VALUEENTRY", (FARPROC)SetTopicDlgProc, 0, TRUE);
444: break;
445:
446: case IDM_CONTEXT:
447: DoDialog("CONTEXT", (FARPROC)ContextDlgProc, 0, TRUE);
448: break;
449:
450: case IDM_ABOUT:
451: DoDialog("ABOUT", (FARPROC)About, 0, TRUE);
452: break;
453:
454: case IDM_HELP:
455: break;
456:
457: default:
458: return (DefWindowProc(hWnd, message, wParam, lParam));
459: }
460: break;
461:
462: case WM_PAINT:
463: PaintServer(hWnd);
464: break;
465:
466: case UM_CHGDATA:
467: {
468: WORD iFmt;
469:
470: // wParam = TopicIndex,
471: // LOWORD(lParam) = ItemIndex
472: // We asynchronously do DdePostAdvise() calls to prevent infinite
473: // loops when in runaway mode.
474: if (wParam == 1) { // test topic
475: if (lParam == 0) { // rand item
476: seed = rand();
477: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
478: if (hDataRand[iFmt]) {
479: DdeFreeDataHandle(hDataRand[iFmt]);
480: hDataRand[iFmt] = 0;
481: }
482: }
483: InvalidateRect(hwndServer, &rcRand, TRUE);
484: DdePostAdvise(idInst, topicList[wParam].hszTopic,
485: (HSZ)topicList[wParam].pItemList[lParam].hszItem);
486: }
487: if (lParam == 1) { // count item
488: count++;
489: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
490: if (hDataCount[iFmt]) {
491: DdeFreeDataHandle(hDataCount[iFmt]);
492: hDataCount[iFmt] = 0;
493: }
494: }
495: InvalidateRect(hwndServer, &rcCount, TRUE);
496: DdePostAdvise(idInst, topicList[wParam].hszTopic,
497: (HSZ)topicList[wParam].pItemList[lParam].hszItem);
498: }
499: // Huge item does not runaway - too slow.
500: }
501: if (cRunaway) {
502: Delay(50, TRUE);
503: // This gives enough time for the system to remain
504: // useable in runaway mode.
505: PostMessage(hwndServer, UM_CHGDATA, wParam, lParam);
506: }
507: }
508: break;
509:
510: case WM_DESTROY: /* message: window being destroyed */
511: if (fAppowned)
512: SendMessage(hwndServer, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_APPOWNED, 0, 0));
513: DdeNameService(idInst, 0, 0, DNS_UNREGISTER); // unregister all services
514: UnHszize();
515: DdeUninitialize(idInst);
516: PostQuitMessage(0);
517: break;
518:
519: default:
520: return (DefWindowProc(hWnd, message, wParam, lParam));
521: }
522: return(0);
523: }
524:
525:
526:
527:
528:
529: VOID Delay(
530: DWORD delay,
531: BOOL fModal)
532: {
533: MSG msg;
534: delay = GetCurrentTime() + delay;
535: while (GetCurrentTime() < delay) {
536: if (fModal && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
537: TranslateMessage(&msg);
538: DispatchMessage(&msg);
539: }
540: }
541: }
542:
543:
544:
545: /*
546: * This function not only paints the server client area with current info,
547: * it also has the side effect of setting the global RECTs that bound each
548: * info area. This way flashing is reduced.
549: */
550: VOID PaintServer(
551: HWND hwnd)
552: {
553: PAINTSTRUCT ps;
554: RECT rc;
555: CHAR szT[MAX_COMMENT];
556:
557: BeginPaint(hwnd, &ps);
558: SetBkMode(ps.hdc, TRANSPARENT);
559: GetClientRect(hwnd, &rc);
560: rc.bottom = rc.top + cyText; // all rects are cyText in height.
561:
562: rcComment = rc;
563: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, pszComment);
564:
565: wsprintf(szT, "# of connections:%d", cServers);
566: rcConnCount = rc;
567: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
568:
569: szT[0] = '\0';
570: rcAllBlock = rc;
571: if (fAllEnabled)
572: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Enabled.");
573: else if (fAllBlocked)
574: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Blocked.");
575: else
576: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
577:
578: rcNextAction = rc;
579: if (fBlockNextCB)
580: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will block.");
581: else if (fTermNextCB)
582: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will terminate.");
583: else
584: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
585:
586: wsprintf(szT, "Count item = %ld", count);
587: rcCount = rc;
588: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
589:
590: wsprintf(szT, "Rand item = %d", seed);
591: rcRand = rc;
592: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
593:
594: wsprintf(szT, "Huge item size = %ld", cbHuge);
595: rcHugeSize = rc;
596: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
597:
598: wsprintf(szT, "Render delay is %d milliseconds.", RenderDelay);
599: rcRndrDelay = rc;
600: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
601:
602: rcExec = rc;
603: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szExec);
604:
605: rcRunaway = rc;
606: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, cRunaway ? "Runaway active." : "");
607:
608: rcAppowned = rc;
609: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, fAppowned ? "Using AppOwned Data Handles." : "");
610:
611: EndPaint(hwnd, &ps);
612: }
613:
614:
615: VOID DrawTextLine(
616: HDC hdc,
617: RECT *prcClip,
618: RECT *prcText,
619: PSTR psz)
620: {
621: RECT rc;
622:
623: if (IntersectRect(&rc, prcText, prcClip)) {
624: DrawText(hdc, psz, -1, prcText,
625: DT_LEFT | DT_EXTERNALLEADING | DT_SINGLELINE | DT_EXPANDTABS |
626: DT_NOCLIP | DT_NOPREFIX);
627: }
628: OffsetRect(prcText, 0, cyText);
629: }
630:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.