home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / ipc / ddeml / client / ddemlcl.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  48KB  |  1,284 lines

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