Sign in to follow this  
Followers 0

Feature Request: Asynchronous Operations & Event Handlers

4 posts in this topic

It's been requested in the past to have multithreading to which the response was "It would take too much redesigning of Autoit" but what about Async? Multithreading and Async are two different things. This way we could put tasks in the background without having to fork processes. Right? Also better event handling would be nice rather than throwing everything in a while loop we could have some functionality like javascript which seems to be far more responsive and reliable as the more you add to your while loop the less change there is of your "event" getting caught for some reason (At least in my experience).

Share this post

Link to post
Share on other sites

There is always GuiEventMode.

Any chance you could explain how they are different?

To me, they are by definition, the exact same thing.


The difference is that an async operation happens on the same thread. Lookup Javascript's async (Which is not multithreading) or even better C# async/await vs thread. Also, I think you were referring to OnEvent? OnEvent will help if it does what it says it does and continues executing the program loop while executing the event function. Thanks because I didn't know that existed but yeah, async is generally not the same as what you would consider multithreading and when asked about multithreading I'm sure that's what the Autoit devs are thinking of, not async.

Since there's already this OnEvent for GUI elements it wouldn't be a stretch to add async/await functionality beyond just executing a function when a GUI event happens.

Share this post

Link to post
Share on other sites
Multithreading is different parts of a program running, typcially called threads.
Asynchronous programming uses threads to kick off a piece of code.   So asynchronous programming relies on multithreading to work.

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post

Link to post
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
Sign in to follow this  
Followers 0

  • Similar Content

    • AutID
      By AutID
      I have some nested async methods calling each other and it is confusing. I am trying to convert a project which downloads the files in an async download. On the click of the download button this is the method triggered:
      private async void enableOfflineModeToolStripMenuItem_Click(object sender, EventArgs e) { for(int i = 0; i < _playlists.Count; i++) { DoubleDimList.Add(new List<String>()); for(int j = 0; j < 5; j++) { string sMp3 = IniReadValue(_playlists[i], "Track " + j); DoubleDimList[i].Add(sMp3); } await Task.Run(() => _InetGetHTMLSearchAsyncs(DoubleDimList[i])); } } It creates a 2d List which at the end looks like this DoubleDimList[3][20]. At the end of each sublist I am doing an async download as you can see. The method looks like this
      private async Task _InetGetHTMLSearchAsyncs(List<string> urlList) { foreach (var url in urlList) { await Task.Run(() => _InetGetHTMLSearchAsync(url)); } } the _InetGetHTMLSearchAsync method looks like this and here is where it gets tricky
      private async Task _InetGetHTMLSearchAsync(string sTitle) { Runs++; if (AudioDumpQuery == string.Empty) { //return string.Empty; } string sResearchURL = "" + AudioDumpQuery + sTitle.Replace(" ", "+"); try { using (var client = new WebClient()) { client.Headers.Add("Referer", @""); client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A"); client.DownloadStringCompleted += Client_DownloadStringCompleted; await Task.Run(() => client.DownloadStringAsync(new Uri(sResearchURL))); } } catch (Exception ex) { Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace); Console.WriteLine("Runs: " + Runs); //throw exception return; } } On Client_DownloadStringCompleted there is another async method called. Here it is
      private async void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { string[] sStringArray; string aRet = e.Result; string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline); if (aTable != null) { string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\""); if (aInfos != null) { for (int i = 0; i < 1; i++) { sStringArray = aInfos[i].Split('*'); sStringArray[0] = sStringArray[0].Replace("&#39;", "'"); aLinks.Add(sStringArray[0]); } await Task.Run(() => DownloadFile(aLinks[FilesDownloaded])); } } } From there, surprise! Another async call.
      private async Task DownloadFile(string url) { try { using (var client = new WebClient()) { client.Headers.Add("Referer", @""); client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A"); client.DownloadFileCompleted += Client_DownloadFileCompleted; await Task.Run(() => client.DownloadFileTaskAsync(url, mp3Path + "\\" + count + ".mp3")); } } catch (Exception Ex) { Console.WriteLine("File download error: " + Ex.StackTrace); //throw exception } } Now the first part after the creation of the 2d List is to retrieve the download links of the mp3s. The second part is to download the mp3 as soon as a valid URL was provided. It works but in a bizarre way. Instead of downloading the file normally(1st, 2nd, 3rd...), it will download randomly the files(1st, 5th, 8th...).
      Where am I messing this up because I definitely am!?
    • JakeJohnson74
      By JakeJohnson74
      Hey Guys, this is somewhat related to another post in here but my specific question was "answered" and so I thought I would make a new post that is referencing the same code, with slightly different issues. 
      Problem 1
      Setup: I am using a label docked to the main GUI to set the size of a child GUI. 
      Issue: When I slowly drag the borders, I can see my green label kind of peeking out from behind the GUI, not a huge problem I guess. If I drag the border very quicky I can get the offset to be really big (200-300 pixels)
      ** Edit - I just realized that the child of the child GUI actually does not display this same "lag" or difference in sizing. hmmmm
      Problem 2
      *discaimer! - Melba if you see this, I know you have Aero disabled so I understand if you don't want anything to do with this one! haha
      Setup: Using windows message WM_WINDOWPOSCHANGING. This should give me a message "While" the window is changing. There is a WM_WINDOWPOSCHANGED, which should fire after the change happens. 
      Issue: Upon a normal maximize/restore methods (double clicking title bar, or using the buttons) the window behaves. Upon an Aero Snap maximize/restore the update only happens AFTER I let go of my left click. So while dragging the window down from its maximized state the child GUI's remain maximized until I let go of the left click  mouse button and it resizes. I really want this to resize the second it unsnaps from the maximized state. 
      **Edit - This is due to the way I am handling the flags parameter of the WINDOWPOS Struct. I'm masking only using 1 of the members and it only sees that once the LMB is released. So I am basically misusing the message because im not very familiar with it I have experimented with bitOR(member1, member2, member3) because im thinking SWP_FRAMECHANGED is not the only member I should be masking against "flags" (although it works somewhat)
      Here is my code. 
      #include <GuiConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> $iGuiWidth = 660 $iGUIHeight = 320 $DividerOffset = 244 Global $aGUIPos[6] Global $hgui, $hgui1, $hguiInner1, $cLabel_1, $cLabel_2, $cLabel_3, $iOFfset_X1, $iOFfset_Y1 Global $bSysMsg = False GUI() GUIRegisterMsg($WM_SIZE, "_WM_SIZE") GUIRegisterMsg($WM_WINDOWPOSCHANGING, "_WM_WINDOWPOSCHANGING") Func GUI() $hgui = GUICreate("test", $iGuiWidth, $iGUIHeight, -1, -1, BitOR($WS_OVERLAPPEDWINDOW, $WS_POPUP)) GUISetBkColor(0x666666) $cLabel_1 = GUICtrlCreateLabel("I am the label", 4, 65, $iGuiWidth - 7, 250) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKWIDTH, $GUI_DOCKRIGHT)) GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() $hgui1 = GUICreate("", $iGuiWidth - 7, $iGUIHeight - 70, -1, 60, $WS_POPUP, $WS_EX_MDICHILD, $hgui) GUISetBkColor(0x888888) GUISetState() $Divider = GUICtrlCreateLabel('', $DividerOffset, 0, 5, 250) GUICtrlSetBkColor(-1, 0xFF0000) GUICtrlSetResizing(-1, BitOR($GUI_DOCKWIDTH, $GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM)) GUICtrlSetCursor(-1, 13) GUISetState() $cLabel_2 = GUICtrlCreateLabel("I am the label", 249, 25, 403, 225) GUICtrlSetBkColor(-1, 0x0000FF) GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKWIDTH, $GUI_DOCKRIGHT)) GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() $hGuiInner1 = GUICreate("", 403, 225, 252,28, $WS_POPUP, $WS_EX_MDICHILD, $hgui1) GUISetBkColor(0x555555) GUISetState() _GetGuiPos($hgui,0,1) _GetGuiPos($hgui1,2,3) ;~ _GetGuiPos(hgui2,3,4) For $i = 0 to 5 ConsoleWrite("$aguipos[" & $i & "]:=" & $aguipos[$i] & @LF) Next EndFunc ;==>GUI While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE Quit() EndSwitch If $bSysMsg Then $bSysMsg = False _Resize_GUIs() EndIf WEnd Func Quit() Exit EndFunc ;==>Quit Func _Resize_GUIs() ;GUI1 $aWin1 = WinGetPos($hgui) $aRet1 = ControlGetPos($hgui, "", $cLabel_1) WinMove($hgui1, "", $aWin1[0] + $aGUIPos[0] + $aRet1[0], $aWin1[1] + $aGUIPos[1] + $aRet1[1], $aRet1[2], $aRet1[3]) $aWin2 = WinGetPos($hgui1) $aRet2 = ControlGetPos($hgui1, "", $cLabel_2) WinMove($hguiInner1, "", $aWin2[0] + $aGUIPos[2] + $aRet2[0], $aWin2[1] + $aGUIPos[3] + $aRet2[1], $aRet2[2], $aRet2[3]) ;~ $aWin3 = WinGetPos($hgui) ;~ $aRet3 = ControlGetPos($hgui, "", $cLabel_3) ;~ WinMove($hgui1, "", $aWin3[0] + $aGUIPos[4] + $aRet3[0], $aWin3[1] + $aGUIPos[5] + $aRet3[1], $aRet3[2], $aRet3[3]) EndFunc ;==>_Resize_GUIs func _WM_WINDOWPOSCHANGING($hWnd, $msg, $wParam, $lParam) Local $winpos_Struct = DllStructCreate("hwnd hwnd;hwnd hwndInsertAfter;int x;int y;int cx;int cy;uint flags", $lParam) $MaximizeOrRestore = bitand(DllStructGetData($winpos_Struct, "flags"), $SWP_FRAMECHANGED) if $MaximizeOrRestore > 0 then $bSysMsg = True endif EndFunc Func _WM_SIZE($hWnd, $msg, $wParam, $lParam) _Resize_GUIs() Return $GUI_RUNDEFMSG EndFunc ;==>_WM_SIZE Func _Exit($s_Msg) MsgBox(0, "Error", $s_Msg) Exit EndFunc Func _GetGuiPos($hTargGUI,$iArrayEle1,$iArrayEle2) $aWin = WinGetPos($hTargGUI) Local $tPoint = DllStructCreate("int X;int Y") DllStructSetData($tPoint, "X", 0) DllStructSetData($tPoint, "Y", 0) _WinAPI_ClientToScreen($hTargGUI, $tPoint) $aGUIPos[$iArrayEle1] = DllStructGetData($tPoint, "X") - $aWin[0] $aGUIPos[$iArrayEle2] = DllStructGetData($tPoint, "Y") - $aWin[1] EndFunc
    • lbsl
      By lbsl
      Hi folks,
      I've been happily abusing this forum resources (and many others as well) for over three years now to get stuff done in AutoIT3.
      I'm currently stuck at a point where i need to fake some sort of multithreading.
      I know AutoIT3 does not and will not support it, but if there only was a good way to tap into the full event trapping cycle of the AU3 engine, i could at least add in some of the routines that need a checkup.
      I figured so far that using the GuiOnEventMode and TrayOnEventMode should allow me to give me this opportunity, but unfortunately, it doesn't.
      I have extended the existing Au3 examples for both options with a counter to show what i mean:
      #include <GUIConstantsEx.au3> #include <Constants.au3> #NoTrayIcon Global $x = 1 Example() Func Example() Opt("GUICoordMode", 2) Opt("GUIResizeMode", 1) Opt("GUIOnEventMode", 1) Opt("TrayOnEventMode", 1) Opt("TrayMenuMode", 1) ; Default tray menu items (Script Paused/Exit) will not be shown. TrayCreateItem("Exit") TrayItemSetOnEvent(-1, "ExitEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYDOUBLE, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYDOUBLE, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_MOUSEOVER, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYDOWN, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYUP, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYDOWN, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYUP, "SpecialEvent") TraySetState() Local $WinHandle = GUICreate("Parent1") ConsoleWrite("WinHandle:" & Hex($WinHandle, 8) & @CRLF) GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents") GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents") GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents") GUICtrlCreateButton("OK", 10, 30, 50) GUICtrlSetOnEvent(-1, "OKPressed") GUICtrlCreateButton("Cancel", 0, -1) GUICtrlSetOnEvent(-1, "CancelPressed") GUICtrlCreateEdit("A small text box with some text in it to test the scrollbar clicking" & @CRLF & @CRLF & @CRLF & @CRLF & "and a couple of lines, click and drag the scrollbars to stop the counter", 80, 80, 180, 100) GUICtrlSetOnEvent(-1, "EditTouched") GUISetState(@SW_SHOW) ; Just idle around While 1 Sleep(500) ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 WEnd EndFunc ;==>Example Func EditTouched() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "OK Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>EditTouched Func OKPressed() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "OK Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>OKPressed Func CancelPressed() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Cancel Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>CancelPressed Func SpecialEvents() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 Select Case @GUI_CtrlId = $GUI_EVENT_CLOSE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Close Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) Exit Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Window Minimized", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) Case @GUI_CtrlId = $GUI_EVENT_RESTORE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Window Restored", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) EndSelect EndFunc ;==>SpecialEvents Func SpecialEvent() Select Case @TRAY_ID = $TRAY_EVENT_PRIMARYDOUBLE MsgBox(64, "SpecialEvent-Info", "Primary mouse button double clicked.") Case @TRAY_ID = $TRAY_EVENT_SECONDARYUP MsgBox(64, "SpecialEvent-Info", "Secondary mouse button clicked.") EndSelect EndFunc ;==>SpecialEvent Func ExitEvent() Exit EndFunc ;==>ExitEvent The counter keeps updating the console output, until you hover above a Tray context menu or you click and hold down any of the scrollbars.
      The counter that i am running in the background here is in my real life a network process that needs to clear a message buffer from time to time.
      I have two applications in Autoit3 running, one server that is doing all the network activity and no GUI related stuff at all and i attach a client to it that has to exchange messages with the server to at least be able to command it up to some level.
      However whenever that message buffer of this client stalls, the server that is broadcasting the ACK messages will also stall eventually because his buffers do not get cleared.
      I have considered using an Sqlite database in WAL mode to exchange messages between the two apps and even if that can work mighty fast, it looks clumsy, but it ensures me that my client app will not crash on partial messages or miss out on messages.
      But if anyone can guide me to a trick where i could at least have all functions called in a processing loop without the AutoIT engine being able to stall that process, in other words:how can i keep that counter "running" at all cost?
      Thanks in advance!
    • KaFu
      By KaFu
      HiHo Forum,

      in my program SMF - Search my Files I use a special method to calculate fake (and fast) md5 hashes to identify duplicate files. With the standard settings SMF reads the first 8KB, 8KB from the middle and the last 8KB from a file and calculates a md5 hash on the data. Now I've noticed that the larger the files, the slower the calculation (makes sense ). I assume that's because also the FileSetPointer() operation takes it's time for large files. Calculation drops from somewhere about 300 files / sec to 30 files / sec (of course depending on the filesize and also your machine's power).

      Now I thought about a way to further improve search & hashing speed and stumbled over the possibility for an "Overlapped" (that's Microsoft's term for asynchronous) file access. You request several portions of a file and wait for the results to show up, the ReadFile() function itself returns instantaneously and does not wait for the return buffer to be filled (opposed to the standard behavior where the function only returns when the operation has been finished).

      Currently in SMF I'm requesting the 3 blocks of data and after they've been read I calculate the hash. What I will try out and test is to request all 3 blocks in overlapped mode and start calculating the hash for each block independently (maybe even in a different thread as pointed out by Ward in ) as soon as they pop up. My assumption is that this might improve the performance for large files (> 10MB? I just have to give it a shoot), for smaller files I think the standard operation should be superior.

      As I've not found any example for asynchronous file access on the forum I thought I just post the WIP code for those interested to take a look and help me improve it ... It's just a crude and raw example, but at least it works (on my machines anyhow).

      Yashied's most excellent is required for the example to work.

      #region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseUpx=n #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** ; [url=""][/url] ; [url=""][/url] ; [url=""][/url] #include <StructureConstants.au3> #include <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 $sFile = FileOpenDialog("Select a large file to open for overlapped (asynchronous) reading...", StringLeft(@WindowsDir, 3), "All (*.*)", 3) If @error Then Exit $sFile = StringReplace($sFile, "|", @CRLF) If FileGetSize($sFile) < 1024 * 100 Then MsgBox(0, "", "Larger than 100kb would make sense...") Exit EndIf $aDrive = _WinAPI_GetDriveNumber(StringLeft($sFile, 2)) $aData = _WinAPI_GetDriveGeometryEx_RO($aDrive[1]) ConsoleWrite(_WinAPI_GetLastErrorMessage() & @TAB & @error & @CRLF) ; 'Bytes per Sector: ' & $aData[4] ; 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 = 16 * $aData[4]; ~ 8.192 bytes with 512 bytes per sector ; Because buffer addresses for read and write operations must be sector-aligned, the application must have direct control of how these buffers are allocated. ; One way to sector-align buffers is to use the VirtualAlloc function to allocate the buffers $pBuffer_Mem = _MemVirtualAlloc(0, $iBytesToRead, $MEM_COMMIT, $PAGE_READWRITE) ; $tBuffer = DllStructCreate("byte[" & $iBytesToRead & "];byte[" & $iBytesToRead & "];byte[" & $iBytesToRead & "]") ; $GENERIC_READ = 0x80000000 ; $FILE_ATTRIBUTE_NORMAL = 0x00000080 ; $FILE_FLAG_OVERLAPPED = 0x40000000 ; $FILE_FLAG_NO_BUFFERING = 0x20000000 Global Const $FILE_FLAG_OVERLAPPED = 0x40000000 Global Const $FILE_FLAG_NO_BUFFERING = 0x20000000 $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) _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), $iBytesToRead, $nBytes, $pOverlapped1) $iTimer_1 = TimerDiff($iTimer) $sTimer_1 = _WinAPI_GetLastError() $tOverlapped2 = DllStructCreate($tagOVERLAPPED) $pOverlapped2 = DllStructGetPtr($tOverlapped2) $iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead / 2 + 1)) $iOffset = (Floor($iOffset / $aData[4])) * $aData[4] 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)) _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 2), $iBytesToRead, $nBytes, $pOverlapped2) $iTimer_2 = TimerDiff($iTimer) $sTimer_2 = _WinAPI_GetLastError() $tOverlapped3 = DllStructCreate($tagOVERLAPPED) $pOverlapped3 = DllStructGetPtr($tOverlapped3) $iOffset = $iFileGetSize - $iBytesToRead $iOffset = (Floor($iOffset / $aData[4])) * $aData[4] 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)) _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 3), $iBytesToRead, $nBytes, $pOverlapped3) $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 _MemVirtualFree($pBuffer_Mem, $iBytesToRead, $MEM_DECOMMIT) $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, "", StringLeft(DllStructGetData($tBuffer, 1), 5) & StringRight(DllStructGetData($tBuffer, 1), 5) & @CRLF _ & StringLeft(DllStructGetData($tBuffer, 2), 5) & StringRight(DllStructGetData($tBuffer, 2), 5) & @CRLF _ & StringLeft(DllStructGetData($tBuffer, 3), 5) & StringRight(DllStructGetData($tBuffer, 3), 5) & @CRLF _ & @CRLF & @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)) Func _ReadFile_Standard($sFile, $iFileGetSize, $iFlag = 0) ; Local $hFile = _WinAPI_CreateFile($Checksum_Filename, 2, 2, 7), $Checksum_Result, $nBytes ; FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000 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 & "];byte[" & $iBytesToRead & "];byte[" & $iBytesToRead & "]") _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), $iBytesToRead, $nBytes) $iOffset = Int(($iFileGetSize / 2) - ($iBytesToRead / 2 + 1)) $iOffset = (Floor($iOffset / $aData[4])) * $aData[4] _WinAPI_SetFilePointerEx($hFile, $iOffset) _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 2), $iBytesToRead, $nBytes) $iOffset = $iFileGetSize - $iBytesToRead $iOffset = (Floor($iOffset / $aData[4])) * $aData[4] _WinAPI_SetFilePointerEx($hFile, $iOffset) ; $iBytesToRead/2 +1 _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 3), $iBytesToRead, $nBytes) _WinAPI_CloseHandle($hFile) Return $tBuffer EndFunc ;==>_ReadFile_Standard Func _WinAPI_GetDriveGeometryEx_RO($iDrive) Local $hFile = _WinAPI_CreateFileEx('.PhysicalDrive' & $iDrive, 3, 0, 0x01) If Not $hFile Then Return SetError(1, 0, 0) EndIf Local $tDGEX = DllStructCreate('int64;dword;dword;dword;dword;int64') Local $Ret = DllCall('kernel32.dll', 'int', 'DeviceIoControl', 'ptr', $hFile, 'dword', 0x000700A0, 'ptr', 0, 'dword', 0, 'ptr', DllStructGetPtr($tDGEX), 'dword', DllStructGetSize($tDGEX), 'dword*', 0, 'ptr', 0) If (@error) Or (Not $Ret[0]) Then $Ret = 0 EndIf _WinAPI_CloseHandle($hFile) If Not IsArray($Ret) Then Return SetError(2, 0, 0) EndIf Local $Result[6] For $i = 0 To 5 $Result[$i] = DllStructGetData($tDGEX, $i + 1) Next Return $Result EndFunc ;==>_WinAPI_GetDriveGeometryEx_RO

      Just wanted to point out that this technique only makes sense in very special cases. The default synchronous FileRead utilizes the internal cache manager and for sure is much faster (and easier) to handle than this asynchronous FileRead method and should be the choice for 99.9% of your needs. For some further info take a look at these pages:

      MSDN - ReadFile function
      MSDN - Synchronous and Asynchronous I/O
      MSKB - Asynchronous Disk I/O Appears as Synchronous

      One observation I've made is that it seems like the _WinAPI_CloseHandle($hFile) call is blocking until the operation has been finished. Before that, the progress of the single requests can be monitored using the _WinAPI_GetOverlappedResult() function.

      Best Regards