6-3
/*
* IoByAPC.c
*
* Sample code for Multithreading Applications in Win32
* This is from Chapter 6, Listing 6-3
*
* Demonstrates how to use APC's (asynchronous
* procedure calls) instead of signaled objects
* to service multiple outstanding overlapped
* operations on a file.
*/
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "MtVerify.h"
//
// Constants
//
#define MAX_REQUESTS 5
#define READ_SIZE 512
#define MAX_TRY_COUNT 5
//
// Function prototypes
//
void CheckOsVersion();
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount);
//
// Global variables
//
// Need a single event object so we know when all I/O is finished
HANDLE ghEvent;
// Keep track of each individual I/O operation
OVERLAPPED gOverlapped[MAX_REQUESTS];
// Handle to the file of interest.
HANDLE ghFile;
// Need a place to put all this data
char gBuffers[MAX_REQUESTS][READ_SIZE];
int nCompletionCount;
/*
* I/O Completion routine gets called
* when app is alertable (in WaitForSingleObjectEx)
* and an overlapped I/O operation has completed.
*/
VOID WINAPI FileIOCompletionRoutine(
DWORD dwErrorCode, // completion code
DWORD dwNumberOfBytesTransfered, // number of bytes transferred
LPOVERLAPPED lpOverlapped // pointer to structure with I/O information
)
{
// The event handle is really the user defined data
int nIndex = (int)(lpOverlapped->hEvent);
printf("Read #%d returned %d. %d bytes were read.\n",
nIndex,
dwErrorCode,
dwNumberOfBytesTransfered);
if (++nCompletionCount == MAX_REQUESTS)
SetEvent(ghEvent); // Cause the wait to terminate
}
int main()
{
int i;
char szPath[MAX_PATH];
CheckOsVersion();
// Need to know when to stop
MTVERIFY(
ghEvent = CreateEvent(
NULL, // No security
TRUE, // Manual reset - extremely important!
FALSE, // Initially set Event to non-signaled state
NULL // No name
)
);
GetWindowsDirectory(szPath, sizeof(szPath));
strcat(szPath, "http://www.cnblogs.com/nanshouyong326/admin/file://WINHLP32.EXE/");
// Open the file for overlapped reads
ghFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (ghFile == INVALID_HANDLE_VALUE)
{
printf("Could not open %s\n", szPath);
return -1;
}
// Queue up a few requests
for (i=0; i<MAX_REQUESTS; i++)
{
// Read some bytes every few K
QueueRequest(i, i*16384, READ_SIZE);
}
printf("QUEUED!!\n");
// Wait for all the operations to complete.
for (;;)
{
DWORD rc;
rc = WaitForSingleObjectEx(ghEvent, INFINITE, TRUE );
if (rc == WAIT_OBJECT_0)
break;
MTVERIFY(rc == WAIT_IO_COMPLETION);
}
CloseHandle(ghFile);
return EXIT_SUCCESS;
}
/*
* Call ReadFileEx to start an overlapped request.
* Make sure we handle errors that are recoverable.
*/
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount)
{
int i;
BOOL rc;
DWORD err;
gOverlapped[nIndex].hEvent = (HANDLE)nIndex;
gOverlapped[nIndex].Offset = dwLocation;
for (i=0; i<MAX_TRY_COUNT; i++)
{
rc = ReadFileEx(
ghFile,
gBuffers[nIndex],
dwAmount,
&gOverlapped[nIndex],
FileIOCompletionRoutine
);
// Handle success
if (rc)
{
// asynchronous i/o is still in progress
printf("Read #%d queued for overlapped I/O.\n", nIndex);
return TRUE;
}
err = GetLastError();
// Handle recoverable error
if ( err == ERROR_INVALID_USER_BUFFER ||
err == ERROR_NOT_ENOUGH_QUOTA ||
err == ERROR_NOT_ENOUGH_MEMORY )
{
Sleep(50); // Wait around and try later
continue;
}
// Give up on fatal error.
break;
}
printf("ReadFileEx failed.\n");
return -1;
}
//
// Make sure we are running under an operating
// system that supports overlapped I/O to files.
//
void CheckOsVersion()
{
OSVERSIONINFO ver;
BOOL bResult;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bResult = GetVersionEx((LPOSVERSIONINFO) &ver);
if ( (!bResult) ||
(ver.dwPlatformId != VER_PLATFORM_WIN32_NT) )
{
fprintf(stderr, "IoByAPC must be run under Windows NT.\n");
exit(EXIT_FAILURE);
}
}
od
00401040 /$ 81EC 0C020000 sub esp, 20C
00401046 |. 56 push esi
00401047 |. 57 push edi
00401048 |. E8 E3020000 call 00401330
0040104D |. 6A 00 push 0 ; /EventName = NULL
0040104F |. 6A 00 push 0 ; |InitiallySignaled = FALSE
00401051 |. 6A 01 push 1 ; |ManualReset = TRUE
00401053 |. 6A 00 push 0 ; |pSecurity = NULL
00401055 |. FF15 28204000 call dword ptr [<&KERNEL32.CreateEven>; \CreateEventA
0040105B |. 85C0 test eax, eax
0040105D |. A3 90314000 mov dword ptr [403190], eax
00401062 |. 0F85 80000000 jnz 004010E8
00401068 |. FF15 24204000 call dword ptr [<&KERNEL32.GetLastErr>; [GetLastError
0040106E |. 6A 00 push 0 ; /Arguments = NULL
00401070 |. 8D4C24 0C lea ecx, dword ptr [esp+C] ; |
00401074 |. 6A 00 push 0 ; |BufSize = 0
00401076 |. 51 push ecx ; |Buffer
00401077 |. 6A 00 push 0 ; |LanguageId = 0 (LANG_NEUTRAL)
00401079 |. 50 push eax ; |MessageId
0040107A |. 6A 00 push 0 ; |pSource = NULL
0040107C |. 68 00110000 push 1100 ; |Flags = ALLOCATE_BUFFER|FROM_SYSTEM|0
00401081 |. FF15 20204000 call dword ptr [<&KERNEL32.FormatMess>; \FormatMessageA
00401087 |. 8B5424 08 mov edx, dword ptr [esp+8]
0040108B |. 8D4424 10 lea eax, dword ptr [esp+10]
0040108F |. 52 push edx ; /<%s>
00401090 |. 68 D8304000 push 004030D8 ; |<%s> = "ghEvent = CreateEvent( NULL, TRUE, FALSE, NULL )"
00401095 |. 68 CC304000 push 004030CC ; |<%s> = "IoByAPC.c"
0040109A |. 6A 55 push 55 ; |<%d> = 55 (85.)
0040109C |. 68 88304000 push 00403088 ; |Format = LF,"The following call failed at line %d in %s:",LF,LF," %s",LF,LF,"Reason: %s",LF,""
004010A1 |. 50 push eax ; |s
004010A2 |. FF15 7C204000 call dword ptr [<&USER32.wsprintfA>] ; \wsprintfA
004010A8 |. 83C4 18 add esp, 18
004010AB |. 8D4C24 0C lea ecx, dword ptr [esp+C]
004010AF |. 8D7C24 10 lea edi, dword ptr [esp+10]
004010B3 |. 33C0 xor eax, eax
004010B5 |. 6A 00 push 0 ; /pOverlapped = NULL
004010B7 |. 51 push ecx ; |pBytesWritten
004010B8 |. 83C9 FF or ecx, FFFFFFFF ; |
004010BB |. 8D5424 18 lea edx, dword ptr [esp+18] ; |
004010BF |. F2:AE repne scas byte ptr es:[edi] ; |
004010C1 |. F7D1 not ecx ; |
004010C3 |. 49 dec ecx ; |
004010C4 |. 51 push ecx ; |nBytesToWrite
004010C5 |. 52 push edx ; |Buffer
004010C6 |. 6A F4 push -0C ; |/DevType = STD_ERROR_HANDLE
004010C8 |. FF15 1C204000 call dword ptr [<&KERNEL32.GetStdHand>; |\GetStdHandle
004010CE |. 50 push eax ; |hFile
004010CF |. FF15 18204000 call dword ptr [<&KERNEL32.WriteFile>>; \WriteFile
004010D5 |. 68 B80B0000 push 0BB8 ; /Timeout = 3000. ms
004010DA |. FF15 14204000 call dword ptr [<&KERNEL32.Sleep>] ; \Sleep
004010E0 |. 6A 01 push 1 ; /status = 1
004010E2 |. FF15 40204000 call dword ptr [<&MSVCRTD.exit>] ; \exit
004010E8 |> 53 push ebx
004010E9 |. 8D8424 140100>lea eax, dword ptr [esp+114]
004010F0 |. 68 04010000 push 104 ; /BufSize = 104 (260.)
004010F5 |. 50 push eax ; |Buffer
004010F6 |. FF15 10204000 call dword ptr [<&KERNEL32.GetWindows>; \GetWindowsDirectoryA
004010FC |. BF 78304000 mov edi, 00403078 ; ASCII "\WINHLP32.EXE"
00401101 |. 83C9 FF or ecx, FFFFFFFF
00401104 |. 33C0 xor eax, eax
00401106 |. 8D9424 140100>lea edx, dword ptr [esp+114]
0040110D |. F2:AE repne scas byte ptr es:[edi]
0040110F |. F7D1 not ecx
00401111 |. 2BF9 sub edi, ecx
00401113 |. 50 push eax ; /hTemplateFile => NULL
00401114 |. 8BF7 mov esi, edi ; |
00401116 |. 8BD9 mov ebx, ecx ; |
00401118 |. 8BFA mov edi, edx ; |
0040111A |. 83C9 FF or ecx, FFFFFFFF ; |
0040111D |. F2:AE repne scas byte ptr es:[edi] ; |
0040111F |. 8BCB mov ecx, ebx ; |
00401121 |. 4F dec edi ; |
00401122 |. C1E9 02 shr ecx, 2 ; |
00401125 |. F3:A5 rep movs dword ptr es:[edi], dword p>; |
00401127 |. 68 00000040 push 40000000 ; |Attributes = OVERLAPPED
0040112C |. 8BCB mov ecx, ebx ; |
0040112E |. 6A 03 push 3 ; |Mode = OPEN_EXISTING
00401130 |. 50 push eax ; |pSecurity => NULL
00401131 |. 83E1 03 and ecx, 3 ; |
00401134 |. 6A 03 push 3 ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00401136 |. 8D8424 280100>lea eax, dword ptr [esp+128] ; |
0040113D |. 68 00000080 push 80000000 ; |Access = GENERIC_READ
00401142 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>; |
00401144 |. 50 push eax ; |FileName
00401145 |. FF15 0C204000 call dword ptr [<&KERNEL32.CreateFile>; \CreateFileA
0040114B |. 83F8 FF cmp eax, -1
0040114E |. A3 94314000 mov dword ptr [403194], eax
00401153 |. 5B pop ebx
00401154 |. 75 22 jnz short 00401178
00401156 |. 8D8C24 100100>lea ecx, dword ptr [esp+110]
0040115D |. 51 push ecx ; /<%s>
0040115E |. 68 64304000 push 00403064 ; |format = "Could not open %s",LF,""
00401163 |. FF15 3C204000 call dword ptr [<&MSVCRTD.printf>] ; \printf
00401169 |. 83C4 08 add esp, 8
0040116C |. 83C8 FF or eax, FFFFFFFF
0040116F |. 5F pop edi
00401170 |. 5E pop esi
00401171 |. 81C4 0C020000 add esp, 20C
00401177 |. C3 retn
00401178 |> 33FF xor edi, edi
0040117A |. 33F6 xor esi, esi
0040117C |> 68 00020000 /push 200
00401181 |. 56 |push esi
00401182 |. 57 |push edi
00401183 |. E8 E8000000 |call 00401270
00401188 |. 83C4 0C |add esp, 0C
0040118B |. 81C6 00400000 |add esi, 4000
00401191 |. 47 |inc edi
00401192 |. 81FE 00400100 |cmp esi, 14000
00401198 |.^ 72 E2 \jb short 0040117C
0040119A |. 68 58304000 push 00403058 ; /format = "QUEUED!!",LF,""
0040119F |. FF15 3C204000 call dword ptr [<&MSVCRTD.printf>] ; \printf
004011A5 |. 8B15 90314000 mov edx, dword ptr [403190]
004011AB |. 8B35 08204000 mov esi, dword ptr [<&KERNEL32.WaitF>; kernel32.WaitForSingleObjectEx
004011B1 |. 83C4 04 add esp, 4
004011B4 |. 6A 01 push 1 ; /fAlertable = TRUE
004011B6 |. 6A FF push -1 ; |Timeout = INFINITE
004011B8 |. 52 push edx ; |hObject => NULL
004011B9 |. FFD6 call esi ; \WaitForSingleObjectEx
004011BB |. 85C0 test eax, eax
004011BD |. 74 17 je short 004011D6
004011BF |> 3D C0000000 /cmp eax, 0C0
004011C4 |. 75 28 |jnz short 004011EE
004011C6 |. A1 90314000 |mov eax, dword ptr [403190]
004011CB |. 6A 01 |push 1
004011CD |. 6A FF |push -1
004011CF |. 50 |push eax
004011D0 |. FFD6 |call esi
004011D2 |. 85C0 |test eax, eax
004011D4 |.^ 75 E9 \jnz short 004011BF
004011D6 |> 8B0D 94314000 mov ecx, dword ptr [403194]
004011DC |. 51 push ecx ; /hObject => NULL
004011DD |. FF15 04204000 call dword ptr [<&KERNEL32.CloseHandl>; \CloseHandle
004011E3 |. 5F pop edi
004011E4 |. 33C0 xor eax, eax
004011E6 |. 5E pop esi
004011E7 |. 81C4 0C020000 add esp, 20C
004011ED |. C3 retn
004011EE |> FF15 24204000 call dword ptr [<&KERNEL32.GetLastErr>; [GetLastError
004011F4 |. 6A 00 push 0 ; /Arguments = NULL
004011F6 |. 8D5424 0C lea edx, dword ptr [esp+C] ; |
004011FA |. 6A 00 push 0 ; |BufSize = 0
004011FC |. 52 push edx ; |Buffer
004011FD |. 6A 00 push 0 ; |LanguageId = 0 (LANG_NEUTRAL)
004011FF |. 50 push eax ; |MessageId
00401200 |. 6A 00 push 0 ; |pSource = NULL
00401202 |. 68 00110000 push 1100 ; |Flags = ALLOCATE_BUFFER|FROM_SYSTEM|0
00401207 |. FF15 20204000 call dword ptr [<&KERNEL32.FormatMess>; \FormatMessageA
0040120D |. 8B4424 08 mov eax, dword ptr [esp+8]
00401211 |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00401215 |. 50 push eax ; /<%s>
00401216 |. 68 3C304000 push 0040303C ; |<%s> = "rc == WAIT_IO_COMPLETION"
0040121B |. 68 CC304000 push 004030CC ; |<%s> = "IoByAPC.c"
00401220 |. 6A 78 push 78 ; |<%d> = 78 (120.)
00401222 |. 68 88304000 push 00403088 ; |Format = LF,"The following call failed at line %d in %s:",LF,LF," %s",LF,LF,"Reason: %s",LF,""
00401227 |. 51 push ecx ; |s
00401228 |. FF15 7C204000 call dword ptr [<&USER32.wsprintfA>] ; \wsprintfA
0040122E |. 8D7C24 28 lea edi, dword ptr [esp+28]
00401232 |. 83C9 FF or ecx, FFFFFFFF
00401235 |. 33C0 xor eax, eax
00401237 |. 83C4 18 add esp, 18
0040123A |. F2:AE repne scas byte ptr es:[edi]
0040123C |. F7D1 not ecx
0040123E |. 8D5424 0C lea edx, dword ptr [esp+C]
00401242 |. 6A 00 push 0 ; /pOverlapped = NULL
00401244 |. 49 dec ecx ; |
00401245 |. 52 push edx ; |pBytesWritten
00401246 |. 8D4424 18 lea eax, dword ptr [esp+18] ; |
0040124A |. 51 push ecx ; |nBytesToWrite
0040124B |. 50 push eax ; |Buffer
0040124C |. 6A F4 push -0C ; |/DevType = STD_ERROR_HANDLE
0040124E |. FF15 1C204000 call dword ptr [<&KERNEL32.GetStdHand>; |\GetStdHandle
00401254 |. 50 push eax ; |hFile
00401255 |. FF15 18204000 call dword ptr [<&KERNEL32.WriteFile>>; \WriteFile
0040125B |. 68 B80B0000 push 0BB8 ; /Timeout = 3000. ms
00401260 |. FF15 14204000 call dword ptr [<&KERNEL32.Sleep>] ; \Sleep
00401266 |. 6A 01 push 1 ; /status = 1
00401268 |. FF15 40204000 call dword ptr [<&MSVCRTD.exit>] ; \exit
0040126E |. 90 nop
0040126F |. 90 nop
00401270 |$ 53 push ebx
00401271 |. 55 push ebp
00401272 |. 56 push esi
00401273 |. 57 push edi
00401274 |. 8B7C24 14 mov edi, dword ptr [esp+14]
00401278 |. 8B4C24 18 mov ecx, dword ptr [esp+18]
0040127C |. 8B5C24 1C mov ebx, dword ptr [esp+1C]
00401280 |. 8B2D 2C204000 mov ebp, dword ptr [<&KERNEL32.ReadF>; kernel32.ReadFileEx
00401286 |. 8D04BF lea eax, dword ptr [edi+edi*4]
00401289 |. 33F6 xor esi, esi
0040128B |. C1E0 02 shl eax, 2
0040128E |. 89B8 B03B4000 mov dword ptr [eax+403BB0], edi
00401294 |. 8988 A83B4000 mov dword ptr [eax+403BA8], ecx
0040129A |. 8D90 A03B4000 lea edx, dword ptr [eax+403BA0]
004012A0 |. 8BC7 mov eax, edi
004012A2 |. C1E0 09 shl eax, 9
004012A5 |. 895424 14 mov dword ptr [esp+14], edx
004012A9 |. 8D88 A0314000 lea ecx, dword ptr [eax+4031A0]
004012AF |. 894C24 18 mov dword ptr [esp+18], ecx
004012B3 |> 8B5424 14 /mov edx, dword ptr [esp+14]
004012B7 |. 8B4424 18 |mov eax, dword ptr [esp+18]
004012BB |. 8B0D 94314000 |mov ecx, dword ptr [403194]
004012C1 |. 68 00104000 |push 00401000
004012C6 |. 52 |push edx
004012C7 |. 53 |push ebx
004012C8 |. 50 |push eax
004012C9 |. 51 |push ecx
004012CA |. FFD5 |call ebp
004012CC |. 85C0 |test eax, eax
004012CE |. 75 3D |jnz short 0040130D
004012D0 |. FF15 24204000 |call dword ptr [<&KERNEL32.GetLastEr>; [GetLastError
004012D6 |. 3D F8060000 |cmp eax, 6F8
004012DB |. 74 0C |je short 004012E9
004012DD |. 3D 18070000 |cmp eax, 718
004012E2 |. 74 05 |je short 004012E9
004012E4 |. 83F8 08 |cmp eax, 8
004012E7 |. 75 0E |jnz short 004012F7
004012E9 |> 6A 32 |push 32 ; /Timeout = 50. ms
004012EB |. FF15 14204000 |call dword ptr [<&KERNEL32.Sleep>] ; \Sleep
004012F1 |. 46 |inc esi
004012F2 |. 83FE 05 |cmp esi, 5
004012F5 |.^ 7C BC \jl short 004012B3
004012F7 |> 68 34314000 push 00403134 ; /format = "ReadFileEx failed.",LF,""
004012FC |. FF15 3C204000 call dword ptr [<&MSVCRTD.printf>] ; \printf
00401302 |. 83C4 04 add esp, 4
00401305 |. 83C8 FF or eax, FFFFFFFF
00401308 |. 5F pop edi
00401309 |. 5E pop esi
0040130A |. 5D pop ebp
0040130B |. 5B pop ebx
0040130C |. C3 retn
0040130D |> 57 push edi ; /<%d>
0040130E |. 68 0C314000 push 0040310C ; |format = "Read #%d queued for overlapped I/O.",LF,""
00401313 |. FF15 3C204000 call dword ptr [<&MSVCRTD.printf>] ; \printf
00401319 |. 83C4 08 add esp, 8
0040131C |. B8 01000000 mov eax, 1
00401321 |. 5F pop edi
00401322 |. 5E pop esi
00401323 |. 5D pop ebp
00401324 |. 5B pop ebx
00401325 \. C3 retn
routu
00401000 . 8B4424 08 mov eax, dword ptr [esp+8]
00401004 . 8B5424 0C mov edx, dword ptr [esp+C]
00401008 . 8B4C24 04 mov ecx, dword ptr [esp+4]
0040100C . 50 push eax ; /<%d>
0040100D . 8B42 10 mov eax, dword ptr [edx+10] ; |
00401010 . 51 push ecx ; |<%d>
00401011 . 50 push eax ; |<%d>
00401012 . 68 10304000 push 00403010 ; |format = "Read #%d returned %d. %d bytes were read.",LF,""
00401017 . FF15 3C204000 call dword ptr [<&MSVCRTD.printf>] ; \printf
0040101D . A1 98314000 mov eax, dword ptr [403198]
00401022 . 83C4 10 add esp, 10
00401025 . 40 inc eax
00401026 . 83F8 05 cmp eax, 5
00401029 . A3 98314000 mov dword ptr [403198], eax
0040102E . 75 0D jnz short 0040103D
00401030 . 8B0D 90314000 mov ecx, dword ptr [403190]
00401036 . 51 push ecx ; /hEvent => NULL
00401037 . FF15 00204000 call dword ptr [<&KERNEL32.SetEvent>] ; \SetEvent
0040103D > C2 0C00 retn 0C
ida