home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / DDEML / CLIENT / DDEMLCL.C_ / DDEMLCL.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  44.7 KB  |  1,235 lines

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