home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / progwin / chap17 / ddepop.c next >
Encoding:
C/C++ Source or Header  |  1990-11-12  |  22.0 KB  |  650 lines

  1. /*--------------------------------------------
  2.    DDEPOP.C -- DDE Server for Population Data
  3.                (c) Charles Petzold, 1990
  4.   --------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <dde.h>
  8. #include <string.h>
  9. #include <time.h>
  10.  
  11. struct
  12.      {
  13.      char *szState ;
  14.      long lPop70 ;
  15.      long lPop80 ;
  16.      long lPop ;
  17.      }
  18.      pop [] = {
  19.               "AL",   3444354,   3894025, 0, "AK",    302583,    401851, 0,
  20.               "AZ",   1775399,   2716598, 0, "AR",   1923322,   2286357, 0,
  21.               "CA",  19971069,  23667764, 0, "CO",   2209596,   2889735, 0,
  22.               "CT",   3032217,   3107564, 0, "DE",    548104,    594338, 0,
  23.               "DC",    756668,    638432, 0, "FL",   6791418,   9746961, 0,
  24.               "GA",   4587930,   5462982, 0, "HI",    769913,    964691, 0,
  25.               "ID",    713015,    944127, 0, "IL",  11110285,  11427409, 0,
  26.               "IN",   5195392,   5490212, 0, "IA",   2825368,   2913808, 0,
  27.               "KS",   2249071,   2364236, 0, "KY",   3220711,   3660324, 0,
  28.               "LA",   3644637,   4206116, 0, "ME",    993722,   1125043, 0,
  29.               "MD",   3923897,   4216933, 0, "MA",   5689170,   5737093, 0,
  30.               "MI",   8881826,   9262044, 0, "MN",   3806103,   4075970, 0,
  31.               "MS",   2216994,   2520770, 0, "MO",   4677623,   4916762, 0,
  32.               "MT",    694409,    786690, 0, "NE",   1485333,   1569825, 0,
  33.               "NV",    488738,    800508, 0, "NH",    737681,    920610, 0,
  34.               "NJ",   7171112,   7365011, 0, "NM",   1017055,   1303302, 0,
  35.               "NY",  18241391,  17558165, 0, "NC",   5084411,   5880415, 0,
  36.               "ND",    617792,    652717, 0, "OH",  10657423,  10797603, 0,
  37.               "OK",   2559463,   3025487, 0, "OR",   2091533,   2633156, 0,
  38.               "PA",  11800766,  11864720, 0, "RI",    949723,    947154, 0,
  39.               "SC",   2590713,   3120730, 0, "SD",    666257,    690768, 0,
  40.               "TN",   3926018,   4591023, 0, "TX",  11198655,  14225513, 0,
  41.               "UT",   1059273,   1461037, 0, "VT",    444732,    511456, 0,
  42.               "VA",   4651448,   5346797, 0, "WA",   3413244,   4132353, 0,
  43.               "WV",   1744237,   1950186, 0, "WI",   4417821,   4705642, 0,
  44.               "WY",    332416,    469557, 0, "US", 203302031, 226542580, 0
  45.               } ;
  46.  
  47. #define NUM_STATES (sizeof (pop) / sizeof (pop [0]))
  48.  
  49. typedef struct
  50.      {
  51.      unsigned int fAdvise:1 ;
  52.      unsigned int fDeferUpd:1 ;
  53.      unsigned int fAckReq:1 ;
  54.      unsigned int dummy:13 ;
  55.      long         lPopPrev ;
  56.      }
  57.      POPADVISE ;
  58.  
  59. #define ID_TIMER    1
  60. #define DDE_TIMEOUT 3000
  61.  
  62. long FAR PASCAL WndProc         (HWND, WORD, WORD, LONG) ;
  63. long FAR PASCAL ServerProc      (HWND, WORD, WORD, LONG) ;
  64. BOOL FAR PASCAL TimerEnumProc   (HWND, LONG) ;
  65. BOOL FAR PASCAL CloseEnumProc   (HWND, LONG) ;
  66. BOOL            PostDataMessage (HWND, HWND, int, BOOL, BOOL, BOOL) ;
  67.  
  68. char   szAppName []     = "DdePop" ;
  69. char   szServerClass [] = "DdePop.Server" ;
  70. HANDLE hInst ;
  71.  
  72. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  73.                     LPSTR lpszCmdLine, int nCmdShow)
  74.      {
  75.      HWND     hwnd ;
  76.      MSG      msg ;
  77.      WNDCLASS wndclass ;
  78.  
  79.      if (hPrevInstance) 
  80.           return FALSE ;
  81.  
  82.      hInst = hInstance ;
  83.  
  84.                // Register window class
  85.  
  86.      wndclass.style         = 0 ;
  87.      wndclass.lpfnWndProc   = WndProc ;
  88.      wndclass.cbClsExtra    = 0 ;
  89.      wndclass.cbWndExtra    = 0 ;
  90.      wndclass.hInstance     = hInstance ;
  91.      wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
  92.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  93.      wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  94.      wndclass.lpszMenuName  = NULL ;
  95.      wndclass.lpszClassName = szAppName ;
  96.  
  97.      RegisterClass (&wndclass) ;
  98.  
  99.                // Register window class for DDE Server
  100.  
  101.      wndclass.style         = 0 ;
  102.      wndclass.lpfnWndProc   = ServerProc ;
  103.      wndclass.cbClsExtra    = 0 ;
  104.      wndclass.cbWndExtra    = 2 * sizeof (WORD) ;
  105.      wndclass.hInstance     = hInstance ;
  106.      wndclass.hIcon         = NULL ;
  107.      wndclass.hCursor       = NULL ;
  108.      wndclass.hbrBackground = NULL ;
  109.      wndclass.lpszMenuName  = NULL ;
  110.      wndclass.lpszClassName = szServerClass ;
  111.  
  112.      RegisterClass (&wndclass) ;
  113.  
  114.      hwnd = CreateWindow (szAppName, "DDE Population Server",
  115.                           WS_OVERLAPPEDWINDOW,
  116.                           CW_USEDEFAULT, CW_USEDEFAULT,
  117.                           CW_USEDEFAULT, CW_USEDEFAULT,
  118.                           NULL, NULL, hInstance, NULL) ;
  119.  
  120.      SendMessage (hwnd, WM_TIMER, 0, 0L) ;   // initialize 'pop' structure
  121.  
  122.      if (!SetTimer (hwnd, ID_TIMER, 5000, NULL))
  123.           {
  124.           MessageBox (hwnd, "Too many clocks or timers!", szAppName,
  125.                       MB_ICONEXCLAMATION | MB_OK) ;
  126.  
  127.           return FALSE ;
  128.           }
  129.  
  130.      ShowWindow (hwnd, SW_SHOWMINNOACTIVE) ;
  131.      UpdateWindow (hwnd) ;
  132.  
  133.      while (GetMessage (&msg, NULL, 0, 0))
  134.           {
  135.           TranslateMessage (&msg) ;
  136.           DispatchMessage (&msg) ;
  137.           }
  138.  
  139.      KillTimer (hwnd, ID_TIMER) ;
  140.  
  141.      return msg.wParam ;
  142.      }
  143.  
  144. long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  145.      {
  146.      static FARPROC lpTimerEnumProc, lpCloseEnumProc ;
  147.      static char    szTopic [] = "US_Population" ;
  148.      ATOM           aApp, aTop ;
  149.      HWND           hwndClient, hwndServer ;
  150.      int            i ;
  151.      long double    ldSecsInDecade, ldSecSince1970 ;
  152.      time_t         lSecSince1970 ;
  153.  
  154.      switch (message)
  155.           {
  156.           case WM_CREATE:
  157.                lpTimerEnumProc = MakeProcInstance (TimerEnumProc, hInst) ;
  158.                lpCloseEnumProc = MakeProcInstance (CloseEnumProc, hInst) ;
  159.                return 0 ;
  160.  
  161.           case WM_DDE_INITIATE:
  162.  
  163.                     // wParam          -- sending window handle
  164.                     // LOWORD (lParam) -- application atom
  165.                     // HIWORD (lParam) -- topic atom
  166.  
  167.                hwndClient = wParam ;
  168.  
  169.                aApp = GlobalAddAtom (szAppName) ;
  170.                aTop = GlobalAddAtom (szTopic) ;
  171.  
  172.                     // Check for matching atoms, create window, and acknowledge
  173.  
  174.                if ((LOWORD (lParam) == NULL || LOWORD (lParam) == aApp) &&
  175.                    (HIWORD (lParam) == NULL || HIWORD (lParam) == aTop))
  176.                     {
  177.                     hwndServer = CreateWindow (szServerClass, NULL,
  178.                                                WS_CHILD, 0, 0, 0, 0,
  179.                                                hwnd, NULL, hInst, NULL) ;
  180.  
  181.                     SetWindowWord (hwndServer, 0, hwndClient) ;
  182.                     SendMessage (wParam, WM_DDE_ACK, hwndServer,
  183.                                  MAKELONG (aApp, aTop)) ;
  184.                     }
  185.  
  186.                     // Otherwise, delete the atoms just created
  187.  
  188.                else
  189.                     {
  190.                     GlobalDeleteAtom (aApp) ;
  191.                     GlobalDeleteAtom (aTop) ;
  192.                     }
  193.  
  194.                return 0 ;
  195.  
  196.           case WM_TIMER:
  197.           case WM_TIMECHANGE:
  198.                time (&lSecSince1970) ;
  199.  
  200.                     // Calculate new current populations
  201.  
  202.                ldSecSince1970 = (long double) lSecSince1970 ;
  203.                ldSecsInDecade = (long double) 3652 * 24 * 60 * 60 ;
  204.  
  205.                for (i = 0 ; i < NUM_STATES ; i++)
  206.                     {
  207.                     pop[i].lPop = (long)
  208.                          (((ldSecsInDecade - ldSecSince1970) * pop[i].lPop70 +
  209.                             ldSecSince1970 * pop[i].lPop80) / ldSecsInDecade
  210.                                    + .5) ;
  211.                     }
  212.  
  213.                     // Notify all child windows
  214.  
  215.                EnumChildWindows (hwnd, lpTimerEnumProc, 0L) ;
  216.                return 0 ;
  217.  
  218.           case WM_QUERYOPEN:
  219.                return 0 ;
  220.  
  221.           case WM_CLOSE:
  222.  
  223.                     // Notify all child windows
  224.  
  225.                EnumChildWindows (hwnd, lpCloseEnumProc, 0L) ;
  226.  
  227.                break ;                  // for default processing
  228.  
  229.           case WM_DESTROY:
  230.                PostQuitMessage (0) ;
  231.                return 0 ;
  232.           }
  233.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  234.      }
  235.  
  236. long FAR PASCAL ServerProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  237.      {
  238.      ATOM          aItem ;
  239.      char          szItem [10], szPopulation [10] ;
  240.      DDEACK        DdeAck ;
  241.      DDEADVISE     Advise ;
  242.      DDEADVISE FAR *lpDdeAdvise ;
  243.      DDEDATA FAR   *lpDdeData ;
  244.      DWORD         dwTime ;
  245.      GLOBALHANDLE  hPopAdvise, hDdeData, hDdeAdvise, hCommands, hDdePoke ;
  246.      int           i ;
  247.      HWND          hwndClient ;
  248.      MSG           msg ;
  249.      POPADVISE FAR *lpPopAdvise ;
  250.      WORD          cfFormat, wStatus ;
  251.  
  252.      switch (message)
  253.           {
  254.           case WM_CREATE:
  255.  
  256.                     // Allocate memory for POPADVISE structures
  257.  
  258.                hPopAdvise = GlobalAlloc (GHND, NUM_STATES * sizeof (POPADVISE));
  259.  
  260.                if (hPopAdvise == NULL)
  261.                     DestroyWindow (hwnd) ;
  262.                else
  263.                     SetWindowWord (hwnd, 2, hPopAdvise) ;
  264.  
  265.                return 0 ;
  266.  
  267.           case WM_DDE_REQUEST:
  268.  
  269.                     // wParam          -- sending window handle
  270.                     // LOWORD (lParam) -- data format
  271.                     // HIWORD (lParam) -- item atom
  272.  
  273.                hwndClient = wParam ;
  274.                cfFormat   = LOWORD (lParam) ;
  275.                aItem      = HIWORD (lParam) ;
  276.  
  277.                     // Check for matching format and data item
  278.  
  279.                if (cfFormat == CF_TEXT)
  280.                     {
  281.                     GlobalGetAtomName (aItem, szItem, sizeof (szItem)) ;
  282.  
  283.                     for (i = 0 ; i < NUM_STATES ; i++)
  284.                          if (strcmp (szItem, pop[i].szState) == 0)
  285.                               break ;
  286.  
  287.                     if (i < NUM_STATES)
  288.                          {
  289.                          GlobalDeleteAtom (aItem) ;
  290.                          PostDataMessage (hwnd, hwndClient, i,
  291.                                           FALSE, FALSE, TRUE) ;
  292.                          return 0 ;
  293.                          }
  294.                     }
  295.  
  296.                     // Negative acknowledge if no match
  297.  
  298.                DdeAck.bAppReturnCode = 0 ;
  299.                DdeAck.reserved       = 0 ;
  300.                DdeAck.fBusy          = FALSE ;
  301.                DdeAck.fAck           = FALSE ;
  302.  
  303.                wStatus = * (WORD *) & DdeAck ;
  304.  
  305.                if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  306.                                  MAKELONG (wStatus, aItem)))
  307.                     {
  308.                     GlobalDeleteAtom (aItem) ;
  309.                     }
  310.  
  311.                return 0 ;
  312.  
  313.           case WM_DDE_ADVISE:
  314.  
  315.                     // wParam          -- sending window handle
  316.                     // LOWORD (lParam) -- DDEADVISE memory handle
  317.                     // HIWORD (lParam) -- item atom
  318.  
  319.                hwndClient = wParam ;
  320.                hDdeAdvise = LOWORD (lParam) ;
  321.                aItem      = HIWORD (lParam) ;
  322.  
  323.                lpDdeAdvise = (DDEADVISE FAR *) GlobalLock (hDdeAdvise) ;
  324.  
  325.                     // Check for matching format and data item
  326.  
  327.                if (lpDdeAdvise->cfFormat == CF_TEXT)
  328.                     {
  329.                     GlobalGetAtomName (aItem, szItem, sizeof (szItem)) ;
  330.  
  331.                     for (i = 0 ; i < NUM_STATES ; i++)
  332.                          if (strcmp (szItem, pop[i].szState) == 0)
  333.                               break ;
  334.  
  335.                          // Fill in the POPADVISE structure and acknowledge
  336.  
  337.                     if (i < NUM_STATES)
  338.                          {
  339.                          hPopAdvise = GetWindowWord (hwnd, 2) ;
  340.                          lpPopAdvise = (POPADVISE FAR *)
  341.                                               GlobalLock (hPopAdvise) ;
  342.  
  343.                          lpPopAdvise[i].fAdvise   = TRUE ;
  344.                          lpPopAdvise[i].fDeferUpd = lpDdeAdvise->fDeferUpd ;
  345.                          lpPopAdvise[i].fAckReq   = lpDdeAdvise->fAckReq ;
  346.                          lpPopAdvise[i].lPopPrev  = pop[i].lPop ;
  347.  
  348.                          GlobalUnlock (hDdeAdvise) ;
  349.                          GlobalFree (hDdeAdvise) ;
  350.  
  351.                          DdeAck.bAppReturnCode = 0 ;
  352.                          DdeAck.reserved       = 0 ;
  353.                          DdeAck.fBusy          = FALSE ;
  354.                          DdeAck.fAck           = TRUE ;
  355.  
  356.                          wStatus = * (WORD *) & DdeAck ;
  357.  
  358.                          if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  359.                                            MAKELONG (wStatus, aItem)))
  360.                               {
  361.                               GlobalDeleteAtom (aItem) ;
  362.                               }
  363.                          else
  364.                               {
  365.                               PostDataMessage (hwnd, hwndClient, i,
  366.                                                lpPopAdvise[i].fDeferUpd,
  367.                                                lpPopAdvise[i].fAckReq,
  368.                                                FALSE) ;
  369.                               }
  370.  
  371.                          GlobalUnlock (hPopAdvise) ;
  372.                          return 0 ;
  373.                          }
  374.                     }
  375.  
  376.                          // Otherwise post a negative WM_DDE_ACK
  377.  
  378.                GlobalUnlock (hDdeAdvise) ;
  379.  
  380.                DdeAck.bAppReturnCode = 0 ;
  381.                DdeAck.reserved       = 0 ;
  382.                DdeAck.fBusy          = FALSE ;
  383.                DdeAck.fAck           = FALSE ;
  384.  
  385.                wStatus = * (WORD *) & DdeAck ;
  386.  
  387.                if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  388.                                  MAKELONG (wStatus, aItem)))
  389.                     {
  390.                     GlobalFree (hDdeAdvise) ;
  391.                     GlobalDeleteAtom (aItem) ;
  392.                     }
  393.  
  394.                return 0 ;
  395.  
  396.           case WM_DDE_UNADVISE:
  397.  
  398.                     // wParam          -- sending window handle
  399.                     // LOWORD (lParam) -- data format
  400.                     // HIWORD (lParam) -- item atom
  401.  
  402.                hwndClient = wParam ;
  403.                cfFormat   = LOWORD (lParam) ;
  404.                aItem      = HIWORD (lParam) ;
  405.  
  406.                DdeAck.bAppReturnCode = 0 ;
  407.                DdeAck.reserved       = 0 ;
  408.                DdeAck.fBusy          = FALSE ;
  409.                DdeAck.fAck           = TRUE ;
  410.  
  411.                hPopAdvise  = GetWindowWord (hwnd, 2) ;
  412.                lpPopAdvise = (POPADVISE FAR *) GlobalLock (hPopAdvise) ;
  413.  
  414.                     // Check for matching format and data item
  415.  
  416.                if (cfFormat == CF_TEXT || cfFormat == 0)
  417.                     {
  418.                     if (aItem == NULL)
  419.                          for (i = 0 ; i < NUM_STATES ; i++)
  420.                               lpPopAdvise[i].fAdvise = FALSE ;
  421.                     else
  422.                          {
  423.                          GlobalGetAtomName (aItem, szItem, sizeof (szItem)) ;
  424.  
  425.                          for (i = 0 ; i < NUM_STATES ; i++)
  426.                               if (strcmp (szItem, pop[i].szState) == 0)
  427.                                    break ;
  428.  
  429.                          if (i < NUM_STATES)
  430.                               lpPopAdvise[i].fAdvise = FALSE ;
  431.                          else
  432.                               DdeAck.fAck = FALSE ;
  433.                          }
  434.                     }
  435.                else
  436.                     DdeAck.fAck = FALSE ;
  437.  
  438.                     // Acknowledge either positively or negatively
  439.  
  440.                wStatus = * (WORD *) & DdeAck ;
  441.  
  442.                if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  443.                                  MAKELONG (wStatus, aItem)))
  444.                     {
  445.                     if (aItem != NULL)
  446.                          GlobalDeleteAtom (aItem) ;
  447.                     }
  448.  
  449.                GlobalUnlock (hPopAdvise) ;
  450.                return 0 ;
  451.  
  452.           case WM_DDE_EXECUTE:
  453.  
  454.                     // Post negative acknowledge
  455.  
  456.                hwndClient = wParam ;
  457.                hCommands  = HIWORD (lParam) ;
  458.  
  459.                DdeAck.bAppReturnCode = 0 ;
  460.                DdeAck.reserved       = 0 ;
  461.                DdeAck.fBusy          = FALSE ;
  462.                DdeAck.fAck           = FALSE ;
  463.  
  464.                wStatus = * (WORD *) & DdeAck ;
  465.  
  466.                if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  467.                                  MAKELONG (wStatus, hCommands)))
  468.                     {
  469.                     GlobalFree (hCommands) ;
  470.                     }
  471.                return 0 ;
  472.  
  473.           case WM_DDE_POKE:
  474.  
  475.                     // Post negative acknowledge
  476.  
  477.                hwndClient = wParam ;
  478.                hDdePoke   = LOWORD (lParam) ;
  479.                aItem      = HIWORD (lParam) ;
  480.  
  481.                DdeAck.bAppReturnCode = 0 ;
  482.                DdeAck.reserved       = 0 ;
  483.                DdeAck.fBusy          = FALSE ;
  484.                DdeAck.fAck           = FALSE ;
  485.  
  486.                wStatus = * (WORD *) & DdeAck ;
  487.  
  488.                if (!PostMessage (hwndClient, WM_DDE_ACK, hwnd,
  489.                                  MAKELONG (wStatus, aItem)))
  490.                     {
  491.                     GlobalFree (hDdePoke) ;
  492.                     GlobalDeleteAtom (aItem) ;
  493.                     }
  494.  
  495.                return 0 ;
  496.  
  497.           case WM_DDE_TERMINATE:
  498.  
  499.                     // Respond with another WM_DDE_TERMINATE message
  500.  
  501.                hwndClient = wParam ;
  502.                PostMessage (hwndClient, WM_DDE_TERMINATE, hwnd, 0L) ;
  503.                DestroyWindow (hwnd) ;
  504.                return 0 ;
  505.  
  506.           case WM_TIMER:
  507.  
  508.                     // Post WM_DDE_DATA messages for changed populations
  509.  
  510.                hwndClient  = GetWindowWord (hwnd, 0) ;
  511.                hPopAdvise  = GetWindowWord (hwnd, 2) ;
  512.                lpPopAdvise = (POPADVISE FAR *) GlobalLock (hPopAdvise) ;
  513.  
  514.                for (i = 0 ; i < NUM_STATES ; i++)
  515.                     if (lpPopAdvise[i].fAdvise)
  516.                          if (lpPopAdvise[i].lPopPrev != pop[i].lPop)
  517.                               {
  518.                               if (!PostDataMessage (hwnd, hwndClient, i,
  519.                                                     lpPopAdvise[i].fDeferUpd,
  520.                                                     lpPopAdvise[i].fAckReq,
  521.                                                     FALSE))
  522.                                    break ;
  523.  
  524.                               lpPopAdvise[i].lPopPrev = pop[i].lPop ;
  525.                               }
  526.  
  527.                GlobalUnlock (hPopAdvise) ;
  528.                return 0 ;
  529.  
  530.           case WM_CLOSE:
  531.  
  532.                     // Post a WM_DDE_TERMINATE message to the client
  533.  
  534.                hwndClient = GetWindowWord (hwnd, 0) ;
  535.                PostMessage (hwndClient, WM_DDE_TERMINATE, hwnd, 0L) ;
  536.  
  537.                dwTime = GetCurrentTime () ;
  538.  
  539.                while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  540.                     if (PeekMessage (&msg, hwnd, WM_DDE_TERMINATE,
  541.                                      WM_DDE_TERMINATE, PM_REMOVE))
  542.                          break ;
  543.  
  544.                DestroyWindow (hwnd) ;
  545.                return 0 ;
  546.  
  547.           case WM_DESTROY:
  548.                hPopAdvise = GetWindowWord (hwnd, 2) ;
  549.                GlobalFree (hPopAdvise) ;
  550.                return 0 ;
  551.           }
  552.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  553.      }
  554.  
  555. BOOL FAR PASCAL TimerEnumProc (HWND hwnd, LONG lParam)
  556.      {
  557.      SendMessage (hwnd, WM_TIMER, 0, 0L) ;
  558.  
  559.      return TRUE ;
  560.      }
  561.  
  562. BOOL FAR PASCAL CloseEnumProc (HWND hwnd, LONG lParam)
  563.      {
  564.      SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
  565.  
  566.      return TRUE ;
  567.      }
  568.  
  569. BOOL PostDataMessage (HWND hwndServer, HWND hwndClient, int iState,
  570.                       BOOL fDeferUpd, BOOL fAckReq, BOOL fResponse)
  571.      {
  572.      ATOM         aItem ;
  573.      char         szPopulation [10] ;
  574.      DDEACK       DdeAck ;
  575.      DDEDATA FAR  *lpDdeData ;
  576.      DWORD        dwTime ;
  577.      GLOBALHANDLE hDdeData ;
  578.      MSG          msg ;
  579.  
  580.      aItem = GlobalAddAtom (pop[iState].szState) ;
  581.  
  582.           // Allocate a DDEDATA structure if not defered update
  583.  
  584.      if (fDeferUpd)
  585.           {
  586.           hDdeData = NULL ;
  587.           }
  588.      else
  589.           {
  590.           wsprintf (szPopulation, "%ld\r\n", pop[iState].lPop) ;
  591.  
  592.           hDdeData = GlobalAlloc (GHND | GMEM_DDESHARE,
  593.                                   sizeof (DDEDATA) + strlen (szPopulation)) ;
  594.  
  595.           lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData) ;
  596.  
  597.           lpDdeData->fResponse = fResponse ;
  598.           lpDdeData->fRelease  = TRUE ;
  599.           lpDdeData->fAckReq   = fAckReq ;
  600.           lpDdeData->cfFormat  = CF_TEXT ;
  601.  
  602.           lstrcpy ((LPSTR) lpDdeData->Value, szPopulation) ;
  603.  
  604.           GlobalUnlock (hDdeData) ;
  605.           }
  606.  
  607.           // Post the WM_DDE_DATA message
  608.  
  609.      if (!PostMessage (hwndClient, WM_DDE_DATA, hwndServer,
  610.                        MAKELONG (hDdeData, aItem)))
  611.           {
  612.           if (hDdeData != NULL)
  613.                GlobalFree (hDdeData) ;
  614.  
  615.           GlobalDeleteAtom (aItem) ;
  616.           return FALSE ;
  617.           }
  618.  
  619.           // Wait for the acknowledge message if it's requested
  620.  
  621.      if (fAckReq)
  622.           {
  623.           DdeAck.fAck = FALSE ;
  624.  
  625.           dwTime = GetCurrentTime () ;
  626.  
  627.           while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  628.                {
  629.                if (PeekMessage (&msg, hwndServer, WM_DDE_ACK, WM_DDE_ACK,
  630.                                 PM_REMOVE))
  631.                     {
  632.                     DdeAck = * (DDEACK *) & LOWORD (msg.lParam) ;
  633.                     aItem  = HIWORD (msg.lParam) ;
  634.                     GlobalDeleteAtom (aItem) ;
  635.                     break ;
  636.                     }
  637.                }
  638.  
  639.           if (DdeAck.fAck == FALSE)
  640.                {
  641.                if (hDdeData != NULL)
  642.                     GlobalFree (hDdeData) ;
  643.  
  644.                return FALSE ;
  645.                }
  646.           }
  647.  
  648.      return TRUE ;
  649.      }
  650.