The return value of ReadFile is of BOOL type, which means the return value only indicates whether the function succeeds or fails. If the function fails, the return value does not provide the information about why it fails. You should call GetLastError to get the error code to check why ReadFile fails. The prototype of ReadFile is:
BOOL ReadFile(
[in] HANDLE hFile,
[out] LPVOID lpBuffer,
[in] DWORD nNumberOfBytesToRead,
[out, optional] LPDWORD lpNumberOfBytesRead,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
If you’ve reached the end of file, ReadFile still succeeds but lpNumberOfBytesRead will be set to 0. If you’ve reached near the end of file,i.e., the number of bytes you want to read (nNumberOfBytesToRead) is less than the remaining bytes of the file, ReadFile still succeeds but lpNumberOfBytesRead will be set to the number of remaining bytes. You should not reply on the return value of ReadFile but lpNumberOfBytesRead to determine whether you’ve reached the end of file, i.e., if ReadFile succeeds but lpNumberOfBytesRead < nNumberOfBytesToRead, you’ve arrived at the end of file. Using this end-of-file decision method, you might call ReadFile one more time than it actually needs to find that you’ve reached the end of file if the length of file is multiple times of nNumberOfBytesToRead, and at the last time, lpNumberOfBytesRead is 0.
Note that if ReadFile fails with an error(such as error code 23 – Data error (cyclic redundancy check) ), it will set lpNumberOfBytesRead to 0, and won’t move the internal file pointer forward, even it has read some data before encountering the error, as if it had read nothing.
ReadFile will fail with error code 87(ERROR_INVALID_PARAMETER) if current internal file pointer is not at the boundary of sector size(512 bytes), so you must set the file pointer at the sector boundary using SetFilePointerEx before calling ReadFile.