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

  1. /*----------------------------------------
  2.    SHOWPOP.C -- DDE Client using DDEPOP
  3.                 (c) Charles Petzold, 1990
  4.   ----------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <dde.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. struct
  12.      {
  13.      char *szAbb ;
  14.      char *szState ;
  15.      long lPop ;
  16.      }
  17.      pop [] = {
  18.               "AL", "Alabama",             0, "AK", "Alaska",              0,
  19.               "AZ", "Arizona",             0, "AR", "Arkansas",            0,
  20.               "CA", "California",          0, "CO", "Colorado",            0,
  21.               "CT", "Connecticut",         0, "DE", "Delaware",            0,
  22.               "DC", "Dist. of Columbia",   0, "FL", "Florida",             0,
  23.               "GA", "Georgia",             0, "HI", "Hawaii",              0,
  24.               "ID", "Idaho",               0, "IL", "Illinois",            0,
  25.               "IN", "Indiana",             0, "IA", "Iowa",                0,
  26.               "KS", "Kansas",              0, "KY", "Kentucky",            0,
  27.               "LA", "Louisiana",           0, "ME", "Maine",               0,
  28.               "MD", "Maryland",            0, "MA", "Massachusetts",       0,
  29.               "MI", "Michigan",            0, "MN", "Minnesota",           0,
  30.               "MS", "Mississippi",         0, "MO", "Missouri",            0,
  31.               "MT", "Montana",             0, "NE", "Nebraska",            0,
  32.               "NV", "Nevada",              0, "NH", "New Hampshire",       0,
  33.               "NJ", "New Jersey",          0, "NM", "New Mexico",          0,
  34.               "NY", "New York",            0, "NC", "North Carolina",      0,
  35.               "ND", "North Dakota",        0, "OH", "Ohio",                0,
  36.               "OK", "Oklahoma",            0, "OR", "Oregon",              0,
  37.               "PA", "Pennsylvania",        0, "RI", "Rhode Island",        0,
  38.               "SC", "South Carolina",      0, "SD", "South Dakota",        0,
  39.               "TN", "Tennessee",           0, "TX", "Texas",               0,
  40.               "UT", "Utah",                0, "VT", "Vermont",             0,
  41.               "VA", "Virginia",            0, "WA", "Washington",          0,
  42.               "WV", "West Virginia",       0, "WI", "Wisconsin",           0,
  43.               "WY", "Wyoming",             0, "US", "United States Total", 0
  44.               } ;
  45.  
  46. #define NUM_STATES       (sizeof (pop) / sizeof (pop [0]))
  47. #define WM_USER_INITIATE (WM_USER + 1)
  48. #define DDE_TIMEOUT      3000
  49.  
  50. long FAR PASCAL WndProc  (HWND, WORD, WORD, LONG) ;
  51.  
  52. char   szAppName [] = "ShowPop" ;
  53.  
  54. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  55.                     LPSTR lpszCmdLine, int nCmdShow)
  56.      {
  57.      HWND     hwnd ;
  58.      MSG      msg ;
  59.      WNDCLASS wndclass ;
  60.  
  61.      if (!hPrevInstance) 
  62.           {
  63.           wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  64.           wndclass.lpfnWndProc   = WndProc ;
  65.           wndclass.cbClsExtra    = 0 ;
  66.           wndclass.cbWndExtra    = 0 ;
  67.           wndclass.hInstance     = hInstance ;
  68.           wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
  69.           wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  70.           wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  71.           wndclass.lpszMenuName  = NULL ;
  72.           wndclass.lpszClassName = szAppName ;
  73.  
  74.           RegisterClass (&wndclass) ;
  75.           }
  76.  
  77.      hwnd = CreateWindow (szAppName, "DDE Client - US Population",
  78.                           WS_OVERLAPPEDWINDOW,
  79.                           CW_USEDEFAULT, CW_USEDEFAULT,
  80.                           CW_USEDEFAULT, CW_USEDEFAULT,
  81.                           NULL, NULL, hInstance, NULL) ;
  82.  
  83.      ShowWindow (hwnd, nCmdShow) ;
  84.      UpdateWindow (hwnd) ;
  85.  
  86.      SendMessage (hwnd, WM_USER_INITIATE, 0, 0L) ;
  87.  
  88.      while (GetMessage (&msg, NULL, 0, 0))
  89.           {
  90.           TranslateMessage (&msg) ;
  91.           DispatchMessage (&msg) ;
  92.           }
  93.      return msg.wParam ;
  94.      }
  95.  
  96. long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  97.      {
  98.      static BOOL   fDoingInitiate = TRUE ;
  99.      static char   szServerApp [] = "DdePop",
  100.                    szTopic     [] = "US_Population" ;
  101.      static HWND   hwndServer = NULL ;
  102.      static short  cxChar, cyChar ;
  103.      ATOM          aApp, aTop, aItem ;
  104.      char          szBuffer [24], szPopulation [16], szItem [16] ;
  105.      DDEACK        DdeAck ;
  106.      DDEDATA FAR   *lpDdeData ;
  107.      DDEADVISE FAR *lpDdeAdvise ;
  108.      DWORD         dwTime ;
  109.      GLOBALHANDLE  hDdeAdvise, hDdeData ;
  110.      HDC           hdc ;
  111.      MSG           msg ;
  112.      PAINTSTRUCT   ps ;
  113.      short         i, x, y ;
  114.      TEXTMETRIC    tm ;
  115.      WORD          wStatus, cfFormat ;
  116.  
  117.      switch (message)
  118.           {
  119.           case WM_CREATE:
  120.                hdc = GetDC (hwnd) ;
  121.                GetTextMetrics (hdc, &tm) ;
  122.                cxChar = tm.tmAveCharWidth ;
  123.                cyChar = tm.tmHeight + tm.tmExternalLeading ;
  124.                ReleaseDC (hwnd, hdc) ;
  125.                return 0 ;
  126.  
  127.           case WM_USER_INITIATE:
  128.  
  129.                      // Broadcast WM_DDE_INITIATE message
  130.  
  131.                aApp = GlobalAddAtom (szServerApp) ;
  132.                aTop = GlobalAddAtom (szTopic) ;
  133.  
  134.                SendMessage (0xFFFF, WM_DDE_INITIATE, hwnd,
  135.                             MAKELONG (aApp, aTop)) ;
  136.  
  137.                      // If no response, try loading DDEPOP first
  138.  
  139.                if (hwndServer == NULL)
  140.                     {
  141.                     WinExec (szServerApp, SW_SHOWMINNOACTIVE) ;
  142.  
  143.                     SendMessage (0xFFFF, WM_DDE_INITIATE, hwnd,
  144.                                  MAKELONG (aApp, aTop)) ;
  145.                     }
  146.  
  147.                     // Delete the atoms
  148.  
  149.                GlobalDeleteAtom (aApp) ;
  150.                GlobalDeleteAtom (aTop) ;
  151.                fDoingInitiate = FALSE ;
  152.  
  153.                     // If still no response, display message box
  154.  
  155.                if (hwndServer == NULL)
  156.                     {
  157.                     MessageBox (hwnd, "Cannot connect with DDEPOP.EXE!",
  158.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  159.  
  160.                     return 0 ;
  161.                     }
  162.  
  163.                     // Post WM_DDE_ADVISE messages
  164.  
  165.                for (i = 0 ; i < NUM_STATES ; i++)
  166.                     {
  167.                     hDdeAdvise = GlobalAlloc (GHND | GMEM_DDESHARE,
  168.                                               sizeof (DDEADVISE)) ;
  169.  
  170.                     lpDdeAdvise = (DDEADVISE FAR *) GlobalLock (hDdeAdvise) ;
  171.  
  172.                     lpDdeAdvise->fAckReq   = TRUE ;
  173.                     lpDdeAdvise->fDeferUpd = FALSE ;
  174.                     lpDdeAdvise->cfFormat  = CF_TEXT ;
  175.  
  176.                     GlobalUnlock (hDdeAdvise) ;
  177.  
  178.                     aItem = GlobalAddAtom (pop[i].szAbb) ;
  179.  
  180.                     if (!PostMessage (hwndServer, WM_DDE_ADVISE, hwnd,
  181.                                       MAKELONG (hDdeAdvise, aItem)))
  182.                          {
  183.                          GlobalFree (hDdeAdvise) ;
  184.                          GlobalDeleteAtom (aItem) ;
  185.                          break ;
  186.                          }
  187.  
  188.                     DdeAck.fAck = FALSE ;
  189.  
  190.                     dwTime = GetCurrentTime () ;
  191.  
  192.                     while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  193.                          {
  194.                          if (PeekMessage (&msg, hwnd, WM_DDE_ACK,
  195.                                           WM_DDE_ACK, PM_REMOVE))
  196.                               {
  197.                               GlobalDeleteAtom (HIWORD (msg.lParam)) ;
  198.  
  199.                               DdeAck = * (DDEACK *) & LOWORD (msg.lParam);
  200.  
  201.                               if (DdeAck.fAck == FALSE)
  202.                                    GlobalFree (hDdeAdvise) ;
  203.  
  204.                               break ;
  205.                               }
  206.                          }
  207.  
  208.                     if (DdeAck.fAck == FALSE)
  209.                          break ;
  210.  
  211.                     while (PeekMessage (&msg, hwnd, WM_DDE_FIRST,
  212.                                         WM_DDE_LAST, PM_REMOVE))
  213.                          {
  214.                          DispatchMessage (&msg) ;
  215.                          }
  216.                     }
  217.  
  218.                if (i < NUM_STATES)
  219.                     {
  220.                     MessageBox (hwnd, "Failure on WM_DDE_ADVISE!",
  221.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  222.                     }
  223.                return 0 ;
  224.  
  225.           case WM_DDE_ACK:
  226.  
  227.                     // In response to WM_DDE_INITIATE, save server window
  228.  
  229.                if (fDoingInitiate)
  230.                     {
  231.                     hwndServer = wParam ;
  232.                     GlobalDeleteAtom (LOWORD (lParam)) ;
  233.                     GlobalDeleteAtom (HIWORD (lParam)) ;
  234.                     }
  235.                return 0 ;
  236.  
  237.           case WM_DDE_DATA:
  238.  
  239.                     // wParam          -- sending window handle
  240.                     // LOWORD (lParam) -- DDEDATA memory handle
  241.                     // HIWORD (lParam) -- item atom
  242.  
  243.                hDdeData  = LOWORD (lParam) ;
  244.                lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData) ;
  245.                aItem     = HIWORD (lParam) ;
  246.  
  247.                     // Initialize DdeAck structure
  248.  
  249.                DdeAck.bAppReturnCode = 0 ;
  250.                DdeAck.reserved       = 0 ;
  251.                DdeAck.fBusy          = FALSE ;
  252.                DdeAck.fAck           = FALSE ;
  253.  
  254.                     // Check for matching format and data item
  255.  
  256.                if (lpDdeData->cfFormat == CF_TEXT)
  257.                     {
  258.                     GlobalGetAtomName (aItem, szItem, sizeof (szItem)) ;
  259.  
  260.                     for (i = 0 ; i < NUM_STATES ; i++)
  261.                          if (strcmp (szItem, pop[i].szAbb) == 0)
  262.                               break ;
  263.  
  264.                     if (i < NUM_STATES)
  265.                          {
  266.                          lstrcpy (szPopulation, lpDdeData->Value) ;
  267.                          pop[i].lPop = atol (szPopulation) ;
  268.                          InvalidateRect (hwnd, NULL, FALSE) ;
  269.  
  270.                          DdeAck.fAck = TRUE ;
  271.                          }
  272.                     }
  273.  
  274.                     // Acknowledge if necessary
  275.  
  276.                if (lpDdeData->fAckReq == TRUE)
  277.                     {
  278.                     wStatus = * (WORD *) & DdeAck ;
  279.  
  280.                     if (!PostMessage (wParam, WM_DDE_ACK, hwnd,
  281.                                       MAKELONG (wStatus, aItem)))
  282.                          {
  283.                          GlobalDeleteAtom (aItem) ;
  284.                          GlobalUnlock (hDdeData) ;
  285.                          GlobalFree (hDdeData) ;
  286.                          return 0 ;
  287.                          }
  288.                     }
  289.                else
  290.                     {
  291.                     GlobalDeleteAtom (aItem) ;
  292.                     }
  293.  
  294.                     // Clean up
  295.  
  296.                if (lpDdeData->fRelease == TRUE || DdeAck.fAck == FALSE)
  297.                     {
  298.                     GlobalUnlock (hDdeData) ;
  299.                     GlobalFree (hDdeData) ;
  300.                     }
  301.                else
  302.                     {
  303.                     GlobalUnlock (hDdeData) ;
  304.                     }
  305.  
  306.                return 0 ;
  307.  
  308.           case WM_PAINT:
  309.                hdc = BeginPaint (hwnd, &ps) ;
  310.  
  311.                for (i = 0 ; i < NUM_STATES ; i++)
  312.                     {
  313.                     if (i < (NUM_STATES + 1) / 2)
  314.                          {
  315.                          x = cxChar ;
  316.                          y = i * cyChar ;
  317.                          }
  318.                     else
  319.                          {
  320.                          x = 44 * cxChar ;
  321.                          y = (i - (NUM_STATES + 1) / 2) * cyChar ;
  322.                          }
  323.  
  324.                     TextOut (hdc, x, y, szBuffer,
  325.                              wsprintf (szBuffer, "%-20s",
  326.                                        (LPSTR) pop[i].szState)) ;
  327.  
  328.                     x += 36 * cxChar ;
  329.  
  330.                     SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
  331.  
  332.                     TextOut (hdc, x, y, szBuffer,
  333.                              wsprintf (szBuffer, "%10ld", pop[i].lPop)) ;
  334.  
  335.                     SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
  336.                     }
  337.  
  338.                EndPaint (hwnd, &ps) ;
  339.                return 0 ;
  340.  
  341.           case WM_DDE_TERMINATE:
  342.  
  343.                     // Respond with another WM_DDE_TERMINATE message
  344.  
  345.                PostMessage (hwndServer, WM_DDE_TERMINATE, hwnd, 0L) ;
  346.                hwndServer = NULL ;
  347.                return 0 ;
  348.  
  349.           case WM_CLOSE:
  350.                if (hwndServer == NULL)
  351.                     break ;
  352.  
  353.                     // Post WM_DDE_UNADVISE message
  354.  
  355.                PostMessage (hwndServer, WM_DDE_UNADVISE, hwnd,
  356.                             MAKELONG (CF_TEXT, NULL)) ;
  357.  
  358.                dwTime = GetCurrentTime () ;
  359.  
  360.                while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  361.                     {
  362.                     if (PeekMessage (&msg, hwnd, WM_DDE_ACK,
  363.                                      WM_DDE_ACK, PM_REMOVE))
  364.                          break ;
  365.                     }
  366.  
  367.                     // Post WM_DDE_TERMINATE message
  368.  
  369.                PostMessage (hwndServer, WM_DDE_TERMINATE, hwnd, 0L) ;
  370.  
  371.                dwTime = GetCurrentTime () ;
  372.  
  373.                while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  374.                     {
  375.                     if (PeekMessage (&msg, hwnd, WM_DDE_TERMINATE,
  376.                                      WM_DDE_TERMINATE, PM_REMOVE))
  377.                          break ;
  378.                     }
  379.  
  380.                break ;             // for default processing
  381.  
  382.           case WM_DESTROY:
  383.                PostQuitMessage (0) ;
  384.                return 0 ;
  385.           }
  386.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  387.      }
  388.