Part 3.
3. Read from the disk (or file) with handle hDisk
Very simplified, one can only read from a disk that is not recognized as valid Windows disk (with or without partitions),
after retreaving the file handle with a different “open” parameter AND with Administrator privilige:
CONST GENERIC_READ = &h80000000
hDisk = CreateFileA("\\\\.\\PhysicalDrive1", GENERIC_READ, (FILE_SHARE_READ OR FILE_SHARE_WRITE), NIL, OPEN_EXISTING, 0, NullHandleTemplateFile)
Note: the combination (FILE_SHARE_READ OR FILE_SHARE_WRITE) seems the only combination working;
if NOT run as administrator, the result will be INVALID_HANDLE (= -1)
Now create a buffer for reading. The number of bytes to read (of write) must be a positive INTEGER multiple of BytesPerSector.
Example: choose buffersize = 1024 (= 2 * 512), so NumToRead must be 1024 then.
DIM NumToRead AS INTEGER
DIM NumActualRead AS INTEGER
DIM lpBuffer AS MemoryBlock(NumToRead)
Note: for a very large blocksize, Xojo.MemoryBlock() should be used instead
The ReadFile function is declared:
Declare Function ReadFile Lib "kernel32" (hFile AS INTEGER, lpBuffer AS PTR, nNumberOfBytesToRead AS INTEGER, byRef lpNumberOfBytesRead AS INTEGER, lpOverlapped AS PTR) AS Boolean
Now reading is possible. The lpOverlapped -pointer is not used, so use NIL.
DIM bResult AS BOOLEAN
bResult = ReadFile(hDisk, lpBuffer, NumToRead, NumActualRead, NIL)
This will read NumToRead bytes from the current position on the disk c.q. file (e.g. 0, when starting). If succesfull, succeeding reads start at positions NumToRead, 2*NumToRead etc. NumActualRead will give the number of bytes that could be read (possibly partially, e.g. if arrived at end of disk/file).
If reading failed for some reason, one can inquire the system by using the function GetLastError:
Declare Function GetLastError Lib "kernel32" AS INTEGER
It will return an errornumber that can be searched for in MSDN; errornumber 87 points to “invalid parameter”,
most likely meaning that NumToRead was NOT an integer multiple of BytesPerSector
To make it easier to start reading from a specified position in the drive/file, one can use the function SetFilePointer.
Declare Function SetfilePointer(hDisk AS INTEGER, lDistanceToMoveLOW AS INTEGER, lpDistanceToMoveHIGH AS PTR, dwMoveMethod AS INTEGER) AS INTEGER
For not too large, non-compressed, (<= 2GB) disks/files generally only lDistanceToMoveLOW is used (non-zero).
For large disks/files a variable must be created to hold the high-order part of the offset.
dwMoveMethod can hold one of three values: File_Begin (=0): relative to start of disk/file, File_Current (=1): rel. to current position in file, File_End (=2): (backwards from) end of file. The specified offset may be negative (with File_Current).
The function will return the actual position in the disk/file after repositioning the pointer.
After ending all read-actions, the disk/file should be closed, by using CloseHandle(hDisk), declared earlier in this post.
(
4. Writing to disk ??"
This should be possible, without to much complexity, for disks that do not contain recognized (Windows) partitions etc.
The device has to be opened with CreateFileA with specific parameters that allow writing. One then uses WriteFile().
In some situations this “raw” access might be useful, e.g. if you use that drive exclusively for your own data. I have not tried this.
Of course the program must run with priviliges as Administrator.
The IBored program from Thomas Tempelmann might work in some situations, but he doesn’t guarantee that for the Windows version.
For accessing already existing partitions one would use the standard functions for fileaccess on the filesystems instead, to prevent accidental data-loss or even damage to the filesystem itself.
)