alertio.c

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

C
388
字号
/************************************************************
Module name: AlertIO.C
Notices: Copyright (c) 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 "Resource.H"


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


static BOOL PrepareDstFile(LPCTSTR pszFileSrc, LPCTSTR pszFileDst,
   PHANDLE phFileSrc, PHANDLE phFileDst, 
   PULARGE_INTEGER pulFileSize, DWORD dwPageSize) {

   ULARGE_INTEGER ulFileSizeDst;
   DWORD dwError;
   BOOL fOk = FALSE;

   __try {
      // Open the existing source file for input.
      *phFileSrc = CreateFile(pszFileSrc, GENERIC_READ,
         FILE_SHARE_READ, NULL, OPEN_EXISTING, 
         FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);

      if (*phFileSrc == INVALID_HANDLE_VALUE) 
         __leave;
   
      // Create the new destination file for output.
      *phFileDst = CreateFile(pszFileDst, GENERIC_WRITE,
         0, NULL, CREATE_ALWAYS, 
         FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, *phFileSrc);

      if (*phFileDst == INVALID_HANDLE_VALUE) 
         __leave;

      // Get the size of the original file.
      pulFileSize->LowPart = GetFileSize(*phFileSrc, 
         &pulFileSize->HighPart);

      // Round up the source file size 
      // to an even multiple of pages
      ulFileSizeDst.QuadPart = (pulFileSize->QuadPart + 
         dwPageSize - 1) & ~(dwPageSize - 1);

      // Force the destination file to the size needed.
      dwError = SetFilePointer(*phFileDst, ulFileSizeDst.LowPart, 
         (PLONG) ulFileSizeDst.HighPart, FILE_BEGIN);
      if ((dwError == 0xffffffff) && (GetLastError() != NO_ERROR))
         __leave;

      if (!SetEndOfFile(*phFileDst)) 
         __leave;

      fOk = TRUE; // We did everything successfully   
   }
   __finally {

      // If anything failed, clean up entirely
      if (!fOk) {
         if (*phFileSrc != INVALID_HANDLE_VALUE) {
            CloseHandle(*phFileSrc);
            *phFileSrc = INVALID_HANDLE_VALUE;
         }
         if (*phFileSrc != INVALID_HANDLE_VALUE) {
            CloseHandle(*phFileDst);
            *phFileDst = INVALID_HANDLE_VALUE;
         }
      }
   }
   return(fOk);
}


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


static void CopyCleanup(LPCTSTR pszFileDst, HANDLE hFileSrc, 
   HANDLE hFileDst, PULARGE_INTEGER pulFileSize) {

   // Close the source and destination files
   CloseHandle(hFileDst);
   CloseHandle(hFileSrc);
   
   // We need another handle to the destination file that is
   // opened without FILE_FLAG_NO_BUFFERING. This allows us 
   // to set the end-of-file marker to a position that is not 
   // sector-aligned.
   hFileDst = CreateFile(pszFileDst, GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
      OPEN_EXISTING, 0, NULL);

   if (hFileDst != INVALID_HANDLE_VALUE) {

      // Set the destination file's size to the size of the
      // source file, in case the size of the source file was
      // not a multiple of the page size.
      SetFilePointer(hFileDst, pulFileSize->LowPart, 
         (PLONG) pulFileSize->HighPart, FILE_BEGIN);
      SetEndOfFile(hFileDst);
      CloseHandle(hFileDst);
   }
}


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


typedef struct {
   // The page size used on the host machine
   DWORD dwPageSize;

   // Handles of the source and destination files
   HANDLE hFileSrc, hFileDst;

   // Size of source file
   ULARGE_INTEGER ulFileSize;

   // Offset in source file where next read begins
   ULARGE_INTEGER ulNextReadOffset;

   // The number of pending read & write I/O requests
   int nReadsInProgress;
   int nWritesInProgress;
} COPYSTATE, *PCOPYSTATE;


COPYSTATE g_cs;


// Each IO requires an OVERLAPPED structure and a buffer.
typedef struct {
	OVERLAPPED Overlapped;
	PBYTE      pbData;
} IOREQ, *PIOREQ;

#define MAX_PENDING_IO_REQS   4
#define BUFFSIZE              (64 * 1024)


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


VOID WINAPI WriteCompletionRoutine(DWORD dwErrorCode, 
   DWORD dwNumberOfBytesTransferred, 
   LPOVERLAPPED pOverlapped);


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


VOID WINAPI ReadCompletionRoutine(DWORD dwErrorCode, 
   DWORD dwNumberOfBytesTransferred, 
   LPOVERLAPPED pOverlapped) {

   PIOREQ pIOReq = (PIOREQ) pOverlapped;
   chASSERT(dwErrorCode == NO_ERROR);
   g_cs.nReadsInProgress--;

   // Round up the number of bytes to write 
   // to a sector boundary.
   dwNumberOfBytesTransferred = 
      (dwNumberOfBytesTransferred + g_cs.dwPageSize - 1) & 
      ~(g_cs.dwPageSize - 1);

   chVERIFY(WriteFileEx(g_cs.hFileDst, pIOReq->pbData, 
      dwNumberOfBytesTransferred, pOverlapped, 
      WriteCompletionRoutine));

   g_cs.nWritesInProgress++;
}


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


VOID WINAPI WriteCompletionRoutine(DWORD dwErrorCode, 
   DWORD dwNumberOfBytesTransferred, 
   LPOVERLAPPED pOverlapped) {

   PIOREQ pIOReq = (PIOREQ) pOverlapped;
   chASSERT(dwErrorCode == NO_ERROR);
   g_cs.nWritesInProgress--;

   if (g_cs.ulNextReadOffset.QuadPart < g_cs.ulFileSize.QuadPart) {
      // We haven't read past the end of the file yet.
      // Read the next chunk of data.
      pOverlapped->Offset     = g_cs.ulNextReadOffset.LowPart;   
      pOverlapped->OffsetHigh = g_cs.ulNextReadOffset.HighPart;   
      chVERIFY(ReadFileEx(g_cs.hFileSrc, pIOReq->pbData,
         BUFFSIZE, pOverlapped, ReadCompletionRoutine));

      g_cs.nReadsInProgress++;
      // Offset in source file where next read begins.
      g_cs.ulNextReadOffset.QuadPart += BUFFSIZE;
   }
}


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


BOOL FileCopy (LPCTSTR pszFileSrc, LPCTSTR pszFileDst) {

   // Maintain info about each IO request.
   IOREQ IOReq[MAX_PENDING_IO_REQS] = { 0 };

   SYSTEM_INFO si;
   int nIOReq;
   BOOL fOk;

   // Initialize the global COPYSTATE variable.
   GetSystemInfo(&si);
   g_cs.dwPageSize = si.dwPageSize;
   g_cs.ulNextReadOffset.QuadPart = 0;
   g_cs.nReadsInProgress = 0;
   g_cs.nWritesInProgress = 0;

   // Open the existing source file for input.
   fOk = PrepareDstFile(pszFileSrc, pszFileDst, 
      &g_cs.hFileSrc, &g_cs.hFileDst, 
      &g_cs.ulFileSize, g_cs.dwPageSize);
   if (!fOk) 
      return(fOk);

   // Start the copy engine by posting a number of read 
   // IO requests against the source file.
   for (nIOReq = 0; nIOReq < MAX_PENDING_IO_REQS; nIOReq++) {
      IOReq[nIOReq].Overlapped.Internal = 0;   
      IOReq[nIOReq].Overlapped.InternalHigh = 0;   
      IOReq[nIOReq].Overlapped.Offset = 
         g_cs.ulNextReadOffset.LowPart;
      IOReq[nIOReq].Overlapped.OffsetHigh = 
         g_cs.ulNextReadOffset.HighPart;   
      IOReq[nIOReq].Overlapped.hEvent = NULL;
      IOReq[nIOReq].pbData = VirtualAlloc(NULL, 
         BUFFSIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

      if (g_cs.ulNextReadOffset.QuadPart < 
         g_cs.ulFileSize.QuadPart) {

         chVERIFY(ReadFileEx(g_cs.hFileSrc, 
            IOReq[nIOReq].pbData, BUFFSIZE, 
            &IOReq[nIOReq].Overlapped, 
            ReadCompletionRoutine));
         g_cs.nReadsInProgress++;
         g_cs.ulNextReadOffset.QuadPart += BUFFSIZE;
      }
   }

   // Loop until an error has occurred or until the
   // destination file has been written.
   while ((g_cs.nReadsInProgress  > 0) || 
          (g_cs.nWritesInProgress > 0)) {
      SleepEx(INFINITE, TRUE);
   }

   // Free the memory buffers used for the copy.
   for (nIOReq = 0; nIOReq < MAX_PENDING_IO_REQS; nIOReq++) {
      VirtualFree(IOReq[nIOReq].pbData, 0, MEM_RELEASE);
   }

   // Close the source and destination files; force the
   // destination file to be the same size as the source.
   CopyCleanup(pszFileDst, g_cs.hFileSrc, 
      g_cs.hFileDst, &g_cs.ulFileSize);

   return(TRUE);
}


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


BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus, 
   LPARAM lParam) {

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

   // Disable the "Copy" button because no file 
   // has been selected yet.
   EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
   
   return(TRUE);
}


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


void Dlg_OnCommand (HWND hwnd, int id, 
   HWND hwndCtl, UINT codeNotify) {
   
   TCHAR szPathname[_MAX_DIR];
   BOOL fOk;
   OPENFILENAME ofn;

   switch (id) {
      case IDOK:
         // Copy the source file to the destination file.
         Static_GetText(GetDlgItem(hwnd, IDC_SRCFILE), 
            szPathname, sizeof(szPathname));
         SetCursor(LoadCursor(NULL, IDC_WAIT));
         FileCopy(szPathname, __TEXT("AlertIO.CPY"));
         break;

      case IDC_BROWSE:
         chINITSTRUCT(ofn, TRUE);
         ofn.hwndOwner = hwnd;
         ofn.lpstrFilter = __TEXT("*.*\0");
         _tcscpy(szPathname, __TEXT("*.*"));
         ofn.lpstrFile = szPathname;
         ofn.nMaxFile = sizeof(szPathname);
         ofn.Flags = OFN_FILEMUSTEXIST;
         fOk = GetOpenFileName(&ofn);
         
         if (fOk) {
            HANDLE hFile;
            Static_SetText(GetDlgItem(hwnd, IDC_SRCFILE), 
               szPathname);
            hFile = CreateFile(szPathname, GENERIC_READ,
               0, NULL, OPEN_EXISTING, 0, NULL);

            SetDlgItemInt(hwnd, IDC_SRCFILESIZE, 
               GetFileSize(hFile, NULL), FALSE);
            CloseHandle(hFile);
         }
         
         // Enable the "Copy" button if the user selected
         // a valid pathname.
         GetWindowText(GetDlgItem(hwnd, IDC_SRCFILE), 
            szPathname, sizeof(szPathname));
         EnableWindow(GetDlgItem(hwnd, IDOK), 
            szPathname[0] != __TEXT('('));
          
         if (fOk) {
            // If the user pressed the OK button in the file
            // dialog box, change focus to the "Copy" button.
            FORWARD_WM_NEXTDLGCTL(hwnd, 
               GetDlgItem(hwnd, IDOK), TRUE, SendMessage);
          }
         break;
         
      case IDCANCEL:
         EndDialog(hwnd, id);
         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) {

   chWARNIFUNICODEUNDERWIN95();
   DialogBox(hinstExe, MAKEINTRESOURCE(IDD_ALERTIO), 
      NULL, Dlg_Proc);

   return(0);
}


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

⌨️ 快捷键说明

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