|
|
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:
1.1.1.2 ! root 150: INT WINAPI WinMain(
! 151: HANDLE hInstance,
! 152: HANDLE hPrevInstance,
! 153: LPSTR lpCmdLine,
! 154: INT nCmdShow)
1.1 root 155: {
156: MSG msg; /* message */
157:
158: if (!hPrevInstance) /* Other instances of app running? */
159: if (!InitApplication(hInstance)) /* Initialize shared things */
160: return (FALSE); /* Exits if unable to initialize */
161:
162: /* Perform initializations that apply to a specific instance */
163:
164: if (!InitInstance(hInstance, nCmdShow))
165: return (FALSE);
166:
167: /* Acquire and dispatch messages until a WM_QUIT message is received. */
168:
169: while (GetMessage(&msg, /* message structure */
170: 0, /* handle of window receiving the message */
171: 0, /* lowest message to examine */
172: 0)) /* highest message to examine */
173: {
174: TranslateMessage(&msg); /* Translates virtual key codes */
175: DispatchMessage(&msg); /* Dispatches message to window */
176: }
177:
178: UnregisterClass(szClass, hInstance);
179: return (msg.wParam); /* Returns the value from PostQuitMessage */
180: }
181:
182:
183: /****************************************************************************
184:
185: FUNCTION: InitApplication(HANDLE)
186:
187: PURPOSE: Initializes window data and registers window class
188:
189: COMMENTS:
190:
191: This function is called at initialization time only if no other
192: instances of the application are running. This function performs
193: initialization tasks that can be done once for any number of running
194: instances.
195:
196: In this case, we initialize a window class by filling out a data
197: structure of type WNDCLASS and calling the Windows RegisterClass()
198: function. Since all instances of this application use the same window
199: class, we only need to do this when the first instance is initialized.
200:
201:
202: ****************************************************************************/
203:
204: BOOL InitApplication(hInstance)
205: HANDLE hInstance; /* current instance */
206: {
207: WNDCLASS wc;
208:
209: /* Fill in window class structure with parameters that describe the */
210: /* main window. */
211:
212: wc.style = 0; /* Class style(s). */
213: wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */
214: /* windows of this class. */
215: wc.cbClsExtra = 0; /* No per-class extra data. */
216: wc.cbWndExtra = 0; /* No per-window extra data. */
217: wc.hInstance = hInstance; /* Application that owns the class. */
218: wc.hIcon = LoadIcon(hInstance, "server");
219: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
220: wc.hbrBackground = (HANDLE)(COLOR_APPWORKSPACE+1);
221: wc.lpszMenuName = "ServerMenu"; /* Name of menu resource in .RC file. */
222: wc.lpszClassName = "ServerWClass"; /* Name used in call to CreateWindow. */
223:
224: /* Register the window class and return success/failure code. */
225:
226: return (RegisterClass(&wc));
227:
228: }
229:
230:
231: /****************************************************************************
232:
233: FUNCTION: InitInstance(HANDLE, int)
234:
235: PURPOSE: Saves instance handle and creates main window
236:
237: COMMENTS:
238:
239: This function is called at initialization time for every instance of
240: this application. This function performs initialization tasks that
241: cannot be shared by multiple instances.
242:
243: In this case, we save the instance handle in a static variable and
244: create and display the main program window.
245:
246: ****************************************************************************/
247:
248: BOOL InitInstance(hInstance, nCmdShow)
249: HANDLE hInstance; /* Current instance identifier. */
250: INT nCmdShow; /* Param for first ShowWindow() call. */
251: {
252: INT i;
253: RECT Rect;
254: TEXTMETRIC metrics;
255: HDC hdc;
256:
257: /* Save the instance handle in static variable, which will be used in */
258: /* many subsequence calls from this application to Windows. */
259:
260: hInst = hInstance;
261:
262:
263: /* Create a main window for this application instance. */
264:
265: hwndServer = CreateWindow(
266: "ServerWClass", /* See RegisterClass() call. */
267: "Server|Test",
268: WS_OVERLAPPEDWINDOW, /* Window style. */
269: CW_USEDEFAULT, /* Default horizontal position. */
270: CW_USEDEFAULT, /* Default vertical position. */
271: 400,
272: 200,
273: NULL, /* Overlapped windows have no parent. */
274: NULL, /* Use the window class menu. */
275: hInstance, /* This instance owns this window. */
276: NULL /* Pointer not needed. */
277: );
278:
279: GetClientRect(hwndServer, (LPRECT) &Rect);
280:
281: /* If window could not be created, return "failure" */
282:
283: if (!hwndServer)
284: return (FALSE);
285:
286: hdc = GetDC(hwndServer);
287: GetTextMetrics(hdc, &metrics);
288: cyText = (WORD)(metrics.tmHeight + metrics.tmExternalLeading);
289: ReleaseDC(hwndServer, hdc);
290:
291: aFormats[0].atom = CF_TEXT; // exception - predefined.
292: for (i = 1; i < CFORMATS; i++) {
293: aFormats[i].atom = RegisterClipboardFormat(aFormats[i].sz);
294: }
295:
296: /* Make the window visible; update its client area; and return "success" */
297:
298: ShowWindow(hwndServer, nCmdShow); /* Show the window */
299: UpdateWindow(hwndServer); /* Sends WM_PAINT message */
300: seed = 1;
301: srand(1);
302: CCFilter.iCodePage = CP_WINANSI; // initial default codepage
303: if (!DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback,
304: hInstance), APPCMD_FILTERINITS, 0)) {
305: Hszize();
306: DdeNameService(idInst, hszAppName, 0, DNS_REGISTER);
307: return(TRUE);
308: }
309: return (FALSE);
310:
311: }
312:
313: /****************************************************************************
314:
315: FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
316:
317: PURPOSE: Processes messages
318:
319: MESSAGES:
320:
321: WM_COMMAND - application menu (About dialog box)
322: WM_DESTROY - destroy window
323:
324: COMMENTS:
325:
326: To process the IDM_ABOUT message, call MakeProcInstance() to get the
327: current instance address of the About() function. Then call Dialog
328: box which will create the box according to the information in your
329: server.rc file and turn control over to the About() function. When
330: it returns, free the intance address.
331:
332: ****************************************************************************/
333:
334: LONG APIENTRY MainWndProc(hWnd, message, wParam, lParam)
335: HWND hWnd; /* window handle */
336: UINT message; /* type of message */
337: WPARAM wParam; /* additional information */
1.1.1.2 ! root 338: LPARAM lParam; /* additional information */
1.1 root 339: {
340: switch (message) {
341: case WM_INITMENU:
342: if (GetMenu(hWnd) != (HMENU)wParam)
343: break;
344:
345: CheckMenuItem((HMENU)wParam, IDM_BLOCKALLCBS,
346: fAllBlocked ? MF_CHECKED : MF_UNCHECKED);
347: CheckMenuItem((HMENU)wParam, IDM_UNBLOCKALLCBS,
348: fAllEnabled ? MF_CHECKED : MF_UNCHECKED);
349: CheckMenuItem((HMENU)wParam, IDM_BLOCKNEXTCB,
350: fBlockNextCB ? MF_CHECKED : MF_UNCHECKED);
351: CheckMenuItem((HMENU)wParam, IDM_TERMNEXTCB,
352: fTermNextCB ? MF_CHECKED : MF_UNCHECKED);
353: CheckMenuItem((HMENU)wParam, IDM_RUNAWAY,
354: cRunaway ? MF_CHECKED : MF_UNCHECKED);
355: CheckMenuItem((HMENU)wParam, IDM_APPOWNED,
356: fAppowned ? MF_CHECKED : MF_UNCHECKED);
357: break;
358:
359: case WM_COMMAND: /* message: command from application menu */
1.1.1.2 ! root 360: switch (LOWORD(wParam)) {
1.1 root 361: case IDM_ENABLEONECB:
362: DdeEnableCallback(idInst, 0, EC_ENABLEONE);
363: fAllBlocked = FALSE;
364: fAllEnabled = FALSE;
365: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
366: break;
367:
368: case IDM_TERMNEXTCB:
369: fTermNextCB = !fTermNextCB;
370: InvalidateRect(hwndServer, &rcNextAction, TRUE);
371: break;
372:
373: case IDM_BLOCKNEXTCB:
374: fBlockNextCB = !fBlockNextCB;
375: InvalidateRect(hwndServer, &rcNextAction, TRUE);
376: break;
377:
378: case IDM_BLOCKALLCBS:
379: DdeEnableCallback(idInst, 0, EC_DISABLE);
380: fAllBlocked = TRUE;
381: fAllEnabled = FALSE;
382: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
383: break;
384:
385: case IDM_UNBLOCKALLCBS:
386: DdeEnableCallback(idInst, 0, EC_ENABLEALL);
387: fAllEnabled = TRUE;
388: fAllBlocked = FALSE;
389: InvalidateRect(hwndServer, &rcAllBlock, TRUE);
390: break;
391:
392: case IDM_APPOWNED:
393: fAppowned = !fAppowned;
394: if (!fAppowned) {
395: WORD iFmt;
396: for (iFmt = 0; iFmt < CFORMATS; iFmt++) {
397: if (hDataHuge[iFmt]) {
398: DdeFreeDataHandle(hDataHuge[iFmt]);
399: hDataHuge[iFmt] = 0;
400: InvalidateRect(hwndServer, &rcHugeSize, TRUE);
401: }
402: if (hDataCount[iFmt]) {
403: DdeFreeDataHandle(hDataCount[iFmt]);
404: hDataCount[iFmt] = 0;
405: }
406: if (hDataRand[iFmt]) {
407: DdeFreeDataHandle(hDataRand[iFmt]);
408: hDataRand[iFmt] = 0;
409: }
410: if (hDataHelp[iFmt]) {
411: DdeFreeDataHandle(hDataHelp[iFmt]);
412: hDataHelp[iFmt] = 0;
413: }
414: }
415: }
416: InvalidateRect(hwndServer, &rcAppowned, TRUE);
417: break;
418:
419: case IDM_RUNAWAY:
420: cRunaway = !cRunaway;
421: InvalidateRect(hwndServer, &rcRunaway, TRUE);
422: if (!cRunaway) {
423: break;
424: }
425: // fall through
426:
427: case IDM_CHANGEDATA:
428: PostMessage(hwndServer, UM_CHGDATA, 1, 0); // rand
429: PostMessage(hwndServer, UM_CHGDATA, 1, 1); // count
430: break;
431:
432: case IDM_RENDERDELAY:
1.1.1.2 ! root 433: DoDialog("VALUEENTRY", (DLGPROC)RenderDelayDlgProc, 0, TRUE);
1.1 root 434: InvalidateRect(hwndServer, &rcRndrDelay, TRUE);
435: break;
436:
437: case IDM_SETSERVER:
1.1.1.2 ! root 438: DoDialog("VALUEENTRY", (DLGPROC)SetServerDlgProc, 0, TRUE);
1.1 root 439: break;
440:
441: case IDM_SETTOPIC:
1.1.1.2 ! root 442: DoDialog("VALUEENTRY", (DLGPROC)SetTopicDlgProc, 0, TRUE);
1.1 root 443: break;
444:
445: case IDM_CONTEXT:
1.1.1.2 ! root 446: DoDialog("CONTEXT", (DLGPROC)ContextDlgProc, 0, TRUE);
1.1 root 447: break;
448:
449: case IDM_ABOUT:
1.1.1.2 ! root 450: DoDialog("ABOUT", (DLGPROC)About, 0, TRUE);
1.1 root 451: break;
452:
453: case IDM_HELP:
454: break;
455:
456: default:
457: return (DefWindowProc(hWnd, message, wParam, lParam));
458: }
459: break;
460:
461: case WM_PAINT:
462: PaintServer(hWnd);
463: break;
464:
465: case UM_CHGDATA:
466: {
467: WORD iFmt;
468:
469: // wParam = TopicIndex,
470: // LOWORD(lParam) = ItemIndex
471: // We asynchronously do DdePostAdvise() calls to prevent infinite
472: // loops when in runaway mode.
473: if (wParam == 1) { // test topic
474: if (lParam == 0) { // rand item
475: seed = rand();
476: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
477: if (hDataRand[iFmt]) {
478: DdeFreeDataHandle(hDataRand[iFmt]);
479: hDataRand[iFmt] = 0;
480: }
481: }
482: InvalidateRect(hwndServer, &rcRand, TRUE);
483: DdePostAdvise(idInst, topicList[wParam].hszTopic,
484: (HSZ)topicList[wParam].pItemList[lParam].hszItem);
485: }
486: if (lParam == 1) { // count item
487: count++;
488: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
489: if (hDataCount[iFmt]) {
490: DdeFreeDataHandle(hDataCount[iFmt]);
491: hDataCount[iFmt] = 0;
492: }
493: }
494: InvalidateRect(hwndServer, &rcCount, TRUE);
495: DdePostAdvise(idInst, topicList[wParam].hszTopic,
496: (HSZ)topicList[wParam].pItemList[lParam].hszItem);
497: }
498: // Huge item does not runaway - too slow.
499: }
500: if (cRunaway) {
501: Delay(50, TRUE);
502: // This gives enough time for the system to remain
503: // useable in runaway mode.
504: PostMessage(hwndServer, UM_CHGDATA, wParam, lParam);
505: }
506: }
507: break;
508:
509: case WM_DESTROY: /* message: window being destroyed */
510: if (fAppowned)
1.1.1.2 ! root 511: SendMessage(hwndServer, WM_COMMAND, (WPARAM)MAKELONG(IDM_APPOWNED, 0), (LONG)(0));
1.1 root 512: DdeNameService(idInst, 0, 0, DNS_UNREGISTER); // unregister all services
513: UnHszize();
514: DdeUninitialize(idInst);
515: PostQuitMessage(0);
516: break;
517:
518: default:
519: return (DefWindowProc(hWnd, message, wParam, lParam));
520: }
521: return(0);
522: }
523:
524:
525:
526:
527:
528: VOID Delay(
529: DWORD delay,
530: BOOL fModal)
531: {
532: MSG msg;
533: delay = GetCurrentTime() + delay;
534: while (GetCurrentTime() < delay) {
535: if (fModal && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
536: TranslateMessage(&msg);
537: DispatchMessage(&msg);
538: }
539: }
540: }
541:
542:
543:
544: /*
545: * This function not only paints the server client area with current info,
546: * it also has the side effect of setting the global RECTs that bound each
547: * info area. This way flashing is reduced.
548: */
549: VOID PaintServer(
550: HWND hwnd)
551: {
552: PAINTSTRUCT ps;
553: RECT rc;
554: CHAR szT[MAX_COMMENT];
555:
556: BeginPaint(hwnd, &ps);
557: SetBkMode(ps.hdc, TRANSPARENT);
558: GetClientRect(hwnd, &rc);
559: rc.bottom = rc.top + cyText; // all rects are cyText in height.
560:
561: rcComment = rc;
562: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, pszComment);
563:
564: wsprintf(szT, "# of connections:%d", cServers);
565: rcConnCount = rc;
566: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
567:
568: szT[0] = '\0';
569: rcAllBlock = rc;
570: if (fAllEnabled)
571: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Enabled.");
572: else if (fAllBlocked)
573: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Blocked.");
574: else
575: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
576:
577: rcNextAction = rc;
578: if (fBlockNextCB)
579: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will block.");
580: else if (fTermNextCB)
581: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will terminate.");
582: else
583: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
584:
585: wsprintf(szT, "Count item = %ld", count);
586: rcCount = rc;
587: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
588:
589: wsprintf(szT, "Rand item = %d", seed);
590: rcRand = rc;
591: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
592:
593: wsprintf(szT, "Huge item size = %ld", cbHuge);
594: rcHugeSize = rc;
595: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
596:
597: wsprintf(szT, "Render delay is %d milliseconds.", RenderDelay);
598: rcRndrDelay = rc;
599: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
600:
601: rcExec = rc;
602: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szExec);
603:
604: rcRunaway = rc;
605: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, cRunaway ? "Runaway active." : "");
606:
607: rcAppowned = rc;
608: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, fAppowned ? "Using AppOwned Data Handles." : "");
609:
610: EndPaint(hwnd, &ps);
611: }
612:
613:
614: VOID DrawTextLine(
615: HDC hdc,
616: RECT *prcClip,
617: RECT *prcText,
618: PSTR psz)
619: {
620: RECT rc;
621:
622: if (IntersectRect(&rc, prcText, prcClip)) {
623: DrawText(hdc, psz, -1, prcText,
624: DT_LEFT | DT_EXTERNALLEADING | DT_SINGLELINE | DT_EXPANDTABS |
625: DT_NOCLIP | DT_NOPREFIX);
626: }
627: OffsetRect(prcText, 0, cyText);
628: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.