Jump to content

ReadFileScatter / FILE_SEGMENT_ELEMENT definition


KaFu
 Share

Recommended Posts

HiHo Forum :),

I'm currently trying to create a working example for ReadFileScatter.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365469(v=vs.85).aspx

http://en.wikipedia.org/wiki/Vectored_I/O

The code is based on my example "Overlapped (Asynchronous) & UnBuffered ReadFile Example"

What should the example do? Extract 3 * 16 KB from @AutoItExe and show it in a MsgBox(), first 16KB, 16KB from the middle of the file and the last 16KB of the file.

The problem seems to be in my definition of the FILE_SEGMENT_ELEMENT structure, the function returns "998 Invalid access to memory location".

typedef union _FILE_SEGMENT_ELEMENT {

PVOID64 Buffer;

ULONGLONG Alignment;

}FILE_SEGMENT_ELEMENT, *PFILE_SEGMENT_ELEMENT;

How to translate this into a tag for a DllStructCreate() call?

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <StructureConstants.au3>
#include <..\WinAPIEx_3.8_3380\WinAPIEx.au3>
#include <Memory.au3>
#include <array.au3>

Global $nBytes, $hFile
Global Const $ERROR_IO_INCOMPLETE = 996 ; Overlapped I/O event is not in a signaled state
Global Const $ERROR_IO_PENDING = 997 ; Overlapped I/O operation is in progress
Global Const $FILE_FLAG_OVERLAPPED = 0x40000000
Global Const $FILE_FLAG_NO_BUFFERING = 0x20000000

$sFile = @AutoItExe

$aDrive = _WinAPI_GetDriveNumber(StringLeft($sFile, 2))
$aGeometry = _WinAPI_GetDriveGeometryEx($aDrive[1])
; 'Bytes per Sector' = $aGeometry[4]
ConsoleWrite(_WinAPI_GetLastErrorMessage() & @TAB & @error & @CRLF)

; FILE_FLAG_NO_BUFFERING
; File access sizes, including the optional file offset in the OVERLAPPED structure, if specified,
; must be for a number of bytes that is an integer multiple of the volume sector size

$iBytesToRead_Total = 16384 ; 16KB per Block / 3 blocks total
$iBytesToRead_Segment_Size = $aGeometry[4]
$iBytesToRead_Segments = $iBytesToRead_Total / $iBytesToRead_Segment_Size

ConsoleWrite("$iBytesToRead_Total " & $iBytesToRead_Total & @CRLF)
ConsoleWrite("$iBytesToRead_Segment_Size " & $iBytesToRead_Segment_Size & @CRLF)
ConsoleWrite("$iBytesToRead_Segments " & $iBytesToRead_Segments & @CRLF)

; The array must contain enough elements to store nNumberOfBytesToRead bytes of data, plus one element for the terminating NULL.
; For example, if there are 40 KB to be read and the page size is 4 KB, the array must have 11 elements that includes 10 for the data and one for the NULL.

Local $tag_FILE_SEGMENT_ELEMENT
Local $t_FILE_SEGMENT_ELEMENT_array[3]
Local $p_FILE_SEGMENT_ELEMENT_array[3]
For $y = 0 To 2
$tag_FILE_SEGMENT_ELEMENT = ""
For $i = 1 To $iBytesToRead_Segments + 1
$tag_FILE_SEGMENT_ELEMENT &= "UINT64;ULONGLONG;"
Next
$t_FILE_SEGMENT_ELEMENT_array[$y] = DllStructCreate($tag_FILE_SEGMENT_ELEMENT)
For $i = 0 To $iBytesToRead_Segments
DllStructSetData($t_FILE_SEGMENT_ELEMENT_array[$y], ($i * 2) + 1, DllStructGetPtr(DllStructCreate("byte[" & $iBytesToRead_Segment_Size & "]", _MemVirtualAlloc(0, $iBytesToRead_Segment_Size, $MEM_COMMIT, $PAGE_READWRITE))))
Next
$p_FILE_SEGMENT_ELEMENT_array[$y] = DllStructGetPtr($t_FILE_SEGMENT_ELEMENT_array[$y])
Next

$iTimer = TimerInit()
$hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, BitOR($FILE_ATTRIBUTE_NORMAL, $FILE_FLAG_OVERLAPPED, $FILE_FLAG_NO_BUFFERING))
$iFileGetSize = _WinAPI_GetFileSizeEx($hFile)
ConsoleWrite(@CRLF & "+ Filesize " & $iFileGetSize & @CRLF & @CRLF)

$iTimer_0 = TimerDiff($iTimer)
; Global Const $tagOVERLAPPED = "int Internal;int InternalHigh;int Offset;int OffsetHigh;int hEvent"
$tOverlapped1 = DllStructCreate($tagOVERLAPPED)
$pOverlapped1 = DllStructGetPtr($tOverlapped1)

ConsoleWrite("_ReadFileScatter #1" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[0], $iBytesToRead_Total, $pOverlapped1) & @CRLF)

Func _ReadFileScatter($hFile, $FILE_SEGMENT_ELEMENT_array, $nNumberOfBytesToRead, $pOverlapped)
; ReadFileScatter
; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365469(v=vs.85).aspx

#cs
BOOL WINAPI ReadFileScatter(
_In_ HANDLE hFile,
_In_ FILE_SEGMENT_ELEMENT aSegmentArray[],
_In_ DWORD nNumberOfBytesToRead,
_Reserved_ LPDWORD lpReserved,
_Inout_ LPOVERLAPPED lpOverlapped
);
#ce

ConsoleWrite("_ReadFileScatter START" & @CRLF)
Local $iRes = DllCall("kernel32.dll", "bool", "ReadFileScatter", "ptr", $hFile, "ptr", $FILE_SEGMENT_ELEMENT_array, "dword", $nNumberOfBytesToRead, "ptr", 0, "ptr", $pOverlapped)
ConsoleWrite("_ReadFileScatter END" & @CRLF)
ConsoleWrite(_WinAPI_GetLastError() & @TAB & _WinAPI_GetLastErrorMessage() & @CRLF)
Return $iRes[0]
EndFunc ;==>_ReadFileScatter

$iTimer_1 = TimerDiff($iTimer)
$sTimer_1 = _WinAPI_GetLastError()
$tOverlapped2 = DllStructCreate($tagOVERLAPPED)
$pOverlapped2 = DllStructGetPtr($tOverlapped2)
$iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped2, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the middle of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped2, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #2" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[1], $iBytesToRead_Total, $pOverlapped2) & @CRLF)

$iTimer_2 = TimerDiff($iTimer)
$sTimer_2 = _WinAPI_GetLastError()
$tOverlapped3 = DllStructCreate($tagOVERLAPPED)
$pOverlapped3 = DllStructGetPtr($tOverlapped3)
$iOffset = $iFileGetSize - $iBytesToRead_Total
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped3, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the end of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped3, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #3" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[2], $iBytesToRead_Total, $pOverlapped3) & @CRLF)

$iTimer_3 = TimerDiff($iTimer)
$sTimer_3 = _WinAPI_GetLastError()
$sRes1 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes1 = $sRes1 & @TAB & $nBytes

$iTimer_4 = TimerDiff($iTimer)
$sTimer_4 = _WinAPI_GetLastError()
$sRes2 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes2 = $sRes2 & @TAB & $nBytes

$iTimer_5 = TimerDiff($iTimer)
$sTimer_5 = _WinAPI_GetLastError()
$sRes3 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes3 = $sRes3 & @TAB & $nBytes

$iTimer_6 = TimerDiff($iTimer)
$sTimer_6 = _WinAPI_GetLastError()
_WinAPI_CloseHandle($hFile)

$iTimer_7 = TimerDiff($iTimer)
$sTimer_7 = _WinAPI_GetLastError()
$sRes4 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes4 = $sRes4 & @TAB & $nBytes
$sRes5 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes5 = $sRes5 & @TAB & $nBytes
$sRes6 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes6 = $sRes6 & @TAB & $nBytes


$iTimer = TimerInit()
$t_ReadFile_Standard = _ReadFile_Standard($sFile, $iFileGetSize)
ConsoleWrite("_WinAPI_CloseHandle - Before " & $sRes1 & @TAB & $sRes2 & @TAB & $sRes3 & @CRLF)
ConsoleWrite("_WinAPI_CloseHandle - After " & $sRes4 & @TAB & $sRes5 & @TAB & $sRes6 & @CRLF & @CRLF)
ConsoleWrite($iTimer_0 & @CRLF & $iTimer_1 & @CRLF & $iTimer_2 & @CRLF & $iTimer_3 & @CRLF & $iTimer_4 & @CRLF & $iTimer_5 & @CRLF & $iTimer_6 & @CRLF & $iTimer_7 & @CRLF & @CRLF & TimerDiff($iTimer) & @CRLF & @CRLF)
ConsoleWrite($sTimer_1 & @CRLF & $sTimer_2 & @CRLF & $sTimer_3 & @CRLF & $sTimer_4 & @CRLF & $sTimer_5 & @CRLF & $sTimer_6 & @CRLF & $sTimer_7 & @CRLF)


MsgBox(0, "", "ReadFileScatter" & @CRLF & StringLeft(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0], 1), 1), 5) & StringRight(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0], 32), 1), 5) & @CRLF _
& StringLeft(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1], 1), 1), 5) & StringRight(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1], 32), 1), 5) & @CRLF _
& StringLeft(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2], 1), 1), 5) & StringRight(DllStructGetData(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2], 32), 1), 5) & @CRLF _
& @CRLF & @CRLF & "ReadFile Standard" & @CRLF _
& StringLeft(DllStructGetData($t_ReadFile_Standard, 1), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 1), 5) & @CRLF _
& StringLeft(DllStructGetData($t_ReadFile_Standard, 2), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 2), 5) & @CRLF _
& StringLeft(DllStructGetData($t_ReadFile_Standard, 3), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 3), 5))

For $y = 0 To 2
For $i = 1 To $iBytesToRead_Segments + 1
ConsoleWrite($y & @TAB & $i & @TAB & _MemVirtualFree(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[$y], $i), 0, $MEM_RELEASE) & @CRLF)
Next
Next


Func _ReadFile_Standard($sFile, $iFileGetSize, $iFlag = 0)
Local $hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, $iFlag), $nBytes
If $hFile = 0 Then Return SetError(4) ;"File was locked and could not be analyzed..."
Local $tBuffer = DllStructCreate("byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "]")
_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), $iBytesToRead_Total, $nBytes)
$iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
_WinAPI_SetFilePointerEx($hFile, $iOffset)
_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 2), $iBytesToRead_Total, $nBytes)
$iOffset = $iFileGetSize - $iBytesToRead_Total
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
_WinAPI_SetFilePointerEx($hFile, $iOffset) ; $iBytesToRead/2 +1
_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 3), $iBytesToRead_Total, $nBytes)
_WinAPI_CloseHandle($hFile)
Return $tBuffer
EndFunc ;==>_ReadFile_Standard

Best Regards

Edited by KaFu
Link to comment
Share on other sites

Well, got it working... but I don't understand why :lol:...

MSDN:

"The array must contain enough elements to store nNumberOfBytesToRead bytes of data, plus one element for the terminating NULL.

For example, if there are 40 KB to be read and the page size is 4 KB, the array must have 11 elements that includes 10 for the data and one for the NULL."

If I would follow this, my file segment count should be something like this:

$iBytesToRead_Segments = $iBytesToRead_Total / $iBytesToRead_Segment_Size + 1

But that does not work and throws and error, strangely this works fine (look at the buffer content in the console)

$iBytesToRead_Segments = $iBytesToRead_Total / $iBytesToRead_Segment_Size * 2

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <Array.au3>
#include <StructureConstants.au3>
#include <Memory.au3>
#include <..\WinAPIEx_3.8_3380\WinAPIEx.au3>

Global $nBytes, $hFile
Global Const $ERROR_IO_INCOMPLETE = 996 ; Overlapped I/O event is not in a signaled state
Global Const $ERROR_IO_PENDING = 997 ; Overlapped I/O operation is in progress

Global Const $FILE_FLAG_NO_BUFFERING = 0x20000000
; FILE_FLAG_NO_BUFFERING
; File access sizes, including the optional file offset in the OVERLAPPED structure, if specified,
; must be for a number of bytes that is an integer multiple of the volume sector size
Global Const $FILE_FLAG_OVERLAPPED = 0x40000000

$sFile = @AutoItExe

$iBytesToRead_Total = 16384 ;  Amount of data to fetch per block in byte, 16KB per Block / 3 blocks total

$aSystemInfo = _WinAPI_GetSystemInfo()
$iBytesToRead_Segment_Size = $aSystemInfo[1] ; The page size and the granularity of page protection and commitment
$iBytesToRead_Segments = Ceiling($iBytesToRead_Total / $iBytesToRead_Segment_Size) * 2 ; * 2 ???? ====> see next line from the documentation, a +1 would have made more sense here
$iBytesToRead_Total = $iBytesToRead_Segments * $iBytesToRead_Segment_Size / 2

; The array must contain enough elements to store nNumberOfBytesToRead bytes of data, plus one element for the terminating NULL.
; For example, if there are 40 KB to be read and the page size is 4 KB, the array must have 11 elements that includes 10 for the data and one for the NULL.

ConsoleWrite("$iBytesToRead_Total " & $iBytesToRead_Total & @CRLF)
ConsoleWrite("$iBytesToRead_Segment_Size " & $iBytesToRead_Segment_Size & @CRLF)
ConsoleWrite("$iBytesToRead_Segments " & $iBytesToRead_Segments & @CRLF)

Local $tag_FILE_SEGMENT_ELEMENT
Local $t_FILE_SEGMENT_ELEMENT_array[3][$iBytesToRead_Segments + 2]
Local $p_FILE_SEGMENT_ELEMENT_array[3][$iBytesToRead_Segments + 2]

For $y = 0 To 2

    $tag_FILE_SEGMENT_ELEMENT = ""
    For $i = 1 To $iBytesToRead_Segments
        $tag_FILE_SEGMENT_ELEMENT &= "ptr;"
    Next
    $t_FILE_SEGMENT_ELEMENT_array[$y][0] = DllStructCreate($tag_FILE_SEGMENT_ELEMENT)
    $p_FILE_SEGMENT_ELEMENT_array[$y][0] = DllStructGetPtr($t_FILE_SEGMENT_ELEMENT_array[$y][0])

    For $i = 1 To $iBytesToRead_Segments
        ; DllStructSetData($t_FILE_SEGMENT_ELEMENT_array[$y], $i, DllStructGetPtr(DllStructCreate("byte[" & $iBytesToRead_Segment_Size & "]", _MemVirtualAlloc(0, $iBytesToRead_Segment_Size, $MEM_COMMIT, $PAGE_READWRITE))))
        $t_FILE_SEGMENT_ELEMENT_array[$y][$i] = DllStructCreate("byte[" & $iBytesToRead_Segment_Size & "]", _MemVirtualAlloc(0, $iBytesToRead_Segment_Size, $MEM_COMMIT, $PAGE_READWRITE))
        $p_FILE_SEGMENT_ELEMENT_array[$y][$i] = DllStructGetPtr($t_FILE_SEGMENT_ELEMENT_array[$y][$i])
        DllStructSetData($t_FILE_SEGMENT_ELEMENT_array[$y][0], $i, $p_FILE_SEGMENT_ELEMENT_array[$y][$i])
    Next

Next

$iTimer = TimerInit()
$hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, BitOR($FILE_ATTRIBUTE_NORMAL, $FILE_FLAG_OVERLAPPED, $FILE_FLAG_NO_BUFFERING))
$iFileGetSize = _WinAPI_GetFileSizeEx($hFile)
ConsoleWrite(@CRLF & "+ Filesize " & $iFileGetSize & @CRLF & @CRLF)

$iTimer_0 = TimerDiff($iTimer)
; Global Const $tagOVERLAPPED = "int Internal;int InternalHigh;int Offset;int OffsetHigh;int hEvent"
$tOverlapped1 = DllStructCreate($tagOVERLAPPED)
$pOverlapped1 = DllStructGetPtr($tOverlapped1)

ConsoleWrite("_ReadFileScatter #1" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[0][0], $iBytesToRead_Total, $pOverlapped1) & @CRLF)

Func _ReadFileScatter($hFile, $FILE_SEGMENT_ELEMENT_array, $nNumberOfBytesToRead, $pOverlapped)
    ; ReadFileScatter
    ; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365469(v=vs.85).aspx

    #cs
        BOOL WINAPI ReadFileScatter(
        _In_        HANDLE hFile,
        _In_        FILE_SEGMENT_ELEMENT aSegmentArray[],
        _In_        DWORD nNumberOfBytesToRead,
        _Reserved_  LPDWORD lpReserved,
        _Inout_     LPOVERLAPPED lpOverlapped
        );
    #ce

    ConsoleWrite("_ReadFileScatter START" & @CRLF)
    Local $iRes = DllCall("kernel32.dll", "bool", "ReadFileScatter", "ptr", $hFile, "ptr", $FILE_SEGMENT_ELEMENT_array, "dword", $nNumberOfBytesToRead, "ptr", 0, "ptr", $pOverlapped)
    ConsoleWrite("_ReadFileScatter END" & @CRLF)
    ConsoleWrite(_WinAPI_GetLastError() & @TAB & _WinAPI_GetLastErrorMessage() & @CRLF)
    Return $iRes[0]
EndFunc   ;==>_ReadFileScatter

$iTimer_1 = TimerDiff($iTimer)
$sTimer_1 = _WinAPI_GetLastError()
$tOverlapped2 = DllStructCreate($tagOVERLAPPED)
$pOverlapped2 = DllStructGetPtr($tOverlapped2)
$iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped2, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the middle of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped2, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #2" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[1][0], $iBytesToRead_Total, $pOverlapped2) & @CRLF)

$iTimer_2 = TimerDiff($iTimer)
$sTimer_2 = _WinAPI_GetLastError()
$tOverlapped3 = DllStructCreate($tagOVERLAPPED)
$pOverlapped3 = DllStructGetPtr($tOverlapped3)
$iOffset = $iFileGetSize - $iBytesToRead_Total
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped3, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the end of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped3, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #3" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[2][0], $iBytesToRead_Total, $pOverlapped3) & @CRLF)

$iTimer_3 = TimerDiff($iTimer)
$sTimer_3 = _WinAPI_GetLastError()
$sRes1 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes1 = $sRes1 & @TAB & $nBytes

$iTimer_4 = TimerDiff($iTimer)
$sTimer_4 = _WinAPI_GetLastError()
$sRes2 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes2 = $sRes2 & @TAB & $nBytes

$iTimer_5 = TimerDiff($iTimer)
$sTimer_5 = _WinAPI_GetLastError()
$sRes3 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes3 = $sRes3 & @TAB & $nBytes

$iTimer_6 = TimerDiff($iTimer)
$sTimer_6 = _WinAPI_GetLastError()
_WinAPI_CloseHandle($hFile)

$iTimer_7 = TimerDiff($iTimer)
$sTimer_7 = _WinAPI_GetLastError()
$sRes4 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes4 = $sRes4 & @TAB & $nBytes
$sRes5 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes5 = $sRes5 & @TAB & $nBytes
$sRes6 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes6 = $sRes6 & @TAB & $nBytes


$iTimer = TimerInit()
$t_ReadFile_Standard = _ReadFile_Standard($sFile, $iFileGetSize)
ConsoleWrite("_WinAPI_CloseHandle - Before " & $sRes1 & @TAB & $sRes2 & @TAB & $sRes3 & @CRLF)
ConsoleWrite("_WinAPI_CloseHandle - After " & $sRes4 & @TAB & $sRes5 & @TAB & $sRes6 & @CRLF & @CRLF)

ConsoleWrite($iTimer_0 & @CRLF & $iTimer_1 & @CRLF & $iTimer_2 & @CRLF & $iTimer_3 & @CRLF & $iTimer_4 & @CRLF & $iTimer_5 & @CRLF & $iTimer_6 & @CRLF & @CRLF & "Total Time for ReadFileScatter: " & @TAB & $iTimer_7 & @CRLF & @CRLF & "Total Time for Standard ReadFile:" & @TAB & TimerDiff($iTimer) & @CRLF)
ConsoleWrite($sTimer_1 & @CRLF & $sTimer_2 & @CRLF & $sTimer_3 & @CRLF & $sTimer_4 & @CRLF & $sTimer_5 & @CRLF & $sTimer_6 & @CRLF & $sTimer_7 & @CRLF)

ConsoleWrite("+ Result" & @CRLF)
ConsoleWrite("============" & @CRLF)
For $i = 1 To $iBytesToRead_Segments
    ConsoleWrite($i & @TAB & DllStructGetSize($t_FILE_SEGMENT_ELEMENT_array[0][$i]) & @TAB & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$i], 1), 100) & @TAB & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$i], 1), 100) & @CRLF)
Next
ConsoleWrite("============" & @CRLF)

MsgBox(0, "", "ReadFileScatter" & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & @CRLF & @CRLF & "ReadFile Standard" & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 1), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 2), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 2), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 3), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 3), 5))

For $y = 0 To 2
    For $i = 1 To $iBytesToRead_Segments
        ConsoleWrite($y & @TAB & $i & @TAB & _MemVirtualFree($p_FILE_SEGMENT_ELEMENT_array[$y][$i], 0, $MEM_RELEASE) & @CRLF)
    Next
Next


Func _ReadFile_Standard($sFile, $iFileGetSize, $iFlag = 0)
    Local $hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, $iFlag), $nBytes
    If $hFile = 0 Then Return SetError(4) ;"File was locked and could not be analyzed..."
    Local $tBuffer = DllStructCreate("byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "]")
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), $iBytesToRead_Total, $nBytes)
    $iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
    $iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
    _WinAPI_SetFilePointerEx($hFile, $iOffset)
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 2), $iBytesToRead_Total, $nBytes)
    $iOffset = $iFileGetSize - $iBytesToRead_Total
    $iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
    _WinAPI_SetFilePointerEx($hFile, $iOffset) ; $iBytesToRead/2 +1
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 3), $iBytesToRead_Total, $nBytes)
    _WinAPI_CloseHandle($hFile)
    Return $tBuffer
EndFunc   ;==>_ReadFile_Standard

Edit: Changed

$iBytesToRead_Segments = $iBytesToRead_Total / $iBytesToRead_Segment_Size * 2

to

$iBytesToRead_Segments = Ceiling($iBytesToRead_Total / $iBytesToRead_Segment_Size) * 2

to handle arbitrary data size.

Edited by KaFu
Link to comment
Share on other sites

  • 3 weeks later...

If ever anybody should be interested in this one :whistle:... here's a corrected version.

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; http://www.autoitscript.com/forum/topic/148253-difficult-question-readfilescatter-file-segment-element-definition/#entry1053298

#include <Array.au3>
#include <StructureConstants.au3>
#include <Memory.au3>
#include <..\WinAPIEx_3.8_3380\WinAPIEx.au3>

Global $nBytes, $hFile
Global Const $ERROR_IO_INCOMPLETE = 996 ; Overlapped I/O event is not in a signaled state
Global Const $ERROR_IO_PENDING = 997 ; Overlapped I/O operation is in progress

Global Const $FILE_FLAG_NO_BUFFERING = 0x20000000
; FILE_FLAG_NO_BUFFERING
; File access sizes, including the optional file offset in the OVERLAPPED structure, if specified,
; must be for a number of bytes that is an integer multiple of the volume sector size
Global Const $FILE_FLAG_OVERLAPPED = 0x40000000

$sFile = @AutoItExe

$iBytesToRead_Total = 16384 ;  Amount of data to fetch per block in byte, 16KB per Block / 3 blocks total

$aSystemInfo = _WinAPI_GetSystemInfo()
$iBytesToRead_Segment_Size = $aSystemInfo[1] ; The page size and the granularity of page protection and commitment
ConsoleWrite($aSystemInfo[1] & @CRLF)
$iBytesToRead_Segments = Ceiling($iBytesToRead_Total / $iBytesToRead_Segment_Size) + 1
; $iBytesToRead_Segments = $iBytesToRead_Total / $iBytesToRead_Segment_Size * 2
$iBytesToRead_Total = $iBytesToRead_Segment_Size * ($iBytesToRead_Segments - 1)

; The array must contain enough elements to store nNumberOfBytesToRead bytes of data, plus one element for the terminating NULL.
; For example, if there are 40 KB to be read and the page size is 4 KB, the array must have 11 elements that includes 10 for the data and one for the NULL.

ConsoleWrite("$iBytesToRead_Total " & $iBytesToRead_Total & @CRLF)
ConsoleWrite("$iBytesToRead_Segment_Size " & $iBytesToRead_Segment_Size & @CRLF)
ConsoleWrite("$iBytesToRead_Segments " & $iBytesToRead_Segments & @CRLF)

Local $tag_FILE_SEGMENT_ELEMENT
Local $t_FILE_SEGMENT_ELEMENT_array[3][$iBytesToRead_Segments + 1]
Local $p_FILE_SEGMENT_ELEMENT_array[3][$iBytesToRead_Segments + 1]

For $y = 0 To 2

    $tag_FILE_SEGMENT_ELEMENT = ""
    For $i = 1 To $iBytesToRead_Segments
        $tag_FILE_SEGMENT_ELEMENT &= "UINT64;"
    Next
    $t_FILE_SEGMENT_ELEMENT_array[$y][0] = DllStructCreate($tag_FILE_SEGMENT_ELEMENT)
    $p_FILE_SEGMENT_ELEMENT_array[$y][0] = DllStructGetPtr($t_FILE_SEGMENT_ELEMENT_array[$y][0])

    For $i = 1 To $iBytesToRead_Segments
        $t_FILE_SEGMENT_ELEMENT_array[$y][$i] = DllStructCreate("byte[" & $iBytesToRead_Segment_Size & "]", _MemVirtualAlloc(0, $iBytesToRead_Segment_Size, $MEM_COMMIT, $PAGE_READWRITE))
        $p_FILE_SEGMENT_ELEMENT_array[$y][$i] = DllStructGetPtr($t_FILE_SEGMENT_ELEMENT_array[$y][$i])
        DllStructSetData($t_FILE_SEGMENT_ELEMENT_array[$y][0], $i, $p_FILE_SEGMENT_ELEMENT_array[$y][$i])
    Next

Next

$iTimer = TimerInit()
$hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, BitOR($FILE_ATTRIBUTE_NORMAL, $FILE_FLAG_OVERLAPPED, $FILE_FLAG_NO_BUFFERING))
$iFileGetSize = _WinAPI_GetFileSizeEx($hFile)
ConsoleWrite(@CRLF & "+ Filesize " & $iFileGetSize & @CRLF & @CRLF)

$iTimer_0 = TimerDiff($iTimer)
; Global Const $tagOVERLAPPED = "int Internal;int InternalHigh;int Offset;int OffsetHigh;int hEvent"
$tOverlapped1 = DllStructCreate($tagOVERLAPPED)
$pOverlapped1 = DllStructGetPtr($tOverlapped1)

ConsoleWrite("_ReadFileScatter #1" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[0][0], $iBytesToRead_Total, $pOverlapped1) & @CRLF)

Func _ReadFileScatter($hFile, $FILE_SEGMENT_ELEMENT_array, $nNumberOfBytesToRead, $pOverlapped)
    ; ReadFileScatter
    ; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365469(v=vs.85).aspx

    #cs
        BOOL WINAPI ReadFileScatter(
        _In_        HANDLE hFile,
        _In_        FILE_SEGMENT_ELEMENT aSegmentArray[],
        _In_        DWORD nNumberOfBytesToRead,
        _Reserved_  LPDWORD lpReserved,
        _Inout_  LPOVERLAPPED lpOverlapped
        );
    #ce

    ConsoleWrite("_ReadFileScatter START" & @CRLF)
    Local $iRes = DllCall("kernel32.dll", "int", "ReadFileScatter", "ptr", $hFile, "ptr", $FILE_SEGMENT_ELEMENT_array, "dword", $nNumberOfBytesToRead, "ptr", 0, "ptr", $pOverlapped)
    ConsoleWrite("_ReadFileScatter END" & @CRLF)
    ConsoleWrite($iRes[0] & @TAB & _WinAPI_GetLastError() & @TAB & _WinAPI_GetLastErrorMessage() & @CRLF)
    Return $iRes[0]
EndFunc   ;==>_ReadFileScatter

$iTimer_1 = TimerDiff($iTimer)
$sTimer_1 = _WinAPI_GetLastError()
$tOverlapped2 = DllStructCreate($tagOVERLAPPED)
$pOverlapped2 = DllStructGetPtr($tOverlapped2)
$iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped2, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the middle of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped2, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #2" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[1][0], $iBytesToRead_Total, $pOverlapped2) & @CRLF)

$iTimer_2 = TimerDiff($iTimer)
$sTimer_2 = _WinAPI_GetLastError()
$tOverlapped3 = DllStructCreate($tagOVERLAPPED)
$pOverlapped3 = DllStructGetPtr($tOverlapped3)
$iOffset = $iFileGetSize - $iBytesToRead_Total
$iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
DllStructSetData($tOverlapped3, "Offset", _WinAPI_LoDWord($iOffset)) ; Setting "Filepointer" to the end of the file (SetFilePointer is not valid for overlapped operations)
DllStructSetData($tOverlapped3, "OffsetHigh", _WinAPI_HiDWord($iOffset))
ConsoleWrite("_ReadFileScatter #3" & @TAB & _ReadFileScatter($hFile, $p_FILE_SEGMENT_ELEMENT_array[2][0], $iBytesToRead_Total, $pOverlapped3) & @CRLF)

$iTimer_3 = TimerDiff($iTimer)
$sTimer_3 = _WinAPI_GetLastError()
$sRes1 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes1 = $sRes1 & @TAB & $nBytes

$iTimer_4 = TimerDiff($iTimer)
$sTimer_4 = _WinAPI_GetLastError()
$sRes2 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes2 = $sRes2 & @TAB & $nBytes

$iTimer_5 = TimerDiff($iTimer)
$sTimer_5 = _WinAPI_GetLastError()
$sRes3 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes3 = $sRes3 & @TAB & $nBytes

$iTimer_6 = TimerDiff($iTimer)
$sTimer_6 = _WinAPI_GetLastError()
_WinAPI_CloseHandle($hFile)

$iTimer_7 = TimerDiff($iTimer)
$sTimer_7 = _WinAPI_GetLastError()
$sRes4 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped1, $nBytes)
$sRes4 = $sRes4 & @TAB & $nBytes
$sRes5 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped2, $nBytes)
$sRes5 = $sRes5 & @TAB & $nBytes
$sRes6 = _WinAPI_GetOverlappedResult($hFile, $pOverlapped3, $nBytes)
$sRes6 = $sRes6 & @TAB & $nBytes


$iTimer = TimerInit()
$t_ReadFile_Standard = _ReadFile_Standard($sFile, $iFileGetSize)
ConsoleWrite("_WinAPI_CloseHandle - Before " & $sRes1 & @TAB & $sRes2 & @TAB & $sRes3 & @CRLF)
ConsoleWrite("_WinAPI_CloseHandle - After " & $sRes4 & @TAB & $sRes5 & @TAB & $sRes6 & @CRLF & @CRLF)

ConsoleWrite($iTimer_0 & @CRLF & $iTimer_1 & @CRLF & $iTimer_2 & @CRLF & $iTimer_3 & @CRLF & $iTimer_4 & @CRLF & $iTimer_5 & @CRLF & $iTimer_6 & @CRLF & @CRLF & "Total Time for ReadFileScatter: " & @TAB & $iTimer_7 & @CRLF & @CRLF & "Total Time for Standard ReadFile:" & @TAB & TimerDiff($iTimer) & @CRLF)
ConsoleWrite($sTimer_1 & @CRLF & $sTimer_2 & @CRLF & $sTimer_3 & @CRLF & $sTimer_4 & @CRLF & $sTimer_5 & @CRLF & $sTimer_6 & @CRLF & $sTimer_7 & @CRLF)

ConsoleWrite("+ Result" & @CRLF)
ConsoleWrite("============" & @CRLF)
For $i = 1 To $iBytesToRead_Segments
    ConsoleWrite($i & @TAB & DllStructGetSize($t_FILE_SEGMENT_ELEMENT_array[0][$i]) & @TAB & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$i], 1), 100) & @TAB & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$i], 1), 100) & @CRLF)
Next
ConsoleWrite("============" & @CRLF)

MsgBox(0, "", "ReadFileScatter" & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[0][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[1][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2][1], 1), 5) & StringRight(DllStructGetData($t_FILE_SEGMENT_ELEMENT_array[2][$iBytesToRead_Segments - 1], 1), 5) & @CRLF _
         & @CRLF & @CRLF & "ReadFile Standard" & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 1), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 1), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 2), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 2), 5) & @CRLF _
         & StringLeft(DllStructGetData($t_ReadFile_Standard, 3), 5) & StringRight(DllStructGetData($t_ReadFile_Standard, 3), 5))

For $y = 0 To 2
    For $i = 1 To $iBytesToRead_Segments
        ConsoleWrite($y & @TAB & $i & @TAB & _MemVirtualFree($p_FILE_SEGMENT_ELEMENT_array[$y][$i], 0, $MEM_RELEASE) & @CRLF)
    Next
Next


Func _ReadFile_Standard($sFile, $iFileGetSize, $iFlag = 0)
    Local $hFile = _WinAPI_CreateFileEx($sFile, 3, $GENERIC_READ, 7, $iFlag), $nBytes
    If $hFile = 0 Then Return SetError(4) ;"File was locked and could not be analyzed..."
    Local $tBuffer = DllStructCreate("byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "];byte[" & $iBytesToRead_Total & "]")
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), $iBytesToRead_Total, $nBytes)
    $iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead_Total / 2 + 1))
    $iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
    _WinAPI_SetFilePointerEx($hFile, $iOffset)
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 2), $iBytesToRead_Total, $nBytes)
    $iOffset = $iFileGetSize - $iBytesToRead_Total
    $iOffset = (Floor($iOffset / $iBytesToRead_Segment_Size)) * $iBytesToRead_Segment_Size
    _WinAPI_SetFilePointerEx($hFile, $iOffset) ; $iBytesToRead/2 +1
    _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 3), $iBytesToRead_Total, $nBytes)
    _WinAPI_CloseHandle($hFile)
    Return $tBuffer
EndFunc   ;==>_ReadFile_Standard
Edited by KaFu
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...