Now, I'm already familiar with the DeviceIoControl (ioctl) process and can read from a disk sequentially, 512 bytes at a time.
I create a handle from the list of \.\PhysicalDrive(s) and identify it via IOCTL_STORAGE_QUERY_PROPERTY command. Then process the desired device for data.
At this point, I can read it progressively by creating a loop that advances the read area 1 sector each time with this code (Qt C++ environment)
#include <minwindef.h>
#include <devioctl.h>
#include <ntdddisk.h>
#include <ntddscsi.h>
#include <ioapiset.h>
#include <fileapi.h>
#include <handleapi.h>
#include <winbase.h>
...
HANDLE devHandle = NULL;
devHandle = CreateFile(charArray, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0 ,NULL);
unsigned long secCount = 0;
while(true)
{
bSuccess = ReadFile(devHandle, lpSecBuf, 512, &dwRead, NULL);
if (bSuccess & (dwRead < 512))
{
qDebug()<<"EOF";
break;
}
if(!bSuccess)
{
qDebug()<<"No data could be read from the device.";
break;
}
if(bSuccess && dwRead>0)
{
qDebug()<<"Sector "<<secCount<<" data : "<<lpSecBuf;
}
secCount++;
}
Doing this sequentially means I have to progress through the sectors one by one, counting, until I reach the sector number I want to access. And this is not very optimal in performance.
What if I wanted to access a specific region directly, like "go to sector 45535 and read 512 bytes"? Does IOCTL operation even allow random access like this? I understand there are Random Access flags to a CreateFile call but after that, what? The read function still doesn't allow me to pass any arguments as "destination" or something like that, as far as I can see.
For example, HxD the hex editor can count the number of total sectors in a disk immediately and can go to a certain sector at any time. The function I need is similar to this capability.
I have collected various tips as to how it can be done but I'm practically at an impasse here.
Any ideas would be welcome.

this is not true - read again about
ReadFileand this:
the I/O Manager maintains the current file position. ( look for
LARGE_INTEGER CurrentByteOffsetmember ofFILE_OBJECT).ReadFileandWriteFileupdates the current file position by adding the number of bytes read or written when it completes the operation. also we can set this position by callSetFilePointer[Ex]if we open file in synchronous mode (without
FILE_FLAG_OVERLAPPEDflag) all operations with file is sequential - any new operation not begin execute until previous not finished.in this case we have two options :
NULLpointer forlpOverlappedlpOverlappedvalue toReadFileorWriteFile. Doing this automatically changes the current file position to that(Offset, OffsetHigh)value, performs the read(write) operation, and then updates the position according to the number of bytes actually read(write). This technique gives the caller atomic seek-and-read(write) service.so by code we have 2 variants:
of course atomic seek-and-read(write) much more effective compare using
SetFilePointer[Ex](additional API call to kernel).if we open file in asynchronous mode (with
FILE_FLAG_OVERLAPPEDflag) - multiple read/write operations with file can executed at same time. in this case I/O Manager can not use the file position inFILE_OBJECT- because this undefined behavior here.so we must always explicit pass
lpOverlappedwith valid offset. if we pass aNULLpointer for lpOverlapped - we gotERROR_INVALID_PARAMETERerrorat the last but important. from MSDN (at ReadFile and WriteFile pages)
this is not true and mistake in documentation - you can check yourself that
OVERLAPPEDoffset not updated after operation. may be mean that current file position (CurrentByteOffsetinFILE_OBJECT) is updated. but againOVERLAPPEDoffset is not updated after operation