I am using ReadFileEx to read some bytes from a file and using WriteFileEx to write some bytes to a device. This action will repeat till all file bytes are read and written to the device.
Reason I use Ex APIs is because by requesting overlapped IOs to the OS can keep UI thread responsive updating a progress bar while the read/write function is doing their tasks.
The process begins with a ReadFileEx and a MY_OVERLAPPED
structure and a ReadCompletionRoutine
will be passed in together. Once the read is done, the read completion routine will be called. Inside the routine, a WriteFileEx will be emitted and WriteCompletionRoutine will be called. Inside the write completion routine, another ReadFileEx will be emitted after the offset of the MY_OVERLAPPED structure is reset to next position. That is, two completions will call each other once a read or write is done.
Notice that the above process will only be executed if the calling thread is under alertable state. I use a while loop to keep the thread alertable by keep checking a global state variable is set to TRUE or not. The state variable, completed
, will be set to TRUE inside ReadCompletionRoutine
once all procedure is done.
FYI, MY_OVERLAPPED
structure is a self-define structure that inherits OVERLAPPPED
structure so that I can add 2 more information I need to it.
Now, my question is I would like to add a cancel function so that the user can cancel all the process that has been started. What I do is pretty simple. I set the completed
variable to TRUE when a cancel button is pressed, so the while loop will break and alertable state will be stoped so the completion routines won't be executed. But, I don't know how to cancel the overlapped request that sent by the Read/WriteFileEx
and their completion routines along with the MY_OVERLAPPED
structure(see the //******* part in code). Now my code will crash once the cancel button is pressed. The cancel part is the one causing the crash. Please help, thank you.
//In MyClass.h========================================
struct MY_OVERLAPPED: OVERLAPPED {
MyClass *event;
unsigned long long count;
};
//In MyClass.cpp - main===============================
MY_OVERLAPPED overlap;
memset(&overlap, 0,sizeof(overlap));
//point to this class (MyClass), so all variables can later be accessed
overlap.event = this;
//set read position
overlap.Offset = 0;
overlap.OffsetHigh = 0;
overlap.count = 0;
//start the first read io request, read 524288 bytes, which 524288 bytes will be written in ReadCompletionRoutine
ReadFileEx(overlap.event->hSource, overlap.event->data, 524288, &overlap, ReadCompletionRoutine);
while(completed != true) {
updateProgress(overlap.count);
SleepEx(0,TRUE);
}
//********
CancelIo(overlap.event.hSource);
CancelIo(overlap.event.hDevice);
//********
//In MyClass.cpp - CALLBACKs===============================
void CALLBACK ReadCompletionRoutine(DWORD errorCode, DWORD bytestransfered, LPOVERLAPPED lpOverlapped)
{
//type cast to MY_OVERLAPPED
MY_OVERLAPPED *overlap = static_cast<MY_OVERLAPPED*>(lpOverlapped);
//write 524288 bytes and continue to read next 524288 bytes in WriteCompletionRoutine
WriteFileEx(overlap->event->hDevice, overlap->event->data, 524288, overlap, WriteCompletionRoutine);
}
void CALLBACK WriteCompletionRoutine(DWORD errorCode, DWORD bytestransfered, LPOVERLAPPED lpOverlapped)
{
MY_OVERLAPPED *overlap = static_cast<MY_OVERLAPPED*>(lpOverlapped);
if(overlap->count<fileSize/524288) {
//set new offset to 524288*i, i = overlap->count for next block reading
overlap->count = (overlap->count)+1;
LARGE_INTEGER location;
location.QuadPart = 524288*(overlap->count);
overlap->Offset = location.LowPart;
overlap->OffsetHigh = location.HighPart;
ReadFileEx(overlap->event->hSource, overlap->event->data, 524288, overlap, ReadCompletionRoutine);
}
else {
completed = TRUE;
}
}
Note that I prefer not to use multi-thread programming. Other than that, any better way of accomplishing the same goals is appreciated. Please and feel free to provide detail code and explanations. Thanks.