|
|
1.1 root 1: /***************************************************************************
2: * *
3: * PROGRAM : client.c *
4: * *
5: * PURPOSE : To demonstrate how to use the DDEML library from the *
6: * client side and for basic testing of the DDEML API. *
7: * *
8: ***************************************************************************/
9:
10: #include "client.h"
11: #include <string.h>
12: #include <memory.h>
13: #include "infoctrl.h"
14:
15: /* global variables used in this module or among more than one module */
16: CONVCONTEXT CCFilter = { sizeof(CONVCONTEXT), 0, 0, 0, 0L, 0L };
17: DWORD idInst = 0;
18: HANDLE hInst; /* Program instance handle */
19: HANDLE hAccel; /* Main accelerator resource */
20: HWND hwndFrame = NULL; /* Handle to main window */
21: HWND hwndMDIClient = NULL; /* Handle to MDI client */
22: HWND hwndActive = NULL; /* Handle to currently activated child */
23: LONG DefTimeout = DEFTIMEOUT; /* default synchronous transaction timeout */
24: DWORD wDelay = 0;
25: BOOL fBlockNextCB = FALSE; /* set if next callback causes a CBR_BLOCK */
26: BOOL fTermNextCB = FALSE; /* set to call DdeDisconnect() on next callback */
27: BOOL fAutoReconnect = FALSE; /* set if DdeReconnect() is to be called on XTYP_DISCONNECT callbacks */
28: HDDEDATA hDataOwned = NULL; /* Current owned huge data handle */
29: DWORD fmtLink = 0; /* link clipboard format number */
30: DWORD DefOptions = 0; /* default transaction optons */
31: OWNED aOwned[MAX_OWNED]; /* list of all owned handles. */
32: DWORD cOwned = 0; /* number of existing owned handles. */
33: FARPROC lpMsgFilterProc; /* instance proc from MSGF_DDEMGR filter */
34:
35: /*
36: * This is the array of formats we support
37: */
38: FORMATINFO aFormats[] = {
39: { CF_TEXT, "CF_TEXT" }, // exception! predefined format
40: { 0, "Dummy1" },
41: { 0, "Dummy2" },
42: };
43:
44: /* Forward declarations of helper functions in this module */
45: VOID NEAR PASCAL CloseAllChildren(VOID);
46: VOID NEAR PASCAL InitializeMenu (HANDLE);
47: VOID NEAR PASCAL CommandHandler (HWND,DWORD);
48: VOID NEAR PASCAL SetWrap (HWND,BOOL);
49:
50: /****************************************************************************
51: * *
52: * FUNCTION : WinMain(HANDLE, HANDLE, LPSTR, int) *
53: * *
54: * PURPOSE : Creates the "frame" window, does some initialization and *
55: * enters the message loop. *
56: * *
57: ****************************************************************************/
58: int APIENTRY WinMain(
59: HANDLE hInstance,
60: HANDLE hPrevInstance,
61: LPSTR lpszCmdLine,
62: int nCmdShow
63: )
64: {
65: MSG msg;
66:
67: hInst = hInstance;
68:
69: /* If this is the first instance of the app. register window classes */
70: if (!hPrevInstance){
71: if (!InitializeApplication ())
72: return 0;
73: }
74:
75: /* Create the frame and do other initialization */
76: if (!InitializeInstance(nCmdShow))
77: return 0;
78:
79: /* Enter main message loop */
80: while (GetMessage (&msg, NULL, 0, 0)){
81: (*lpMsgFilterProc)(MSGF_DDEMGR, 0, (LONG)(LPMSG)&msg);
82: }
83:
84: // free up any appowned handles
85: while (cOwned) {
86: DdeFreeDataHandle(aOwned[--cOwned].hData);
87: }
88: DdeUninitialize(idInst);
89:
90: UnhookWindowsHook(WH_MSGFILTER, lpMsgFilterProc);
91: FreeProcInstance(lpMsgFilterProc);
92:
93: return 0;
94: }
95:
96: /****************************************************************************
97: * *
98: * FUNCTION : FrameWndProc (hwnd, msg, wParam, lParam ) *
99: * *
100: * PURPOSE : The window function for the "frame" window, which controls *
101: * the menu and encompasses all the MDI child windows. Does *
102: * the major part of the message processing. Specifically, in *
103: * response to: *
104: * *
105: ****************************************************************************/
106: LONG APIENTRY FrameWndProc ( hwnd, msg, wParam, lParam )
107: HWND hwnd;
108: UINT msg;
109: WPARAM wParam;
110: LPARAM lParam;
111:
112: {
113: switch (msg){
114: case WM_CREATE:{
115: CLIENTCREATESTRUCT ccs;
116:
117: /* Find window menu where children will be listed */
118: ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
119: ccs.idFirstChild = IDM_WINDOWCHILD;
120:
121: /* Create the MDI client filling the client area */
122: hwndMDIClient = CreateWindow ("mdiclient",
123: NULL,
124: WS_CHILD | WS_CLIPCHILDREN |
125: WS_VSCROLL | WS_HSCROLL,
126: 0,
127: 0,
128: 0,
129: 0,
130: hwnd,
131: (HMENU)0xCAC,
132: hInst,
133: (LPSTR)&ccs);
134:
135:
136: ShowWindow (hwndMDIClient,SW_SHOW);
137: break;
138: }
139:
140: case WM_INITMENU:
141: InitializeMenu ((HMENU)wParam);
142: break;
143:
144: case WM_COMMAND:
145: CommandHandler (hwnd, GET_WM_COMMAND_ID(wParam, lParam));
146: break;
147:
148: case WM_CLOSE:
149: CloseAllChildren();
150: DestroyWindow(hwnd);
151: break;
152:
153: case WM_DESTROY:
154: PostQuitMessage(0);
155: break;
156:
157: default:
158: /* use DefFrameProc() instead of DefWindowProc() since there
159: * are things that have to be handled differently because of MDI
160: */
161: return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
162: }
163: return 0;
164: }
165:
166:
167:
168:
169:
170: /****************************************************************************
171: * *
172: * FUNCTION : MDIChildWndProc *
173: * *
174: * PURPOSE : The window function for the "child" conversation and list *
175: * windows. *
176: * *
177: ****************************************************************************/
178: LONG APIENTRY MDIChildWndProc( hwnd, msg, wParam, lParam )
179: HWND hwnd;
180: UINT msg;
181: WPARAM wParam;
182: LPARAM lParam;
183: {
184: MYCONVINFO *pmci;
185: RECT rc;
186:
187: switch (msg){
188: case WM_CREATE:
189: /*
190: * Create a coresponding conversation info structure to link this
191: * window to the conversation or conversation list it represents.
192: *
193: * lParam: points to the conversation info to initialize our copy to.
194: */
195: pmci = (MYCONVINFO *)MyAlloc(sizeof(MYCONVINFO));
196: if (pmci != NULL) {
197: _fmemcpy(pmci,
198: (LPSTR)((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam,
199: sizeof(MYCONVINFO));
200: pmci->hwndXaction = 0; /* no current transaction yet */
201: pmci->x = pmci->y = 0; /* new transaction windows start here */
202: DdeKeepStringHandle(idInst, pmci->hszTopic);/* keep copies of the hszs for us */
203: DdeKeepStringHandle(idInst, pmci->hszApp);
204:
205: // link hConv and hwnd together
206: SetWindowLong(hwnd, 0, (DWORD)pmci);
207:
208: /*
209: * non-list windows link the conversations to the windows via the
210: * conversation user handle.
211: */
212: if (!pmci->fList)
213: DdeSetUserHandle(pmci->hConv, QID_SYNC, (DWORD)hwnd);
214: }
215: goto CallDCP;
216: break;
217:
218: case UM_GETNEXTCHILDX:
219: case UM_GETNEXTCHILDY:
220: /*
221: * Calculate the next place to put the next transaction window.
222: */
223: {
224: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
225: GetClientRect(hwnd, &rc);
226: if (msg == UM_GETNEXTCHILDX) {
227: pmci->x += 14;
228: if (pmci->x > (rc.right - 200 - rc.left))
229: pmci->x = 0;
230: return(pmci->x);
231: } else {
232: pmci->y += 12;
233: if (pmci->y > (rc.bottom - 100 - rc.top))
234: pmci->y = 0;
235: return(pmci->y);
236: }
237: }
238: break;
239:
240: case UM_DISCONNECTED:
241: /*
242: * Disconnected conversations can't have any transactions so we
243: * remove all the transaction windows here to show whats up.
244: */
245: {
246: HWND hwndT;
247: while (hwndT = GetWindow(hwnd, GW_CHILD))
248: DestroyWindow(hwndT);
249: InvalidateRect(hwnd, NULL, TRUE);
250: }
251: break;
252:
253: case WM_DESTROY:
254: /*
255: * Cleanup our conversation info structure, and disconnect all
256: * conversations associated with this window.
257: */
258: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
259: pmci->hwndXaction = 0; /* clear this to avoid focus problems */
260: if (pmci->hConv) {
261: if (pmci->fList) {
262: DdeDisconnectList((HCONVLIST)pmci->hConv);
263: } else {
264: MyDisconnect(pmci->hConv);
265: }
266: }
267: DdeFreeStringHandle(idInst, pmci->hszTopic);
268: DdeFreeStringHandle(idInst, pmci->hszApp);
269: MyFree(pmci);
270: goto CallDCP;
271: break;
272:
273: case WM_SETFOCUS:
274: /*
275: * This catches focus changes caused by dialogs.
276: */
277: lParam = (LPARAM)hwnd;
278: // fall through
279:
280: case WM_MDIACTIVATE:
281: hwndActive = GET_WM_MDIACTIVATE_HWNDACTIVATE(wParam, lParam);
282: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
283: /*
284: * pass the focus onto the current transaction window.
285: */
286: if (GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wParam, lParam) &&
287: IsWindow(pmci->hwndXaction))
288: SetFocus(pmci->hwndXaction);
289: break;
290:
291: case ICN_HASFOCUS:
292: /*
293: * update which transaction window is the main one.
294: */
295: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
296: pmci->hwndXaction = wParam ? (HWND)lParam : NULL;
297: break;
298:
299: case ICN_BYEBYE:
300: /*
301: * Transaction window is closing...
302: *
303: * wParam = hwndXact
304: * lParam = lpxact
305: */
306: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
307: if (pmci != NULL) {
308: XACT *pxact;
309:
310: pxact = (XACT *)lParam;
311: if (pxact != NULL) {
312: /*
313: * If this transaction is active, abandon it first.
314: */
315: if (pxact->fsOptions & XOPT_ASYNC &&
316: !(pxact->fsOptions & XOPT_COMPLETED)) {
317: DdeAbandonTransaction(idInst, pmci->hConv, pxact->Result);
318: }
319: /*
320: * release resources associated with transaction.
321: */
322: DdeFreeStringHandle(idInst, pxact->hszItem);
323: MyFree((PSTR)pxact);
324: /*
325: * Locate next apropriate transaction window to get focus.
326: */
327: if (!pmci->hwndXaction || pmci->hwndXaction == (HWND)wParam)
328: pmci->hwndXaction = GetWindow(hwnd, GW_CHILD);
329: if (pmci->hwndXaction == (HWND)wParam)
330: pmci->hwndXaction = GetWindow((HWND)wParam, GW_HWNDNEXT);
331: if (pmci->hwndXaction == (HWND)wParam ||
332: !IsWindow(pmci->hwndXaction) ||
333: !IsChild(hwnd, pmci->hwndXaction))
334: pmci->hwndXaction = NULL;
335: else
336: SetFocus(pmci->hwndXaction);
337: }
338: }
339: break;
340:
341: case WM_PAINT:
342: /*
343: * Paint this conversation's related information.
344: */
345: pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
346: {
347: PAINTSTRUCT ps;
348: PSTR psz;
349:
350: BeginPaint(hwnd, &ps);
351: SetBkMode(ps.hdc, TRANSPARENT);
352: psz = pmci->fList ? GetConvListText(pmci->hConv) :
353: GetConvInfoText(pmci->hConv, &pmci->ci);
354: if (psz) {
355: GetClientRect(hwnd, &rc);
356: DrawText(ps.hdc, psz, -1, &rc,
357: DT_WORDBREAK | DT_LEFT | DT_NOPREFIX | DT_TABSTOP);
358: MyFree(psz);
359: }
360: EndPaint(hwnd, &ps);
361: }
362: break;
363:
364: case WM_QUERYENDSESSION:
365: return TRUE;
366:
367: default:
368: CallDCP:
369: /* Again, since the MDI default behaviour is a little different,
370: * call DefMDIChildProc instead of DefWindowProc()
371: */
372: return DefMDIChildProc (hwnd, msg, wParam, lParam);
373: }
374: return FALSE;
375: }
376:
377:
378: /****************************************************************************
379: * *
380: * FUNCTION : Initializemenu ( hMenu ) *
381: * *
382: * PURPOSE : Sets up greying, enabling and checking of main menu items *
383: * based on the app's state. *
384: * *
385: ****************************************************************************/
386: VOID NEAR PASCAL InitializeMenu ( hmenu )
387: HANDLE hmenu;
388: {
389: BOOL fLink = FALSE; // set if Link format is on the clipboard;
390: BOOL fAny = FALSE; // set if hwndActive exists
391: BOOL fList = FALSE; // set if hwndActive is a list window
392: BOOL fConnected = FALSE; // set if hwndActive is a connection conversation.
393: BOOL fXaction = FALSE; // set if hwndActive has a selected transaction window
394: BOOL fXactions = FALSE; // set if hwndActive contains transaction windows
395: BOOL fBlocked = FALSE; // set if hwndActive conversation is blocked.
396: BOOL fBlockNext = FALSE; // set if handActive conversation is blockNext.
397: MYCONVINFO *pmci = NULL;
398:
399: if (OpenClipboard(hwndFrame)) {
400: fLink = (IsClipboardFormatAvailable(fmtLink));
401: CloseClipboard();
402: }
403:
404: if (fAny = (IsWindow(hwndActive) &&
405: (pmci = (MYCONVINFO *)GetWindowLong(hwndActive, 0)))) {
406: fXactions = (BOOL)GetWindow(hwndActive, GW_CHILD);
407: if (!(fList = pmci->fList)) {
408: CONVINFO ci;
409:
410: ci.cb = sizeof(CONVINFO);
411: DdeQueryConvInfo(pmci->hConv, QID_SYNC, &ci);
412: fConnected = ci.wStatus & ST_CONNECTED;
413: fXaction = IsWindow(pmci->hwndXaction);
414: fBlocked = ci.wStatus & ST_BLOCKED;
415: fBlockNext = ci.wStatus & ST_BLOCKNEXT;
416: }
417: }
418:
419: EnableMenuItem(hmenu, IDM_EDITPASTE,
420: fLink ? MF_ENABLED : MF_GRAYED);
421:
422: // IDM_CONNECTED - always enabled.
423:
424: EnableMenuItem(hmenu, IDM_RECONNECT,
425: fList ? MF_ENABLED : MF_GRAYED);
426:
427: EnableMenuItem (hmenu, IDM_DISCONNECT,
428: fConnected ? MF_ENABLED : MF_GRAYED);
429:
430: EnableMenuItem (hmenu, IDM_TRANSACT,
431: fConnected ? MF_ENABLED : MF_GRAYED);
432:
433: EnableMenuItem(hmenu, IDM_ABANDON,
434: fXaction ? MF_ENABLED : MF_GRAYED);
435:
436: EnableMenuItem(hmenu, IDM_ABANDONALL,
437: fXactions ? MF_ENABLED : MF_GRAYED);
438:
439:
440: EnableMenuItem (hmenu, IDM_BLOCKCURRENT,
441: fConnected && !fBlocked ? MF_ENABLED : MF_GRAYED);
442: CheckMenuItem(hmenu, IDM_BLOCKCURRENT,
443: fBlocked ? MF_CHECKED : MF_UNCHECKED);
444:
445: EnableMenuItem (hmenu, IDM_ENABLECURRENT,
446: fConnected && (fBlocked || fBlockNext) ? MF_ENABLED : MF_GRAYED);
447: CheckMenuItem(hmenu, IDM_ENABLECURRENT,
448: !fBlocked ? MF_CHECKED : MF_UNCHECKED);
449:
450: EnableMenuItem (hmenu, IDM_ENABLEONECURRENT,
451: fConnected && (fBlocked) ? MF_ENABLED : MF_GRAYED);
452: CheckMenuItem(hmenu, IDM_ENABLEONECURRENT,
453: fBlockNext ? MF_CHECKED : MF_UNCHECKED);
454:
455: EnableMenuItem (hmenu, IDM_BLOCKALLCBS,
456: fAny ? MF_ENABLED : MF_GRAYED);
457:
458: EnableMenuItem (hmenu, IDM_ENABLEALLCBS,
459: fAny ? MF_ENABLED : MF_GRAYED);
460:
461: EnableMenuItem (hmenu, IDM_ENABLEONECB,
462: fAny ? MF_ENABLED : MF_GRAYED);
463:
464: EnableMenuItem(hmenu, IDM_BLOCKNEXTCB,
465: fAny || fBlockNextCB ? MF_ENABLED : MF_GRAYED);
466: CheckMenuItem(hmenu, IDM_BLOCKNEXTCB,
467: fBlockNextCB ? MF_CHECKED : MF_UNCHECKED);
468:
469: EnableMenuItem(hmenu, IDM_TERMNEXTCB,
470: fAny || fTermNextCB ? MF_ENABLED : MF_GRAYED);
471: CheckMenuItem(hmenu, IDM_TERMNEXTCB,
472: fTermNextCB ? MF_CHECKED : MF_UNCHECKED);
473:
474: // IDM_DELAY - always enabled.
475:
476: // IDM_TIMEOUT - alwasy enabled.
477:
478: EnableMenuItem (hmenu, IDM_WINDOWTILE,
479: fAny ? MF_ENABLED : MF_GRAYED);
480:
481: EnableMenuItem (hmenu, IDM_WINDOWCASCADE,
482: fAny ? MF_ENABLED : MF_GRAYED);
483:
484: EnableMenuItem (hmenu, IDM_WINDOWICONS,
485: fAny ? MF_ENABLED : MF_GRAYED);
486:
487: EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL,
488: fAny ? MF_ENABLED : MF_GRAYED);
489:
490: EnableMenuItem (hmenu, IDM_XACTTILE,
491: fXactions ? MF_ENABLED : MF_GRAYED);
492:
493: EnableMenuItem (hmenu, IDM_XACTCASCADE,
494: fXactions ? MF_ENABLED : MF_GRAYED);
495:
496: CheckMenuItem(hmenu, IDM_AUTORECONNECT,
497: fAutoReconnect ? MF_CHECKED : MF_UNCHECKED);
498:
499: // IDM_HELPABOUT - always enabled.
500: }
501:
502:
503:
504: /****************************************************************************
505: * *
506: * FUNCTION : CloseAllChildren () *
507: * *
508: * PURPOSE : Destroys all MDI child windows. *
509: * *
510: ****************************************************************************/
511: VOID NEAR PASCAL CloseAllChildren ()
512: {
513: HWND hwndT;
514:
515: /* hide the MDI client window to avoid multiple repaints */
516: ShowWindow(hwndMDIClient,SW_HIDE);
517:
518: /* As long as the MDI client has a child, destroy it */
519: while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD)){
520:
521: /* Skip the icon title windows */
522: while (hwndT && GetWindow (hwndT, GW_OWNER))
523: hwndT = GetWindow (hwndT, GW_HWNDNEXT);
524:
525: if (!hwndT)
526: break;
527:
528: SendMessage(hwndMDIClient, WM_MDIDESTROY, (DWORD)hwndT, 0L);
529: }
530:
531: ShowWindow( hwndMDIClient, SW_SHOW);
532: }
533:
534: /****************************************************************************
535: * *
536: * FUNCTION : CommandHandler () *
537: * *
538: * PURPOSE : Processes all "frame" WM_COMMAND messages. *
539: * *
540: ****************************************************************************/
541: VOID NEAR PASCAL CommandHandler (
542: HWND hwnd,
543: DWORD id)
544:
545: {
546: MYCONVINFO *pmci = NULL;
547:
548: if (hwndActive)
549: pmci = (MYCONVINFO *)GetWindowLong(hwndActive, 0);
550:
551: switch (id){
552: case IDM_EDITPASTE:
553: {
554: HANDLE hClipData;
555: LPSTR psz;
556: XACT xact;
557:
558: if (OpenClipboard(hwnd)) {
559: if (hClipData = GetClipboardData(fmtLink)) {
560: if (psz = GlobalLock(hClipData)) {
561: /*
562: * Create a conversation with the link app and
563: * begin a request and advise start transaction.
564: */
565: xact.hConv = CreateConv(DdeCreateStringHandle(idInst, psz, NULL),
566: DdeCreateStringHandle(idInst, &psz[_fstrlen(psz) + 1], NULL),
567: FALSE);
568: if (xact.hConv) {
569: psz += _fstrlen(psz) + 1;
570: psz += _fstrlen(psz) + 1;
571: xact.ulTimeout = DefTimeout;
572: xact.wType = XTYP_ADVSTART;
573: xact.hDdeData = 0;
574: xact.wFmt = CF_TEXT;
575: xact.hszItem = DdeCreateStringHandle(idInst, psz, NULL);
576: xact.fsOptions = 0;
577: ProcessTransaction(&xact);
578: xact.wType = XTYP_REQUEST;
579: ProcessTransaction(&xact);
580: }
581: GlobalUnlock(hClipData);
582: }
583: }
584: CloseClipboard();
585: }
586: }
587: break;
588:
589: case IDM_CONNECT:
590: case IDM_RECONNECT:
591: DoDialog(MAKEINTRESOURCE(IDD_CONNECT), (WNDPROC)ConnectDlgProc,
592: id == IDM_RECONNECT, FALSE);
593: break;
594:
595: case IDM_DISCONNECT:
596: if (hwndActive) {
597: SendMessage(hwndMDIClient, WM_MDIDESTROY, (DWORD)hwndActive, 0L);
598: }
599: break;
600:
601: case IDM_TRANSACT:
602: if (DoDialog(MAKEINTRESOURCE(IDD_TRANSACT), (WNDPROC)TransactDlgProc,
603: (DWORD)(LPSTR)pmci->hConv, FALSE))
604: SetFocus(GetWindow(hwndActive, GW_CHILD));
605: break;
606:
607: case IDM_ABANDON:
608: if (pmci != NULL && IsWindow(pmci->hwndXaction)) {
609: DestroyWindow(pmci->hwndXaction);
610: }
611: break;
612:
613: case IDM_ABANDONALL:
614: DdeAbandonTransaction(idInst, pmci->hConv, NULL);
615: {
616: HWND hwndXaction;
617:
618: hwndXaction = GetWindow(hwndActive, GW_CHILD);
619: while (hwndXaction) {
620: DestroyWindow(hwndXaction);
621: hwndXaction = GetWindow(hwndActive, GW_CHILD);
622: }
623: }
624: break;
625:
626: case IDM_BLOCKCURRENT:
627: DdeEnableCallback(idInst, pmci->hConv, EC_DISABLE);
628: InvalidateRect(hwndActive, NULL, TRUE);
629: break;
630:
631: case IDM_ENABLECURRENT:
632: DdeEnableCallback(idInst, pmci->hConv, EC_ENABLEALL);
633: InvalidateRect(hwndActive, NULL, TRUE);
634: break;
635:
636: case IDM_ENABLEONECURRENT:
637: DdeEnableCallback(idInst, pmci->hConv, EC_ENABLEONE);
638: InvalidateRect(hwndActive, NULL, TRUE);
639: break;
640:
641: case IDM_BLOCKALLCBS:
642: DdeEnableCallback(idInst, NULL, EC_DISABLE);
643: InvalidateRect(hwndMDIClient, NULL, TRUE);
644: break;
645:
646: case IDM_ENABLEALLCBS:
647: DdeEnableCallback(idInst, NULL, EC_ENABLEALL);
648: InvalidateRect(hwndMDIClient, NULL, TRUE);
649: break;
650:
651: case IDM_ENABLEONECB:
652: DdeEnableCallback(idInst, NULL, EC_ENABLEONE);
653: InvalidateRect(hwndMDIClient, NULL, TRUE);
654: break;
655:
656: case IDM_BLOCKNEXTCB:
657: fBlockNextCB = !fBlockNextCB;
658: break;
659:
660: case IDM_TERMNEXTCB:
661: fTermNextCB = !fTermNextCB;
662: break;
663:
664: case IDM_DELAY:
665: DoDialog(MAKEINTRESOURCE(IDD_VALUEENTRY), (WNDPROC)DelayDlgProc, NULL,
666: TRUE);
667: break;
668:
669: case IDM_TIMEOUT:
670: DoDialog(MAKEINTRESOURCE(IDD_VALUEENTRY), (WNDPROC)TimeoutDlgProc, NULL,
671: TRUE);
672: break;
673:
674: case IDM_CONTEXT:
675: DoDialog(MAKEINTRESOURCE(IDD_CONTEXT), (WNDPROC)ContextDlgProc, NULL, TRUE);
676: break;
677:
678: case IDM_AUTORECONNECT:
679: fAutoReconnect = !fAutoReconnect;
680: break;
681:
682: /* The following are window commands - these are handled by the
683: * MDI Client.
684: */
685: case IDM_WINDOWTILE:
686: /* Tile MDI windows */
687: SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
688: break;
689:
690: case IDM_WINDOWCASCADE:
691: /* Cascade MDI windows */
692: SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
693: break;
694:
695: case IDM_WINDOWICONS:
696: /* Auto - arrange MDI icons */
697: SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
698: break;
699:
700: case IDM_WINDOWCLOSEALL:
701: CloseAllChildren();
702: break;
703:
704: case IDM_XACTTILE:
705: TileChildWindows(hwndActive);
706: break;
707:
708: case IDM_XACTCASCADE:
709: MyCascadeChildWindows(hwndActive);
710: break;
711:
712: case IDM_HELPABOUT:{
713: DoDialog(MAKEINTRESOURCE(IDD_ABOUT), (WNDPROC)AboutDlgProc, NULL, TRUE);
714: break;
715: }
716:
717: default:
718: /*
719: * This is essential, since there are frame WM_COMMANDS generated
720: * by the MDI system for activating child windows via the
721: * window menu.
722: */
723: DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND,
724: GET_WM_COMMAND_MPS(id, 0, 0));
725: }
726: }
727:
728:
729: /****************************************************************************
730: * *
731: * FUNCTION : MPError (flags, id, ...) *
732: * *
733: * PURPOSE : Flashes a Message Box to the user. The format string is *
734: * taken from the STRINGTABLE. *
735: * *
736: * RETURNS : Returns value returned by MessageBox() to the caller. *
737: * *
738: ****************************************************************************/
739: INT FAR cdecl MPError(
740: DWORD bFlags,
741: DWORD id,
742: ...)
743: {
744: CHAR sz[160];
745: CHAR szFmt[128];
746:
747: LoadString (hInst, id, szFmt, sizeof (szFmt));
748: wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
749: LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
750: return MessageBox (hwndFrame, sz, szFmt, bFlags);
751: }
752:
753:
754:
755: /****************************************************************************
756: * *
757: * FUNCTION : CreateConv() *
758: * *
759: * PURPOSE : *
760: * *
761: * RETURNS : *
762: * *
763: ****************************************************************************/
764: HCONV CreateConv(
765: HSZ hszApp,
766: HSZ hszTopic,
767: BOOL fList)
768: {
769: HCONV hConv;
770: HWND hwndConv = 0;
771: CONVINFO ci;
772:
773: if (fList) {
774: hConv = (HCONV)DdeConnectList(idInst, hszApp, hszTopic, NULL, &CCFilter);
775: } else {
776: hConv = DdeConnect(idInst, hszApp, hszTopic, &CCFilter);
777: }
778: if (hConv) {
779: if (fList) {
780: ci.hszSvcPartner = hszApp;
781: ci.hszTopic = hszTopic;
782: } else {
783: ci.cb = sizeof(CONVINFO);
784: DdeQueryConvInfo(hConv, QID_SYNC, &ci);
785: }
786: hwndConv = AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, fList);
787: // HSZs get freed when window dies.
788: }
789: if (!hwndConv) {
790: DdeFreeStringHandle(idInst, hszApp);
791: DdeFreeStringHandle(idInst, hszTopic);
792: }
793: return(hConv);
794: }
795:
796:
797:
798:
799:
800:
801: /****************************************************************************
802: * *
803: * FUNCTION : AddConv() *
804: * *
805: * PURPOSE : Creates an MDI window representing a conversation *
806: * (fList = FALSE) or a set of MID windows for the list of *
807: * conversations (fList = TRUE). *
808: * *
809: * EFFECTS : Sets the hUser for the conversation to the created MDI *
810: * child hwnd. Keeps the hszs if successful. *
811: * *
812: * RETURNS : created MDI window handle. *
813: * *
814: ****************************************************************************/
815: HWND APIENTRY AddConv(
816: HSZ hszApp,
817: HSZ hszTopic,
818: HCONV hConv,
819: BOOL fList)
820: {
821: HWND hwnd;
822: MDICREATESTRUCT mcs;
823: MYCONVINFO mci;
824:
825: if (fList) {
826: /*
827: * Create all child windows FIRST so we have info for list window.
828: */
829: CONVINFO ci;
830: HCONV hConvChild = 0;
831:
832: ci.cb = sizeof(CONVINFO);
833: while (hConvChild = DdeQueryNextServer((HCONVLIST)hConv, hConvChild)) {
834: if (DdeQueryConvInfo(hConvChild, QID_SYNC, &ci)) {
835: AddConv(ci.hszSvcPartner, ci.hszTopic, hConvChild, FALSE);
836: }
837: }
838: }
839:
840: mcs.szTitle = GetConvTitleText(hConv, hszApp, hszTopic, fList);
841:
842: mcs.szClass = fList ? szList : szChild;
843: mcs.hOwner = hInst;
844: mcs.x = mcs.cx = CW_USEDEFAULT;
845: mcs.y = mcs.cy = CW_USEDEFAULT;
846: mcs.style = GetWindow(hwndMDIClient, GW_CHILD) ? 0L : WS_MAXIMIZE;
847:
848: // mci.hwndXaction =
849: mci.fList = fList;
850: mci.hConv = hConv;
851: mci.hszTopic = hszTopic;
852: mci.hszApp = hszApp;
853: // mci.x =
854: // mci.y =
855: // mci.ci =
856: mcs.lParam = (DWORD)(LPSTR)&mci;
857:
858: hwnd = (HWND)SendMessage (hwndMDIClient, WM_MDICREATE, 0,
859: (LONG)(LPMDICREATESTRUCT)&mcs);
860:
861: MyFree((PSTR)(DWORD)mcs.szTitle);
862:
863: return hwnd;
864: }
865:
866:
867:
868:
869:
870: /****************************************************************************
871: * *
872: * FUNCTION : GetConvListText() *
873: * *
874: * RETURN : Returns a ponter to a string containing a list of *
875: * conversations contained in the given hConvList freeable *
876: * by MyFree(); *
877: * *
878: ****************************************************************************/
879: PSTR GetConvListText(
880: HCONVLIST hConvList)
881: {
882: HCONV hConv = 0;
883: DWORD cConv = 0;
884: CONVINFO ci;
885: DWORD cb = 0;
886: CHAR *psz, *pszStart;
887:
888: ci.cb = sizeof(CONVINFO);
889:
890: // find out size needed.
891:
892: while (hConv = DdeQueryNextServer(hConvList, hConv)) {
893: if (DdeQueryConvInfo(hConv, QID_SYNC, &ci)) {
894: if (!IsWindow((HWND)ci.hUser)) {
895: if (ci.wStatus & ST_CONNECTED) {
896: /*
897: * This conversation doesn't have a corresponding
898: * MDI window. This is probably due to a reconnection.
899: */
900: ci.hUser = (DWORD)AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, FALSE);
901: } else {
902: continue; // skip this guy - he was closed locally.
903: }
904: }
905: cb += GetWindowTextLength((HWND)ci.hUser);
906: if (cConv++)
907: cb += 2; // room for CRLF
908: }
909: }
910: cb++; // for terminator.
911:
912: // allocate and fill
913:
914: if (pszStart = psz = MyAlloc(cb)) {
915: *psz = '\0';
916: hConv = 0;
917: while (hConv = DdeQueryNextServer(hConvList, hConv)) {
918: if (DdeQueryConvInfo(hConv, QID_SYNC, &ci) &&
919: IsWindow((HWND)ci.hUser)) {
920: psz += GetWindowText((HWND)ci.hUser, psz, cb);
921: if (--cConv) {
922: *psz++ = '\r';
923: *psz++ = '\n';
924: }
925: }
926: }
927: }
928: return(pszStart);
929: }
930:
931:
932: /****************************************************************************
933: * *
934: * FUNCTION : GetConvInfoText() *
935: * *
936: * PURPOSE : Returns a pointer to a string that reflects a *
937: * conversation's information. Freeable by MyFree(); *
938: * *
939: ****************************************************************************/
940: PSTR GetConvInfoText(
941: HCONV hConv,
942: CONVINFO *pci)
943: {
944: PSTR psz;
945: PSTR szApp;
946:
947: psz = MyAlloc(300);
948: pci->cb = sizeof(CONVINFO);
949: if (hConv) {
950: if (!DdeQueryConvInfo(hConv, QID_SYNC, (PCONVINFO)pci)) {
951: strcpy(psz, "State=Disconnected");
952: return(psz);
953: }
954: szApp = GetHSZName(pci->hszServiceReq);
955: wsprintf(psz,
956: "hUser=0x%lx\r\nhConvPartner=0x%lx\r\nhszServiceReq=%s\r\nStatus=%s\r\nState=%s\r\nLastError=%s",
957: pci->hUser, pci->hConvPartner, (LPSTR)szApp,
958: (LPSTR)Status2String(pci->wStatus),
959: (LPSTR)State2String(pci->wConvst),
960: (LPSTR)Error2String(pci->wLastError));
961: MyFree(szApp);
962: } else {
963: strcpy(psz, Error2String(DdeGetLastError(idInst)));
964: }
965: return(psz);
966: }
967:
968:
969:
970: /****************************************************************************
971: * *
972: * FUNCTION : GetConvTitleText() *
973: * *
974: * PURPOSE : Creates standard window title text based on parameters. *
975: * *
976: * RETURNS : psz freeable by MyFree() *
977: * *
978: ****************************************************************************/
979: PSTR GetConvTitleText(
980: HCONV hConv,
981: HSZ hszApp,
982: HSZ hszTopic,
983: BOOL fList)
984: {
985: DWORD cb;
986: PSTR psz;
987:
988: cb = (DWORD)DdeQueryString(idInst, hszApp, NULL, 0, 0) +
989: (DWORD)DdeQueryString(idInst, hszTopic, (LPSTR)NULL, 0, 0) +
990: (fList ? 30 : 20);
991:
992: if (psz = MyAlloc(cb)) {
993: DdeQueryString(idInst, hszApp, psz, cb, 0);
994: strcat(psz, "|");
995: DdeQueryString(idInst, hszTopic, &psz[strlen(psz)], cb, 0);
996: if (fList)
997: strcat(psz, " - LIST");
998: wsprintf(&psz[strlen(psz)], " - (%lx)", hConv);
999: }
1000: return(psz);
1001: }
1002:
1003:
1004:
1005: /****************************************************************************
1006: * *
1007: * FUNCTION : Status2String() *
1008: * *
1009: * PURPOSE : Converts a conversation status word to a string and *
1010: * returns a pointer to that string. The string is valid *
1011: * till the next call to this function. *
1012: * *
1013: ****************************************************************************/
1014: PSTR Status2String(
1015: DWORD status)
1016: {
1017: DWORD c, i;
1018: static CHAR szStatus[6 * 18];
1019: static struct {
1020: CHAR *szStatus;
1021: DWORD status;
1022: } s2s[] = {
1023: { "Connected" , ST_CONNECTED },
1024: { "Advise" , ST_ADVISE },
1025: { "IsLocal" , ST_ISLOCAL },
1026: { "Blocked" , ST_BLOCKED },
1027: { "Client" , ST_CLIENT },
1028: { "Disconnected" , ST_TERMINATED },
1029: { "BlockNext" , ST_BLOCKNEXT },
1030: };
1031: #define CFLAGS 7
1032: szStatus[0] = '\0';
1033: c = 0;
1034: for (i = 0; i < CFLAGS; i++) {
1035: if (status & s2s[i].status) {
1036: if (c++)
1037: strcat(szStatus, " | ");
1038: strcat(szStatus, s2s[i].szStatus);
1039: }
1040: }
1041: return szStatus;
1042: #undef CFLAGS
1043: }
1044:
1045:
1046:
1047:
1048: /****************************************************************************
1049: * *
1050: * FUNCTION : State2String() *
1051: * *
1052: * PURPOSE : converts a conversation state word to a string and *
1053: * returns a pointer to that string. The string is valid *
1054: * till the next call to this routine. *
1055: * *
1056: ****************************************************************************/
1057: PSTR State2String(
1058: DWORD state)
1059: {
1060: static CHAR *s2s[] = {
1061: "NULL" ,
1062: "Incomplete" ,
1063: "Standby" ,
1064: "Initiating" ,
1065: "ReqSent" ,
1066: "DataRcvd" ,
1067: "PokeSent" ,
1068: "PokeAckRcvd" ,
1069: "ExecSent" ,
1070: "ExecAckRcvd" ,
1071: "AdvSent" ,
1072: "UnadvSent" ,
1073: "AdvAckRcvd" ,
1074: "UnadvAckRcvd" ,
1075: "AdvDataSent" ,
1076: "AdvDataAckRcvd" ,
1077: "?" , // 16
1078: };
1079:
1080: if (state >= 17)
1081: return s2s[17];
1082: else
1083: return s2s[state];
1084: }
1085:
1086: /****************************************************************************
1087: * *
1088: * FUNCTION : Error2String() *
1089: * *
1090: * PURPOSE : Converts an error code to a string and returns a pointer *
1091: * to that string. The string is valid until the next call *
1092: * to this function. *
1093: * *
1094: ****************************************************************************/
1095: PSTR Error2String(
1096: DWORD error)
1097: {
1098: static CHAR szErr[23];
1099: static CHAR *e2s[] = {
1100: "Advacktimeout" ,
1101: "Busy" ,
1102: "Dataacktimeout" ,
1103: "Dll_not_initialized" ,
1104: "Dll_usage" ,
1105: "Execacktimeout" ,
1106: "Invalidparameter" ,
1107: "Low Memory warning" ,
1108: "Memory_error" ,
1109: "Notprocessed" ,
1110: "No_conv_established" ,
1111: "Pokeacktimeout" ,
1112: "Postmsg_failed" ,
1113: "Reentrancy" ,
1114: "Server_died" ,
1115: "Sys_error" ,
1116: "Unadvacktimeout" ,
1117: "Unfound_queue_id" ,
1118: };
1119: if (!error) {
1120: strcpy(szErr, "0");
1121: } else if (error > DMLERR_LAST || error < DMLERR_FIRST) {
1122: strcpy(szErr, "???");
1123: } else {
1124: strcpy(szErr, e2s[error - DMLERR_FIRST]);
1125: }
1126: return(szErr);
1127: }
1128:
1129:
1130:
1131:
1132:
1133: /****************************************************************************
1134: * *
1135: * FUNCTION : Type2String() *
1136: * *
1137: * PURPOSE : Converts a wType word and fsOption flags to a string and *
1138: * returns a pointer to that string. the string is valid *
1139: * until the next call to this function. *
1140: * *
1141: ****************************************************************************/
1142: PSTR Type2String(
1143: DWORD wType,
1144: DWORD fsOptions)
1145: {
1146: static CHAR sz[30];
1147: static CHAR o2s[] = "^!#$X*<?";
1148: static CHAR *t2s[] = {
1149: "" ,
1150: "AdvData" ,
1151: "AdvReq" ,
1152: "AdvStart" ,
1153: "AdvStop" ,
1154: "Execute" ,
1155: "Connect" ,
1156: "ConnectConfirm" ,
1157: "XactComplete" ,
1158: "Poke" ,
1159: "Register" ,
1160: "Request" ,
1161: "Term" ,
1162: "Unregister" ,
1163: "WildConnect" ,
1164: "" ,
1165: };
1166: DWORD bit, c, i;
1167:
1168: strcpy(sz, t2s[((wType & XTYP_MASK) >> XTYP_SHIFT)]);
1169: c = strlen(sz);
1170: sz[c++] = ' ';
1171: for (i = 0, bit = 1; i < 7; bit = bit << 1, i++) {
1172: if (fsOptions & bit)
1173: sz[c++] = o2s[i];
1174: }
1175: sz[c] = '\0';
1176: return(sz);
1177: }
1178:
1179:
1180:
1181:
1182: /****************************************************************************
1183: * *
1184: * FUNCTION : GetHSZName() *
1185: * *
1186: * PURPOSE : Allocates local memory for and retrieves the string form *
1187: * of an HSZ. Returns a pointer to the local memory or NULL *
1188: * if failure. The string must be freed via MyFree(). *
1189: * *
1190: ****************************************************************************/
1191: PSTR GetHSZName(
1192: HSZ hsz)
1193: {
1194: PSTR psz;
1195: DWORD cb;
1196:
1197: cb = (DWORD)DdeQueryString(idInst, hsz, NULL, 0, 0) + 1;
1198: psz = MyAlloc(cb);
1199: DdeQueryString(idInst, hsz, psz, cb, 0);
1200: return(psz);
1201: }
1202:
1203:
1204: /****************************************************************************
1205: *
1206: * FUNCTION : MyMsgFilterProc
1207: *
1208: * PURPOSE : This filter proc gets called for each message we handle.
1209: * This allows our application to properly dispatch messages
1210: * that we might not otherwise see because of DDEMLs modal
1211: * loop that is used while processing synchronous transactions.
1212: *
1213: * Generally, applications that only do synchronous transactions
1214: * in response to user input (as this app does) does not need
1215: * to install such a filter proc because it would be very rare
1216: * that a user could command the app fast enough to cause
1217: * problems. However, this is included as an example.
1218: *
1219: ****************************************************************************/
1220: DWORD APIENTRY MyMsgFilterProc(
1221: INT nCode,
1222: WPARAM wParam,
1223: DWORD lParam)
1224: {
1225: wParam; // not used
1226:
1227: #define lpmsg ((LPMSG)lParam)
1228: if (nCode == MSGF_DDEMGR) {
1229:
1230: /* If a keyboard message is for the MDI , let the MDI client
1231: * take care of it. Otherwise, check to see if it's a normal
1232: * accelerator key. Otherwise, just handle the message as usual.
1233: */
1234:
1235: if ( !TranslateMDISysAccel (hwndMDIClient, lpmsg) &&
1236: !TranslateAccelerator (hwndFrame, hAccel, lpmsg)){
1237: TranslateMessage (lpmsg);
1238: DispatchMessage (lpmsg);
1239: }
1240: return(1);
1241: }
1242: return(0);
1243: #undef lpmsg
1244: }
1245:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.