DDEMLCL.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:47k
源码类别:

Windows编程

开发平台:

Visual C++

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