|
|
1.1.1.2 ! root 1: /****************************************************************************\ ! 2: ** ** ! 3: ** Microsoft Developer Support ** ! 4: ** Copyright (c) 1992 Microsoft Corporation ** ! 5: ** ** ! 6: ** MODULE: IO.C ** ! 7: ** ** ! 8: ** ** ! 9: ** PURPOSE: Demonstrates the basic concepts envolved when using ** ! 10: ** asynchronous IO. In particular the main advantage is your ** ! 11: ** app more correctly thread can go about doing useful work ** ! 12: ** while waiting for IO. The main disadvantage is you must keep ** ! 13: ** track of the file pointer. ** ! 14: ** ** ! 15: ** INPUT: Both the File to read and File to write to must be entered ** ! 16: ** on via the command line. Note the file to write to must be ** ! 17: ** unique. ** ! 18: ** ** ! 19: ** FUNCTIONS: ** ! 20: ** ** ! 21: ** Do_BackgroundTask() ** ! 22: ** ** ! 23: ** ** ! 24: ** COMMENTS: Reads a file asynchronously writes to another synchronously ** ! 25: ** ** ! 26: ** ** ! 27: \***************************************************************************/ ! 28: ! 29: ! 30: 1.1 root 31: #define STRICT 32: #define NOMINMAX 33: #include <windows.h> 34: 35: #include <stdlib.h> 36: #include <stdio.h> 37: #include <memory.h> 38: #include <string.h> 39: 40: #define DEFAULT 0L 41: #define SUCCESS 0L 42: #define IO_ERROR (HANDLE)0xFFFFFFFF 43: #define WAIT_ERROR 0xFFFFFFFF 44: #define SECTOR_SIZE 1024 45: #define RETURN_IMEDIATELY 0L 46: 47: #if !defined(HEVENT) 48: typedef HANDLE HEVENT; 49: #endif 50: 51: #if !defined(HFILEEX) 52: typedef HANDLE HFILEEX; 53: #endif 54: 55: VOID ErrorMsg ( PSZ psz ) ; 56: VOID Do_BackgroundTask ( VOID ) ; 57: 58: 59: 60: void main ( int argc, char *argv[] ) 61: 62: { 63: 64: 65: HFILEEX hInfile, // Handle to the file to read 66: hOutfile; // Handle to the file to write to 67: 68: HEVENT hEvent ; // Handle to the synchronization Event 69: 70: OVERLAPPED 71: OverLapped ; // The operating system does not automatically 72: // track the current file position of a file 73: // open for asynchroous I/O. Instead one must 74: // manually track this by updating the OVERLAPPED 75: // structure. To update this structure one uses 76: // the result returned by GetOverLappedResults(). 77: 78: 79: CHAR buf[SECTOR_SIZE] ; // Buffer used by either 80: // ReadFile() or WriteFile() 81: 82: DWORD cbBytesRead, // count of bytes read by ReadFile() 83: // When asynchonous I/O is performed 84: // one must check how many bytes were 85: // read by calling GetOverLappedResults(). 86: 87: 88: cbBytesWritten, // count of bytes written by WriteFile() 89: 90: cbBytesTransfered ; // this value is returned by 91: // GetOverLappedResults() represents the 92: // count of bytes transfered asynchronous 93: 94: DWORD dwStatus, // value returned by GetLastError() 95: dwSuccess ; // return code of last API called 96: 97: BOOL bSuccess ; // return code of last API called 98: 99: CHAR buffer[80] ; 100: 101: /***************************************************************************\ 102: ** ** 103: ** This block of code initalizes all the necessary variables needed to do ** 104: ** asynchronous IO. Specfically it opens the files and initializes the ** 105: ** synchronization EVENT and OVERLAPPED structure needed to keep track ** 106: ** of asynchronous file I/O ** 107: ** ** 108: \***************************************************************************/ 109: 110: 111: if ( argc != 3 ) 112: { 113: printf ( "\nUsage: IO1 input_file output_file\n" ) ; 114: exit ( EXIT_FAILURE ) ; 115: } 116: 117: 118: 119: /* 120: * Open file which we will be copying. Note we are opening this 121: * asynchronously. 122: */ 123: 124: hInfile = CreateFile 125: ( 126: argv[1] // File to read 127: ,GENERIC_READ // Open file for reading only 128: ,FILE_SHARE_READ // Allow others to read file 129: ,NULL // No security 130: ,OPEN_EXISTING // Fail if file doesn't exit 131: ,FILE_FLAG_OVERLAPPED // Async I/o 132: ,DEFAULT 133: ) ; 134: 135: 136: if ( hInfile == IO_ERROR ) 137: { 138: strcpy ( buffer, "Error opening" ) ; 139: strcat ( buffer, argv[1] ) ; 140: ErrorMsg ( buffer ) ; 141: } 142: 143: 144: /* 145: * Create the file to write to; here we have opened it for synchronous IO. 146: */ 147: 148: hOutfile = CreateFile 149: ( 150: argv[2] // File to write to 151: ,GENERIC_WRITE // Open file only to write to 152: ,DEFAULT // No sharing allowed 153: ,NULL // No security 154: ,CREATE_NEW // Fail if file exists 155: ,FILE_ATTRIBUTE_NORMAL // No attributes 156: ,DEFAULT 157: ) ; 158: 159: 160: if ( hOutfile == IO_ERROR ) 161: { 162: strcpy ( buffer, "Error opening" ) ; 163: strcat ( buffer, argv[1] ) ; 164: ErrorMsg ( buffer ) ; 165: } 166: 167: 168: 169: /* 170: * Create Synchronoizing Event 171: */ 172: 173: hEvent = CreateEvent 174: ( 175: NULL // No security 176: ,TRUE // Manual reset 177: ,FALSE // Initially Event set to non-signaled state 178: ,NULL // No name 179: ) ; 180: if ( !hEvent ) 181: ErrorMsg ( "Error creating Event" ) ; 182: 183: 184: /* 185: * Intialize OverLapped structure. We will be using an Event instead 186: * of the file handle for synchronizing I/O. One reason to use a unique 187: * event instead of the file handle would be a so multi-threaded app 188: * would know which thread to unblock when the handle is set to the 189: * signaled state. 190: */ 191: 192: memset ( &OverLapped, 0, sizeof ( OVERLAPPED ) ) ; 193: OverLapped.hEvent = hEvent ; 194: 195: 196: bSuccess = TRUE ; 197: 198: 199: /***************************************************************************\ 200: ** ** 201: ** This is the main function of this program. Here we loop until the file ** 202: ** has been copied. Notice that even though we are using asynchronous I/O ** 203: ** ReadFile() may still return sychronously if it can be done fast enough ** 204: ** ** 205: \***************************************************************************/ 206: 207: while ( bSuccess ) 208: { 209: 210: /* 211: * Read file asynchronously 212: */ 213: 214: bSuccess = ReadFile 215: ( 216: hInfile // Handle of file to read 217: ,buf // Buffer to store input 218: ,SECTOR_SIZE // Number of bytes to read 219: ,&cbBytesRead // Number of bytes read. See note] 220: // above in delcaration 221: ,&OverLapped // Used for asynchronous I/O 222: ) ; 223: 224: 225: 226: /* 227: * Check whether ReadFile() has completed yet 228: */ 229: if ( !bSuccess && (( dwStatus = GetLastError ()) == ERROR_IO_PENDING ) ) 230: { 231: printf ( "\nIO Pending" ) ; 232: /* 233: * Read not complete yet first execute the background task then check 234: * to the if event "hEvent" set to the signaled state. If the event is 235: * not set signaled state then loop through again - run the background 236: * task and check the event. 237: * 238: */ 239: 240: Do_BackgroundTask () ; 241: 242: dwSuccess = WaitForSingleObject ( hEvent, RETURN_IMEDIATELY ) ; 243: 244: if ( dwSuccess == WAIT_ERROR ) 245: ErrorMsg("Error in WaitForSingleObject") ; 246: else if ( dwSuccess == SUCCESS ) 247: { 248: 249: bSuccess = GetOverlappedResult( 250: hInfile, &OverLapped, &cbBytesTransfered, FALSE) ; 251: if ( !bSuccess ) 252: ErrorMsg ( "Error in GetOverLappedResult" ) ; 253: else 254: { 255: // Read has completed now find out how many bytes have been read 256: 257: printf ( "\nNumber of bytes transfered is %d\n", cbBytesTransfered ) ; 258: OverLapped.Offset += cbBytesTransfered ; 259: cbBytesRead = cbBytesTransfered ; 260: } 261: } 262: else if ( dwSuccess == WAIT_TIMEOUT ) 263: Do_BackgroundTask () ; 264: } 265: /* 266: * ReadFile() read file synchronously; update Overlapped structure 267: */ 268: else if ( bSuccess && cbBytesRead != 0 ) 269: { 270: printf ( "\nNumber of bytes transfered is %d\n", cbBytesRead ) ; 271: OverLapped.Offset += cbBytesRead ; 272: } 273: /* 274: * ReadFile() has found the end of the file; exit loop 275: */ 276: else if ( bSuccess && cbBytesRead == 0 ) 277: { 278: printf ( "End of file read\n" ) ; 279: break ; 280: } 281: /* 282: * An error occured while reading, print out status and exit loop. 283: */ 284: else 285: ErrorMsg ( "Error reading to file" ) ; 286: 287: 288: 289: /* 290: * Write to file synchronously 291: */ 292: bSuccess = WriteFile 293: ( 294: hOutfile // Handle of file to write to 295: ,buf // Data to write to file 296: ,cbBytesRead // Number of bytes to write 297: ,&cbBytesWritten // Number of bytes written 298: ,NULL // Only need for asynchonous output 299: ) ; 300: 301: 302: if ( !bSuccess ) 303: ErrorMsg ( "Error writing to file" ) ; 304: 305: } // End of WHILE loop 306: 307: 308: 309: CloseHandle ( hInfile ) ; // Close handle to input file 310: FlushFileBuffers ( hOutfile ) ; // Make sure all data written to file first 311: CloseHandle ( hOutfile ) ; // Close handle to output file 312: exit ( EXIT_SUCCESS ) ; 313: 314: } 315: 316: 317: 318: /***************************************************************************\ 319: ** ** 320: ** FUNCTION: ErrorMsg(LPTSTR) ** 321: ** ** 322: ** PURPOSE: Prints out an error message the return code of the last API ** 323: ** to fail. ** 324: ** ** 325: ** INPUT: psz: This string is a description of where the code failed in ** 326: ** the module ** 327: ** ** 328: ** OUTPUT: None ** 329: ** ** 330: \****************************************************************************/ 331: 332: VOID ErrorMsg ( PSZ psz ) 333: { 334: 335: printf ("\n%s: return code = %d\n", psz, GetLastError()) ; 336: exit ( EXIT_FAILURE ) ; 337: } 338: 339: /***************************************************************************\ 340: ** ** 341: ** FUNCTION: Do_BackgroundTask ( VOID ) ** 342: ** ** 343: ** PURPOSE: Works in the background while IO sytems ** 344: ** ** 345: ** COMMENTS: ** 346: ** ** 347: ** Currently this does nothing if I have the time I will come up ** 348: ** with some silly task to keep the user entertained. ** 349: ** ** 350: ** INPUT: None ** 351: ** ** 352: ** OUTPUT: None ** 353: ** ** 354: \***************************************************************************/ 355: 356: VOID Do_BackgroundTask ( VOID ) 357: { 358: Sleep ( 5000L ) ; 359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.