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