home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows (5th Edition) / Programming Windows, 5th ed. - Companion CD (097-0002183)(1999).iso / Chap23 / UpdDemo / UpdDemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-09  |  15.4 KB  |  500 lines

  1. /*------------------------------------------------
  2.    UPDDEMO.C -- Demonstrates Anonymous FTP Access
  3.                 (c) Charles Petzold, 1998
  4.   ------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <wininet.h>
  8. #include <process.h>
  9. #include "resource.h"
  10.  
  11.      // User-defined messages used in WndProc
  12.  
  13. #define WM_USER_CHECKFILES (WM_USER + 1)
  14. #define WM_USER_GETFILES   (WM_USER + 2)
  15.  
  16.      // Information for FTP download
  17.  
  18. #define FTPSERVER TEXT ("ftp.cpetzold.com")
  19. #define DIRECTORY TEXT ("cpetzold.com/ProgWin/UpdDemo")
  20. #define TEMPLATE  TEXT ("UD??????.TXT")
  21.  
  22.      // Structures used for storing filenames and contents
  23.  
  24. typedef struct
  25. {
  26.      TCHAR * szFilename ;
  27.      char  * szContents ;
  28. }
  29. FILEINFO ;
  30.  
  31. typedef struct
  32. {
  33.      int      iNum ;
  34.      FILEINFO info[1] ;
  35. }
  36. FILELIST ;
  37.  
  38.      // Structure used for second thread
  39.  
  40. typedef struct
  41. {
  42.      BOOL bContinue ;
  43.      HWND hwnd ;
  44. }
  45. PARAMS ;
  46.  
  47.      // Declarations of all functions in program
  48.  
  49. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
  50. BOOL    CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ;
  51. VOID             FtpThread (PVOID) ;
  52. VOID             ButtonSwitch (HWND, HWND, TCHAR *) ;
  53. FILELIST *       GetFileList (VOID) ;
  54. int              Compare (const FILEINFO *, const FILEINFO *) ;
  55.  
  56.      // A couple globals
  57.  
  58. HINSTANCE hInst ;
  59. TCHAR     szAppName[] = TEXT ("UpdDemo") ;
  60.  
  61. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  62.                     PSTR szCmdLine, int iCmdShow)
  63. {
  64.      HWND         hwnd ;
  65.      MSG          msg ;
  66.      WNDCLASS     wndclass ;
  67.  
  68.      hInst = hInstance ;
  69.  
  70.      wndclass.style         = 0 ;
  71.      wndclass.lpfnWndProc   = WndProc ;
  72.      wndclass.cbClsExtra    = 0 ;
  73.      wndclass.cbWndExtra    = 0 ;
  74.      wndclass.hInstance     = hInstance ;
  75.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  76.      wndclass.hCursor       = NULL ;
  77.      wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  78.      wndclass.lpszMenuName  = NULL ;
  79.      wndclass.lpszClassName = szAppName ;
  80.  
  81.      if (!RegisterClass (&wndclass))
  82.      {
  83.           MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
  84.                       szAppName, MB_ICONERROR) ;
  85.           return 0 ;
  86.      }
  87.      
  88.      hwnd = CreateWindow (szAppName, TEXT ("Update Demo with Anonymous FTP"),
  89.                           WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  90.                           CW_USEDEFAULT, CW_USEDEFAULT,
  91.                           CW_USEDEFAULT, CW_USEDEFAULT,
  92.                           NULL, NULL, hInstance, NULL) ;
  93.  
  94.      ShowWindow (hwnd, iCmdShow) ;
  95.      UpdateWindow (hwnd) ;
  96.  
  97.           // After window is displayed, check if the latest file exists
  98.  
  99.      SendMessage (hwnd, WM_USER_CHECKFILES, 0, 0) ;
  100.  
  101.      while (GetMessage (&msg, NULL, 0, 0))
  102.      {
  103.           TranslateMessage (&msg) ;
  104.           DispatchMessage (&msg) ;
  105.      }
  106.      return msg.wParam ;
  107. }
  108.  
  109. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  110. {
  111.      static FILELIST * plist ;
  112.      static int        cxClient, cyClient, cxChar, cyChar ;
  113.      HDC               hdc ;
  114.      int               i ;
  115.      PAINTSTRUCT       ps ;
  116.      SCROLLINFO        si ;
  117.      SYSTEMTIME        st ;
  118.      TCHAR             szFilename [MAX_PATH] ;
  119.  
  120.      switch (message)
  121.      {
  122.      case WM_CREATE:
  123.           cxChar = LOWORD (GetDialogBaseUnits ()) ;
  124.           cyChar = HIWORD (GetDialogBaseUnits ()) ;
  125.           return 0 ;
  126.  
  127.      case WM_SIZE:
  128.           cxClient = LOWORD (lParam) ;
  129.           cyClient = HIWORD (lParam) ;
  130.  
  131.           si.cbSize = sizeof (SCROLLINFO) ;
  132.           si.fMask  = SIF_RANGE | SIF_PAGE ;
  133.           si.nMin   = 0 ;
  134.           si.nMax   = plist ? plist->iNum - 1 : 0 ;
  135.           si.nPage  = cyClient / cyChar ;
  136.  
  137.           SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;
  138.           return 0 ;
  139.  
  140.      case WM_VSCROLL:
  141.           si.cbSize = sizeof (SCROLLINFO) ;
  142.           si.fMask  = SIF_POS | SIF_RANGE | SIF_PAGE ;
  143.           GetScrollInfo (hwnd, SB_VERT, &si) ;
  144.  
  145.           switch (LOWORD (wParam))
  146.           {
  147.           case SB_LINEDOWN:       si.nPos += 1 ;              break ;
  148.           case SB_LINEUP:         si.nPos -= 1 ;              break ;
  149.           case SB_PAGEDOWN:       si.nPos += si.nPage ;       break ;
  150.           case SB_PAGEUP:         si.nPos -= si.nPage ;       break ;
  151.           case SB_THUMBPOSITION:  si.nPos = HIWORD (wParam) ; break ;
  152.           default:                return 0 ;
  153.           }
  154.           si.fMask = SIF_POS ;
  155.           SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;
  156.           InvalidateRect (hwnd, NULL, TRUE) ;
  157.           return 0 ;
  158.  
  159.      case WM_USER_CHECKFILES:
  160.                // Get the system date & form filename from year and month
  161.  
  162.           GetSystemTime (&st) ;
  163.           wsprintf (szFilename, TEXT ("UD%04i%02i.TXT"), st.wYear, st.wMonth) ;
  164.  
  165.                // Check if the file exists; if so, read all the files
  166.  
  167.           if (GetFileAttributes (szFilename) != (DWORD) -1)
  168.           {
  169.                SendMessage (hwnd, WM_USER_GETFILES, 0, 0) ;
  170.                return 0 ;
  171.           }
  172.                // Otherwise, get files from Internet.
  173.                // But first check so we don't try to copy files to a CD-ROM!
  174.  
  175.           if (GetDriveType (NULL) == DRIVE_CDROM)
  176.           {
  177.                MessageBox (hwnd, TEXT ("Cannot run this program from CD-ROM!"),
  178.                                  szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  179.                return 0 ;
  180.           }
  181.                // Ask user if an Internet connection is desired
  182.  
  183.           if (IDYES == MessageBox (hwnd, 
  184.                                   TEXT ("Update information from Internet?"),
  185.                                   szAppName, MB_YESNO | MB_ICONQUESTION))
  186.  
  187.                // Invoke dialog box 
  188.  
  189.           DialogBox (hInst, szAppName, hwnd, DlgProc) ;
  190.  
  191.                // Update display
  192.  
  193.           SendMessage (hwnd, WM_USER_GETFILES, 0, 0) ;
  194.           return 0 ;
  195.  
  196.      case WM_USER_GETFILES:
  197.           SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  198.           ShowCursor (TRUE) ;
  199.  
  200.                // Read in all the disk files
  201.  
  202.           plist = GetFileList () ;
  203.  
  204.           ShowCursor (FALSE) ;
  205.           SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  206.  
  207.                // Simulate a WM_SIZE message to alter scroll bar & repaint
  208.  
  209.           SendMessage (hwnd, WM_SIZE, 0, MAKELONG (cxClient, cyClient)) ;
  210.           InvalidateRect (hwnd, NULL, TRUE) ;
  211.           return 0 ;
  212.  
  213.      case WM_PAINT:
  214.           hdc = BeginPaint (hwnd, &ps) ;
  215.           SetTextAlign (hdc, TA_UPDATECP) ;
  216.  
  217.           si.cbSize = sizeof (SCROLLINFO) ;
  218.           si.fMask  = SIF_POS ;
  219.           GetScrollInfo (hwnd, SB_VERT, &si) ;
  220.  
  221.           if (plist)
  222.           {
  223.                for (i = 0 ; i < plist->iNum ; i++)
  224.                {
  225.                     MoveToEx (hdc, cxChar, (i - si.nPos) * cyChar, NULL) ;
  226.                     TextOut  (hdc, 0, 0, plist->info[i].szFilename,                                          
  227.                                 lstrlen (plist->info[i].szFilename)) ;
  228.                     TextOut  (hdc, 0, 0, TEXT (": "), 2) ;
  229.                     TextOutA (hdc, 0, 0, plist->info[i].szContents, 
  230.                                  strlen (plist->info[i].szContents)) ;
  231.                }
  232.           }
  233.           EndPaint (hwnd, &ps) ;
  234.           return 0 ;
  235.  
  236.      case WM_DESTROY:
  237.           PostQuitMessage (0) ;
  238.           return 0 ;
  239.      }
  240.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  241. }
  242.  
  243. BOOL CALLBACK DlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  244. {
  245.      static PARAMS params ;
  246.  
  247.      switch (message)
  248.      {
  249.      case WM_INITDIALOG:
  250.           params.bContinue = TRUE ;
  251.           params.hwnd = hwnd ;
  252.  
  253.           _beginthread (FtpThread, 0, ¶ms) ;
  254.           return TRUE ;
  255.  
  256.      case WM_COMMAND:
  257.           switch (LOWORD (wParam))
  258.           {
  259.           case IDCANCEL:           // button for user to abort download
  260.                params.bContinue = FALSE ;
  261.                return TRUE ;
  262.  
  263.           case IDOK:               // button to make dialog box go away
  264.                EndDialog (hwnd, 0) ;
  265.                return TRUE ;
  266.           }
  267.      }
  268.      return FALSE ;
  269. }
  270.  
  271. /*----------------------------------------------------------------------
  272.    FtpThread: Reads files from FTP server and copies them to local disk
  273.   ----------------------------------------------------------------------*/
  274.  
  275. void FtpThread (PVOID parg)
  276. {
  277.      BOOL            bSuccess ;
  278.      HINTERNET       hIntSession, hFtpSession, hFind ;
  279.      HWND            hwndStatus, hwndButton ;
  280.      PARAMS        * pparams ;
  281.      TCHAR           szBuffer [64] ;
  282.      WIN32_FIND_DATA finddata ;
  283.  
  284.      pparams = parg ;
  285.      hwndStatus = GetDlgItem (pparams->hwnd, IDC_STATUS) ;
  286.      hwndButton = GetDlgItem (pparams->hwnd, IDCANCEL) ;
  287.  
  288.           // Open an internet session
  289.      
  290.      hIntSession = InternetOpen (szAppName, INTERNET_OPEN_TYPE_PRECONFIG,
  291.                                  NULL, NULL, INTERNET_FLAG_ASYNC) ;
  292.  
  293.      if (hIntSession == NULL)
  294.      {
  295.           wsprintf (szBuffer, TEXT ("InternetOpen error %i"), GetLastError ()) ;
  296.           ButtonSwitch (hwndStatus, hwndButton, szBuffer) ;
  297.           _endthread () ;
  298.      }
  299.  
  300.      SetWindowText (hwndStatus, TEXT ("Internet session opened...")) ;
  301.  
  302.           // Check if user has pressed Cancel
  303.  
  304.      if (!pparams->bContinue)
  305.      {
  306.           InternetCloseHandle (hIntSession) ;
  307.           ButtonSwitch (hwndStatus, hwndButton, NULL) ;
  308.           _endthread () ;
  309.      }
  310.  
  311.           // Open an FTP session.
  312.  
  313.      hFtpSession = InternetConnect (hIntSession, FTPSERVER,
  314.                                     INTERNET_DEFAULT_FTP_PORT,
  315.                                     NULL, NULL, INTERNET_SERVICE_FTP, 0, 0) ;
  316.      if (hFtpSession == NULL)
  317.      {
  318.           InternetCloseHandle (hIntSession) ;
  319.           wsprintf (szBuffer, TEXT ("InternetConnect error %i"), 
  320.                               GetLastError ()) ;
  321.           ButtonSwitch (hwndStatus, hwndButton, szBuffer) ;
  322.           _endthread () ;
  323.      }
  324.  
  325.      SetWindowText (hwndStatus, TEXT ("FTP Session opened...")) ;
  326.      
  327.           // Check if user has pressed Cancel
  328.  
  329.      if (!pparams->bContinue)
  330.      {
  331.           InternetCloseHandle (hFtpSession) ;
  332.           InternetCloseHandle (hIntSession) ;
  333.           ButtonSwitch (hwndStatus, hwndButton, NULL) ;
  334.           _endthread () ;
  335.      }
  336.  
  337.           // Set the directory
  338.      
  339.      bSuccess = FtpSetCurrentDirectory (hFtpSession, DIRECTORY) ;
  340.  
  341.      if (!bSuccess)
  342.      {
  343.           InternetCloseHandle (hFtpSession) ;
  344.           InternetCloseHandle (hIntSession) ;
  345.           wsprintf (szBuffer, TEXT ("Cannot set directory to %s"),
  346.                               DIRECTORY) ;
  347.           ButtonSwitch (hwndStatus, hwndButton, szBuffer) ;
  348.           _endthread () ;
  349.      }
  350.  
  351.      SetWindowText (hwndStatus, TEXT ("Directory found...")) ;
  352.  
  353.           // Check if user has pressed Cancel
  354.  
  355.      if (!pparams->bContinue)
  356.      {
  357.           InternetCloseHandle (hFtpSession) ;
  358.           InternetCloseHandle (hIntSession) ;
  359.           ButtonSwitch (hwndStatus, hwndButton, NULL) ;
  360.           _endthread () ;
  361.      }
  362.  
  363.           // Get the first file fitting the template
  364.  
  365.      hFind = FtpFindFirstFile (hFtpSession, TEMPLATE, 
  366.                                &finddata, 0, 0) ;
  367.  
  368.      if (hFind == NULL)
  369.      {
  370.           InternetCloseHandle (hFtpSession) ;
  371.           InternetCloseHandle (hIntSession) ;
  372.           ButtonSwitch (hwndStatus, hwndButton, TEXT ("Cannot find files")) ;
  373.           _endthread () ;
  374.      }
  375.  
  376.      do 
  377.      {
  378.                // Check if user has pressed Cancel
  379.  
  380.           if (!pparams->bContinue)
  381.           {
  382.                InternetCloseHandle (hFind) ;
  383.                InternetCloseHandle (hFtpSession) ;
  384.                InternetCloseHandle (hIntSession) ;
  385.                ButtonSwitch (hwndStatus, hwndButton, NULL) ;
  386.                _endthread () ;
  387.           }
  388.                // Copy file from internet to local hard disk, but fail
  389.                // if the file already exists locally
  390.  
  391.           wsprintf (szBuffer, TEXT ("Reading file %s..."), finddata.cFileName) ;
  392.           SetWindowText (hwndStatus, szBuffer) ;
  393.  
  394.           FtpGetFile (hFtpSession, 
  395.                       finddata.cFileName, finddata.cFileName, TRUE, 
  396.                       FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY, 0) ;
  397.      }
  398.      while (InternetFindNextFile (hFind, &finddata)) ;
  399.  
  400.      InternetCloseHandle (hFind) ;
  401.      InternetCloseHandle (hFtpSession) ;
  402.      InternetCloseHandle (hIntSession) ;
  403.  
  404.      ButtonSwitch (hwndStatus, hwndButton, TEXT ("Internet Download Complete"));
  405. }
  406.  
  407. /*-----------------------------------------------------------------------
  408.    ButtonSwitch:  Displays final status message and changes Cancel to OK
  409.   -----------------------------------------------------------------------*/
  410.  
  411. VOID ButtonSwitch (HWND hwndStatus, HWND hwndButton, TCHAR * szText) 
  412. {
  413.      if (szText)
  414.           SetWindowText (hwndStatus, szText) ;
  415.      else
  416.           SetWindowText (hwndStatus, TEXT ("Internet Session Cancelled")) ;
  417.  
  418.      SetWindowText (hwndButton, TEXT ("OK")) ;
  419.      SetWindowLong (hwndButton, GWL_ID, IDOK) ;
  420. }
  421.  
  422. /*-----------------------------------------------------------------------
  423.    GetFileList: Reads files from disk and saves their names and contents
  424.   -----------------------------------------------------------------------*/
  425.  
  426. FILELIST * GetFileList (void)
  427. {
  428.      DWORD           dwRead ;
  429.      FILELIST      * plist ;
  430.      HANDLE          hFile, hFind ;
  431.      int             iSize, iNum  ;
  432.      WIN32_FIND_DATA finddata ;
  433.  
  434.      hFind = FindFirstFile (TEMPLATE, &finddata) ;
  435.  
  436.      if (hFind == INVALID_HANDLE_VALUE)
  437.           return NULL ;
  438.      
  439.      plist = NULL ;
  440.      iNum  = 0 ;
  441.  
  442.      do
  443.      {
  444.                // Open the file and get the size
  445.  
  446.           hFile = CreateFile (finddata.cFileName, GENERIC_READ, FILE_SHARE_READ,
  447.                               NULL, OPEN_EXISTING, 0, NULL) ;
  448.  
  449.           if (hFile == INVALID_HANDLE_VALUE)
  450.                continue ;
  451.      
  452.           iSize = GetFileSize (hFile, NULL) ;
  453.  
  454.           if (iSize == (DWORD) -1)
  455.           {
  456.                CloseHandle (hFile) ;
  457.                continue ;
  458.           }
  459.                // Realloc the FILELIST structure for a new entry 
  460.  
  461.           plist = realloc (plist, sizeof (FILELIST) + iNum * sizeof (FILEINFO));
  462.  
  463.                // Allocate space and save the filename 
  464.  
  465.           plist->info[iNum].szFilename = malloc (lstrlen (finddata.cFileName) +
  466.                                                  sizeof (TCHAR)) ;
  467.           lstrcpy (plist->info[iNum].szFilename, finddata.cFileName) ;
  468.  
  469.                // Allocate space and save the contents
  470.  
  471.           plist->info[iNum].szContents = malloc (iSize + 1) ;
  472.           ReadFile (hFile, plist->info[iNum].szContents, iSize, &dwRead, NULL);
  473.           plist->info[iNum].szContents[iSize] = 0 ;
  474.  
  475.           CloseHandle (hFile) ;
  476.           iNum ++ ;
  477.      }
  478.      while (FindNextFile (hFind, &finddata)) ;
  479.  
  480.      FindClose (hFind) ;
  481.  
  482.           // Sort the files by filename
  483.  
  484.      qsort (plist->info, iNum, sizeof (FILEINFO), Compare) ;
  485.  
  486.      plist->iNum = iNum ;
  487.  
  488.      return plist ;
  489. }
  490.  
  491. /*----------------------------
  492.    Compare function for qsort
  493.   ----------------------------*/
  494.  
  495. int Compare (const FILEINFO * pinfo1, const FILEINFO * pinfo2)
  496. {
  497.      return lstrcmp (pinfo2->szFilename, pinfo1->szFilename) ;
  498. }
  499.  
  500.