home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / io / fwatch / fwatch.c next >
C/C++ Source or Header  |  1997-10-08  |  12KB  |  376 lines

  1. /**********************************************************************
  2.    File name: fwatch.c
  3.  
  4.       Main source file for sample demonstrating use of file change
  5.       notification APIs.
  6.  
  7.    Functions:
  8.  
  9.       CheckChangedFile()      - Gets and displays change information
  10.       HandleDirectoryChange() - Watch function
  11.       WatchDirectories()      - Starts the watch
  12.       main()                  - Program main
  13.  
  14.  
  15.    Written by Microsoft Product Support Services, Windows Developer Support.
  16.    Copyright 1996-1997 Microsoft Corporation. All rights reserved.
  17. **********************************************************************/
  18. #define UNICODE
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <conio.h>
  23. #include <windows.h>
  24.  
  25. #define MAX_DIRS    10
  26. #define MAX_FILES   255
  27. #define MAX_BUFFER  4096
  28.  
  29. // this is the all purpose structure that contains  
  30. // the interesting directory information and provides
  31. // the input buffer that is filled with file change data
  32. typedef struct _DIRECTORY_INFO {
  33. HANDLE      hDir;
  34. TCHAR       lpszDirName[MAX_PATH];
  35. CHAR        lpBuffer[MAX_BUFFER];
  36. DWORD       dwBufLength;
  37. OVERLAPPED  Overlapped;
  38. }DIRECTORY_INFO, *PDIRECTORY_INFO, *LPDIRECTORY_INFO;
  39.  
  40. DIRECTORY_INFO  DirInfo[MAX_DIRS];        // Buffer for all of the directories
  41. TCHAR           FileList[MAX_FILES*MAX_PATH];   // Buffer for all of the files
  42. DWORD           numDirs;
  43.  
  44.  
  45. /**********************************************************************
  46.    CheckChangedFile()
  47.  
  48.    Purpose:
  49.       This function prints out information when one of the files we
  50.       are watching is changed.
  51.  
  52.    Parameters:
  53.  
  54.       LPDIRECTORY_INFO lpdi - Information about the watched directory
  55.       PFILE_NOTIFY_INFORMATION lpfni - Information about modified file
  56.  
  57.  
  58.    Return Value:
  59.       None
  60.  
  61.    Comments:
  62.  
  63. ********************************************************************/
  64. void WINAPI CheckChangedFile( LPDIRECTORY_INFO lpdi,
  65.                               PFILE_NOTIFY_INFORMATION lpfni)
  66. {
  67.     TCHAR      szFullPathName[MAX_PATH];
  68.     TCHAR      *p;
  69.     HANDLE     hFile;
  70.     FILETIME   LocalFileTime;
  71.     SYSTEMTIME SystemTime;
  72.     BY_HANDLE_FILE_INFORMATION FileInfo;
  73.  
  74.     p = FileList;
  75.  
  76.     while(*p && lstrcmpi(p,lpfni->FileName))
  77.         p+=(lstrlen(p)+1);
  78.  
  79.     if(*p)
  80.     {
  81.         lstrcpy( szFullPathName, lpdi->lpszDirName );
  82.         lstrcat( szFullPathName, L"\\" );
  83.         lstrcat( szFullPathName, lpfni->FileName );
  84.  
  85.         // we assume that the file was changed, since 
  86.         // that is the only thing we look for in this sample
  87.         wprintf( L"%s changed,", szFullPathName );
  88.  
  89.         hFile=CreateFile( szFullPathName,
  90.                           GENERIC_READ,
  91.                           FILE_SHARE_READ,
  92.                           NULL,
  93.                           OPEN_EXISTING,
  94.                           FILE_FLAG_SEQUENTIAL_SCAN,
  95.                           0);
  96.  
  97.         GetFileInformationByHandle( hFile, &FileInfo );
  98.  
  99.         FileTimeToLocalFileTime( &(FileInfo.ftLastWriteTime), &LocalFileTime );
  100.  
  101.         FileTimeToSystemTime( &LocalFileTime, &SystemTime );
  102.  
  103.         wprintf( L" Size = %d bytes,", FileInfo.nFileSizeLow );
  104.         wprintf( L" Last Access = %02d/%02d/%02d %02d:%02d:%02d",
  105.                  SystemTime.wMonth,
  106.                  SystemTime.wDay,
  107.                  SystemTime.wYear,
  108.                  SystemTime.wHour,
  109.                  SystemTime.wMinute,
  110.                  SystemTime.wSecond );
  111.  
  112.         CloseHandle( hFile );
  113.  
  114.         wprintf( L"\n" );
  115.     }
  116. }
  117.  
  118.  
  119. /**********************************************************************
  120.    HandleDirectoryChanges()
  121.  
  122.    Purpose:
  123.       This function receives notification of directory changes and
  124.       calls CheckChangedFile() to display the actual changes. After
  125.       notification and processing, this function calls
  126.       ReadDirectoryChangesW to reestablish the watch.
  127.  
  128.    Parameters:
  129.  
  130.       HANDLE hCompPort - Handle for completion port
  131.  
  132.  
  133.    Return Value:
  134.       None
  135.  
  136.    Comments:
  137.  
  138. ********************************************************************/
  139. void WINAPI HandleDirectoryChange( DWORD dwCompletionPort )
  140. {
  141.     DWORD numBytes;
  142.     DWORD cbOffset;
  143.     LPDIRECTORY_INFO di;
  144.     LPOVERLAPPED lpOverlapped;
  145.     PFILE_NOTIFY_INFORMATION fni;
  146.  
  147.     do
  148.     {
  149.         // Retrieve the directory info for this directory
  150.         // through the completion key
  151.         GetQueuedCompletionStatus( (HANDLE) dwCompletionPort,
  152.                                    &numBytes,
  153.                                    (LPDWORD) &di,
  154.                                    &lpOverlapped,
  155.                                    INFINITE);
  156.  
  157.         if ( di )
  158.         {
  159.  
  160.             fni = (PFILE_NOTIFY_INFORMATION)di->lpBuffer;
  161.  
  162.             do
  163.             {
  164.                 cbOffset = fni->NextEntryOffset;
  165.  
  166.                 if( fni->Action == FILE_ACTION_MODIFIED )
  167.                     CheckChangedFile( di, fni );
  168.  
  169.                 fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE) fni + cbOffset);
  170.  
  171.             } while( cbOffset );
  172.  
  173.             // Reissue the watch command
  174.             ReadDirectoryChangesW( di->hDir,di->lpBuffer,
  175.                                    MAX_BUFFER,
  176.                                    TRUE,
  177.                                    FILE_NOTIFY_CHANGE_LAST_WRITE,
  178.                                    &di->dwBufLength,
  179.                                    &di->Overlapped,
  180.                                    NULL);
  181.         }
  182.  
  183.     } while( di );
  184.  
  185.  
  186. }
  187.  
  188.  
  189. /**********************************************************************
  190.    WatchDirectories()
  191.  
  192.    Purpose:
  193.       This function implements the ReadDirectoryChangesW API for
  194.       indicated directories. For each directory watched, a thread
  195.       is created which waits for changes to the directory. This
  196.       function waits for the user to input 'q', then cleans up and
  197.       quits.
  198.  
  199.    Parameters:
  200.  
  201.       HANDLE hCompPort - Handle for completion port
  202.  
  203.  
  204.    Return Value:
  205.       None
  206.  
  207. ********************************************************************/
  208. void WINAPI WatchDirectories( HANDLE hCompPort )
  209. {
  210.     DWORD   i;
  211.     DWORD   tid;
  212.     HANDLE  hThread;
  213.  
  214.  
  215.     // Start watching each of the directories of interest
  216.  
  217.     for (i=0;i<numDirs;i++)
  218.     {
  219.         ReadDirectoryChangesW( DirInfo[i].hDir,
  220.                                DirInfo[i].lpBuffer,
  221.                                MAX_BUFFER,
  222.                                TRUE,
  223.                                FILE_NOTIFY_CHANGE_LAST_WRITE,
  224.                                &DirInfo[i].dwBufLength,&DirInfo[i].Overlapped,
  225.                                NULL);
  226.     }
  227.  
  228.     // Create a thread to sit on the directory changes
  229.  
  230.     hThread = CreateThread( NULL,
  231.                             0,
  232.                             (LPTHREAD_START_ROUTINE) HandleDirectoryChange,
  233.                             hCompPort,
  234.                             0,
  235.                             &tid);
  236.  
  237.     // Just loop and wait for the user to quit
  238.  
  239.     while (getch() != 'q');
  240.  
  241.     // The user has quit - clean up
  242.  
  243.     PostQueuedCompletionStatus( hCompPort, 0, 0, NULL );
  244.  
  245.     // Wait for the Directory thread to finish before exiting
  246.  
  247.     WaitForSingleObject( hThread, INFINITE );
  248.  
  249.     CloseHandle( hThread );
  250. }
  251.  
  252.  
  253. /**********************************************************************
  254.    main()
  255.  
  256.    Purpose:
  257.       Main entry-point for fwatch sample. This function reads an .ini
  258.       file (fwatch.ini) to determine which directories and files to
  259.           watch. For each directory watched some information is gathered
  260.       and stored.
  261.  
  262.    Return Value:  (see errors.h for description)
  263.       None
  264.  
  265.    Comments:
  266.  
  267. ********************************************************************/
  268. void main(int argc, char *argv[])
  269. {
  270.  
  271.     TCHAR   *p,*q;                          // Temporary String Pointer
  272.     HANDLE  hCompPort=NULL;                 // Handle To a Completion Port
  273.     DWORD   i;                              // You always need an I.
  274.     TCHAR   DirList[MAX_DIRS*MAX_PATH];     // Buffer for all of the directories
  275.     TCHAR   IniFile[MAX_PATH];
  276.     TCHAR   FilePath[MAX_PATH];
  277.     HANDLE  hFile;
  278.  
  279.     GetCurrentDirectory( MAX_PATH, IniFile );
  280.  
  281.     lstrcat( IniFile, L"\\fwatch.ini" );
  282.  
  283.     GetPrivateProfileString( L"Directories",
  284.                              NULL,
  285.                              NULL,
  286.                              DirList,
  287.                              MAX_DIRS*MAX_PATH,
  288.                              IniFile );
  289.  
  290.     GetPrivateProfileString( L"Files",
  291.                              NULL,
  292.                              NULL,
  293.                              FileList,
  294.                              MAX_FILES*MAX_PATH,
  295.                              IniFile );
  296.  
  297.     wprintf( L"Watching these directories:\n" );
  298.  
  299.     // First, walk through the raw list and count items, creating
  300.     // an array of handles for each directory
  301.     for (p=DirList;*p!='\0';numDirs++,p+=(lstrlen(p)+1))
  302.     {
  303.  
  304.  
  305.         if( CreateDirectory( p, NULL ) )
  306.             wprintf( L"Directory %s created\n", p );
  307.         else
  308.             wprintf( L"Directory %s exists\n", p );
  309.  
  310.         // Get a handle to the directory
  311.         DirInfo[numDirs].hDir = CreateFile( p,
  312.                                             FILE_LIST_DIRECTORY,
  313.                                             FILE_SHARE_READ |
  314.                                             FILE_SHARE_WRITE |
  315.                                             FILE_SHARE_DELETE,
  316.                                             NULL,
  317.                                             OPEN_EXISTING,
  318.                                             FILE_FLAG_BACKUP_SEMANTICS |
  319.                                             FILE_FLAG_OVERLAPPED,
  320.                                             NULL);
  321.  
  322.         if( DirInfo[numDirs].hDir == INVALID_HANDLE_VALUE )
  323.         {
  324.             wprintf( L"Unable to open directory %s. GLE=%d. Terminating...\n",
  325.                      p, GetLastError() );
  326.             exit( 0 );
  327.         }
  328.  
  329.         for (q=FileList;*q!='\0';q+=(lstrlen(q)+1))
  330.         {
  331.             lstrcpy( FilePath, p );
  332.             lstrcat( FilePath, L"\\" );
  333.             lstrcat( FilePath, q );
  334.  
  335.             if( hFile = CreateFile( FilePath,
  336.                                     GENERIC_WRITE,
  337.                                     FILE_SHARE_READ |
  338.                                     FILE_SHARE_WRITE |
  339.                                     FILE_SHARE_DELETE,
  340.                                     NULL,
  341.                                     CREATE_ALWAYS,
  342.                                     FILE_ATTRIBUTE_NORMAL,
  343.                                     NULL) )
  344.             {
  345.                 wprintf( L"  File %s created\n", FilePath );
  346.                 CloseHandle( hFile );
  347.             }
  348.             else
  349.                 wprintf( L"  File %s could not be created\n", FilePath );
  350.  
  351.         }
  352.  
  353.         lstrcpy( DirInfo[numDirs].lpszDirName, p );
  354.  
  355.         // Set up a key(directory info) for each directory
  356.         hCompPort=CreateIoCompletionPort( DirInfo[numDirs].hDir,
  357.                                           hCompPort,
  358.                                           (DWORD) &DirInfo[numDirs],
  359.                                           0);
  360.  
  361.     }
  362.  
  363.     wprintf( L"\n\nPress <q> to exit\n" );
  364.  
  365.     // Start watching
  366.     WatchDirectories( hCompPort );
  367.  
  368.     for(i=0;i<numDirs;i++)
  369.         CloseHandle( DirInfo[i].hDir );
  370.  
  371.     CloseHandle( hCompPort );
  372.  
  373. }
  374.  
  375.  
  376.