filechng.c

来自「一本已经绝版的好书」· C语言 代码 · 共 512 行

C
512
字号
/************************************************************
Module name: FileChng.C
Written by: Jim Harkins and Jeffrey Richter
Notices: Copyright (c) 1995-1997 Jeffrey Richter
************************************************************/


#include "..\CmnHdr.H"                  /* See Appendix C. */
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Resource.H"


/////////////////////////////////////////////////////////////
// The following functions are taken directly from DirWalk.C.


static BOOL IsChildDir (WIN32_FIND_DATA *lpFindData) {

   return(
      ((lpFindData->dwFileAttributes & 
         FILE_ATTRIBUTE_DIRECTORY) != 0) &&
      (lstrcmp(lpFindData->cFileName, __TEXT("."))  != 0) &&
      (lstrcmp(lpFindData->cFileName, __TEXT("..")) != 0));
}


/////////////////////////////////////////////////////////////


static BOOL FindNextChildDir (HANDLE hFindFile,
   WIN32_FIND_DATA *lpFindData) {

   BOOL fFound = FALSE;

   do {
      fFound = FindNextFile(hFindFile, lpFindData);
   } while (fFound && !IsChildDir(lpFindData));

   return(fFound);
}


/////////////////////////////////////////////////////////////


static HANDLE FindFirstChildDir (LPTSTR szPath,
   WIN32_FIND_DATA *lpFindData) {

   BOOL fFound;
   HANDLE hFindFile = FindFirstFile(szPath, lpFindData);

   if (hFindFile != INVALID_HANDLE_VALUE) {
      fFound = IsChildDir(lpFindData);

      if (!fFound)
         fFound = FindNextChildDir(hFindFile, lpFindData);

      if (!fFound) {
         FindClose(hFindFile);
         hFindFile = INVALID_HANDLE_VALUE;
      }
   }
   return(hFindFile);
}


/////////////////////////////////////////////////////////////


// To minimize stack use, one instance of the DIRWALKDATA
// structure is created as a local variable in DirWalk,
// and a pointer to it is passed to DirWalkRecurse.

// Data used by DirWalkRecurse
typedef struct {
   HWND   hwndTreeLB;   // Handle to the output list box
   int    nDepth;       // Nesting depth
   BOOL   fRecurse;     // Set to TRUE to list subdirectories.
   TCHAR  szBuf[1000];  // Output formatting buffer
   int    nIndent;      // Indentation character count
   BOOL   fOk;          // Loop control flag
   BOOL   fIsDir;       // Loop control flag
   WIN32_FIND_DATA FindData; // File information
} DIRWALKDATA, *LPDIRWALKDATA;


/////////////////////////////////////////////////////////////


// Walk the directory structure and fill a list box with
// filenames. If pDW->fRecurse is set, list any child
// directories by recursively calling DirWalkRecurse.
void DirWalkRecurse (LPDIRWALKDATA pDW) {
   HANDLE hFind;

   pDW->nDepth++;

   pDW->nIndent = 3 * pDW->nDepth;
   _stprintf(pDW->szBuf, __TEXT("%*s"), pDW->nIndent,
      __TEXT(""));

   GetCurrentDirectory(chDIMOF(pDW->szBuf) - pDW->nIndent,
      &pDW->szBuf[pDW->nIndent]);
   ListBox_AddString(pDW->hwndTreeLB, pDW->szBuf);

   hFind = FindFirstFile(__TEXT("*.*"), &pDW->FindData);
   pDW->fOk = (hFind != INVALID_HANDLE_VALUE);

   while (pDW->fOk) {
      pDW->fIsDir = pDW->FindData.dwFileAttributes &
         FILE_ATTRIBUTE_DIRECTORY;
      if (!pDW->fIsDir ||
         (!pDW->fRecurse && IsChildDir(&pDW->FindData))) {

         _stprintf(pDW->szBuf,
            pDW->fIsDir ? __TEXT("%*s[%s]") : __TEXT("%*s%s"),
            pDW->nIndent, __TEXT(""),
            pDW->FindData.cFileName);

         ListBox_AddString(pDW->hwndTreeLB, pDW->szBuf);
      }
      pDW->fOk = FindNextFile(hFind, &pDW->FindData);
   }
   if (hFind != INVALID_HANDLE_VALUE)
      FindClose(hFind);

   if (pDW->fRecurse) {
      // Get the first child directory.
      hFind = FindFirstChildDir(
         __TEXT("*.*"), &pDW->FindData);
      pDW->fOk = (hFind != INVALID_HANDLE_VALUE);
      while (pDW->fOk) {
         // Change into the child directory.
         if (SetCurrentDirectory(pDW->FindData.cFileName)) {

            // Perform the recursive walk into the child
            // directory.  Remember that some members of pDW 
            // will be overwritten by this call.
            DirWalkRecurse(pDW);

            // Change back to the child's parent directory.
            SetCurrentDirectory(__TEXT(".."));
         }

         pDW->fOk = FindNextChildDir(hFind, &pDW->FindData);
      }

      if (hFind != INVALID_HANDLE_VALUE)
         FindClose(hFind);
   }
   pDW->nDepth--;
}


/////////////////////////////////////////////////////////////


// Walk the directory structure and fill a list box with
// filenames. This function sets up a call to 
// DirWalkRecurse, which does the real work.

void DirWalk (
   HWND hwndTreeLB,      // List box to fill
   LPCTSTR pszRootPath,  // Starting point of the tree walk
   BOOL fRecurse) {      // Expand subdirectories.

   TCHAR szCurrDir[_MAX_DIR];
   DIRWALKDATA DW;

   // Clear out the list box.
   ListBox_ResetContent(hwndTreeLB);

   // Save the current directory so that it can 
   // be restored later.
   GetCurrentDirectory(chDIMOF(szCurrDir), szCurrDir);

   // Set the current directory to where we want
   // to start walking.
   SetCurrentDirectory(pszRootPath);

   // nDepth is used to control indenting. The value -1 will
   // cause the first level to display flush left.
   DW.nDepth = -1;

   DW.hwndTreeLB = hwndTreeLB;
   DW.fRecurse = fRecurse;

   // Call the recursive function to walk the subdirectories.
   DirWalkRecurse(&DW);

   // Restore the current directory to what it was 
   // before the function was called.
   SetCurrentDirectory(szCurrDir);
}


/////////////////////////////////////////////////////////////


HANDLE g_hChange = INVALID_HANDLE_VALUE;
int    g_nCount = 0;


/////////////////////////////////////////////////////////////


void Dlg_ErrorBox (LPCTSTR pszSource) {
   TCHAR szBuf[100];   // Output formatting buffer.

   _stprintf(szBuf, __TEXT("%s reported error %lu"),
      pszSource, GetLastError());

   chMB(szBuf);
}


/////////////////////////////////////////////////////////////


DWORD Dlg_GetFilter (HWND hwnd) {
   DWORD fdwFilter = 0;

   if (IsDlgButtonChecked(hwnd, IDC_FILENAME))
      fdwFilter |= FILE_NOTIFY_CHANGE_FILE_NAME;
      
   if (IsDlgButtonChecked(hwnd, IDC_DIRNAME))
      fdwFilter |= FILE_NOTIFY_CHANGE_DIR_NAME;
      
   if (IsDlgButtonChecked(hwnd, IDC_ATTRIBS))
      fdwFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
      
   if (IsDlgButtonChecked(hwnd, IDC_SIZEFLTR))
      fdwFilter |= FILE_NOTIFY_CHANGE_SIZE;

   if (IsDlgButtonChecked(hwnd, IDC_LASTWRITE))
      fdwFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
      
   if (IsDlgButtonChecked(hwnd, IDC_LASTACCESS))
      fdwFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
      
   if (IsDlgButtonChecked(hwnd, IDC_CREATION))
      fdwFilter |= FILE_NOTIFY_CHANGE_CREATION;
      
   if (IsDlgButtonChecked(hwnd, IDC_SECURITY))
      fdwFilter |= FILE_NOTIFY_CHANGE_SECURITY;
      
   return(fdwFilter);
}


/////////////////////////////////////////////////////////////


// Validate the dialog box controls and configure a
// valid call to FindFirstChangeNotification:
// At least one filter flag must be set, and
// the path must be valid.
BOOL Dlg_Validate (HWND hwnd) {
   BOOL  fValid = FALSE;
   TCHAR szPath[_MAX_DIR];

   // Test to see whether at least one flag is set.
   if (0 != Dlg_GetFilter(hwnd)) {
   
      // Verify that the path exists. 
      GetDlgItemText(hwnd, IDC_PATH, szPath, 
         chDIMOF(szPath));
      fValid = SetCurrentDirectory(szPath);
   }
   return(fValid);
}


/////////////////////////////////////////////////////////////


// Stop close change notification.
void Dlg_CloseChange (HWND hwnd) {
   BOOL fDisableFocus =
      (GetFocus() == GetDlgItem(hwnd, IDC_STOP));

   EnableWindow(GetDlgItem(hwnd, IDC_STOP), FALSE);

   if (Dlg_Validate(hwnd)) {
      EnableWindow(GetDlgItem(hwnd, IDC_START), TRUE);
      if (fDisableFocus) {
         SetFocus(GetDlgItem(hwnd, IDC_START));
      }
   } else {
      fDisableFocus = fDisableFocus ||
         (GetFocus() == GetDlgItem(hwnd, IDC_START));

      EnableWindow(GetDlgItem(hwnd, IDC_START), FALSE);
      if (fDisableFocus) {
         SetFocus(GetDlgItem(hwnd, IDC_INCSUBDIRS));
      }
   }

   if (INVALID_HANDLE_VALUE != g_hChange) {
      if (!FindCloseChangeNotification(g_hChange)) {
         Dlg_ErrorBox(__TEXT("FindCloseChangeNotification"));
      }
      g_hChange = INVALID_HANDLE_VALUE;
   }
}


/////////////////////////////////////////////////////////////


// Start close change notification.
void Dlg_OpenChange (HWND hwnd) {
   TCHAR szPath[_MAX_DIR];
   BOOL fDisableFocus = 
     (GetFocus() == GetDlgItem(hwnd, IDC_START));

   Dlg_CloseChange(hwnd);

   g_nCount = 0;
   SetDlgItemInt(hwnd, IDC_NCOUNT, g_nCount, FALSE);

   GetDlgItemText(hwnd, IDC_PATH, szPath, chDIMOF(szPath));

   g_hChange = FindFirstChangeNotification(szPath,
      IsDlgButtonChecked(hwnd, IDC_INCSUBDIRS),
      Dlg_GetFilter(hwnd));

   if (INVALID_HANDLE_VALUE == g_hChange) {
      Dlg_ErrorBox(__TEXT("FindFirstChangeNotification"));
      g_hChange = INVALID_HANDLE_VALUE;
   } else {
      EnableWindow(GetDlgItem(hwnd, IDC_START), FALSE);
      EnableWindow(GetDlgItem(hwnd, IDC_STOP), TRUE);

      if (fDisableFocus) {
         SetFocus(GetDlgItem(hwnd, IDC_STOP));
      }
      DirWalk(GetDlgItem(hwnd, IDC_TREE), szPath,
         IsDlgButtonChecked(hwnd, IDC_INCSUBDIRS));
   }
}


/////////////////////////////////////////////////////////////


BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,
   LPARAM lParam) {
   TCHAR szPath[_MAX_DIR];

   // Associate an icon with the dialog box.
   chSETDLGICONS(hwnd, IDI_FILECHNG, IDI_FILECHNG);

   // Path defaults to the current path
   GetCurrentDirectory(chDIMOF(szPath), szPath);
   SetDlgItemText(hwnd, IDC_PATH, szPath);

   Dlg_CloseChange(hwnd);

   return(TRUE);
}


/////////////////////////////////////////////////////////////


void Dlg_OnCommand (HWND hwnd, int id, HWND hwndCtl,
   UINT codeNotify) {

   switch (id) {
      case IDC_PATH:
         // If change notification is started and
         // the user updates the path,
         // stop notifications.
         if (EN_CHANGE == codeNotify) {
            Dlg_CloseChange(hwnd);
         }
         break;

      case IDC_INCSUBDIRS:
      case IDC_FILENAME:
      case IDC_DIRNAME:
      case IDC_ATTRIBS:
      case IDC_SIZEFLTR:
      case IDC_LASTWRITE:
      case IDC_LASTACCESS:
      case IDC_CREATION:
      case IDC_SECURITY:
      case IDC_STOP:
         Dlg_CloseChange(hwnd);
         break;

      case IDC_START:
         Dlg_OpenChange(hwnd);
         break;

      case IDCANCEL:
         Dlg_CloseChange(hwnd);
         PostQuitMessage(0);
         break;
   }
}


/////////////////////////////////////////////////////////////


BOOL CALLBACK Dlg_Proc (HWND hwnd, UINT uMsg, WPARAM wParam,
   LPARAM lParam) {

   switch (uMsg) {
      chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
      chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
   }
   return(FALSE);
}


/////////////////////////////////////////////////////////////


int WINAPI _tWinMain (HINSTANCE hinstExe,
   HINSTANCE hinstPrev, LPTSTR pszCmdLine, int nCmdShow) {

   HWND  hwnd;
   MSG   msg;
   DWORD dwResult;
   BOOL  fQuit = FALSE, fWait4FileChanges;
   TCHAR szPath[_MAX_DIR];

   chWARNIFUNICODEUNDERWIN95();

   // Create a modeless dialog box instead of a modal
   // dialog box because we need to have more control over
   // the message loop processing.
   hwnd = CreateDialog(hinstExe, 
      MAKEINTRESOURCE(IDD_FILECHNG), NULL, Dlg_Proc);

   // Continue to loop until a WM_QUIT
   // message comes out of the queue.
   while (!fQuit) {
   
      // Do we have a valid file change notification handle?
      fWait4FileChanges = (INVALID_HANDLE_VALUE != g_hChange);
      
      // If we do, wait until a file change occurs OR until
      // a message shows up in our queue.
      dwResult = MsgWaitForMultipleObjects(
         (fWait4FileChanges) ? 1 : 0,
         &g_hChange, FALSE, INFINITE, QS_ALLEVENTS);


      if (fWait4FileChanges && (WAIT_OBJECT_0 == dwResult)) {
         // We awoke because of a file change notification.
         // Let's update the list box.

         // Increment the counter indicating the number
         // of notifications we have received.
         SetDlgItemInt(hwnd, IDC_NCOUNT, ++g_nCount, FALSE);

         // Get the root path and fill the list box with the
         // list of files in the path and the root
         // directory's subdirectories if the Include
         // Subdirectories check box is checked.
         GetDlgItemText(hwnd, IDC_PATH, szPath, 
            chDIMOF(szPath));
         DirWalk(GetDlgItem(hwnd, IDC_TREE), szPath,
            IsDlgButtonChecked(hwnd, IDC_INCSUBDIRS));

         // Tell the system that we processed the
         // notification.
         FindNextChangeNotification(g_hChange);
      } else {
      
         // We awoke because there is at least one message in
         // the queue. Let's dispatch all the queued messages.
         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
         
            // Call IsDialogMessage so that the keyboard can
            // be used to control focus in the dialog box.
            if (!IsDialogMessage(hwnd, &msg)) {
               if (msg.message == WM_QUIT) {
                  // If we have a WM_QUIT message,
                  // set the flag so that the
                  // loop terminates.
                  fQuit = TRUE;
               } else {
                  // Not a WM_QUIT message. Translate it
                  // and dispatch it.
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
               }
            }  // if (!IsDialogMessage())
         }  // while messages are still in the queue
      }  // if file change notification OR message
   }  // while (!fQuit)
   
   // The application is terminating. Destroy the modeless
   // dialog box.
   DestroyWindow(hwnd);
   
   return(0);
}


//////////////////////// End Of File ////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?