Ktulu789 Posted January 9, 2008 Share Posted January 9, 2008 (edited) Hello, AutoIt forum, it's been a while!This is my current scenario:Using nLite I made an unattended WinXP SP2 installation which, on first boot (but before having the user profile completely created) runs a script that, after copying some files from the cd to the hard disk calls another script. As for the profile to be fully created and for Windows to finish booting the first called exe must close.The second script makes a lot of adjustments to the system and some of them are made in the current user profile so the script fails if files are missing, or not yet created.For instance, it creates a hot key shortcut for the @ProgramsDir&"Internet explorer.lnk" file.On slow machines this file takes a while to appear and the function FileCreateShortcut fails if the file doesn't exist.I originally made a Sleep(60.000) but I want something better, faster and more reliable because, even with such a long sleep it failed sometimes. And as this is run even before the windows taskbar and systray there is no way to pause it sometimes.My idea is to use WMI and performance monitor looking for the DQ (disk queue) every little while and sleeping(1000) if it is bigger than 0 or 1:$strComputer = "." $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2") $colClass = $objWMIService.ExecQuery("Select * from Win32_PerfRawData_PerfDisk_PhysicalDisk") For $objClass in $colClass MsgBox(0,"","This one: " & $objClass.CurrentDiskQueueLength) Next $objWMIService = "" $colClass = "" $objClass = ""After ten consecutive 0 DQs (or 10 secs of calm sea)... Run, Forest, run!!And my questions are:1. Does anyone know any other way even more reliable than this one?2. If I look for ones on the DQ I wonder if the running script will count as part of the queue. But I don't really think so.3a. As I don't know nothing about anything (and even less about WMI): "Select * from Win32_PerfRawData_PerfDisk_PhysicalDisk"This line looks up every physical disk (or every instance of w32_perf....) on the machine because of the "*". Or am I wrong?Edit: No I was wrong: the "*" stands for every dynamic class (Name, CurrentDiskQueueLenght, DiskBytesPersec, etc) inside the given NameSpace (CIMv2). I got this with trial and error, also I found Scriptomatic 2.0 which helped me enumerate all Dynamic classes in my computer.3b*. How can I change that to only look for the C: or, more properly, the 0 physical drive and not the rest, if any?I tried to change the For ... In but as objects are not common variables........Edit: * Forget about 3b. I will monitor all physical HDs, otherwise I will be forced to use HDs only in the Primary master IDE channel.I will use: $objClass.Name="_Total"Other work around was to If FileExists() Then but there are many files to check.While I wait for your generous help I will start implementing this but by now I'm gonna hit the sack as I used most of today's time to search the internetz. At least today I've got a seemingly good solution with WMI!!There are lots of programs that put a led icon in the systray and if there's any way to get the state of the disk without the "led", say dll, it would be great.I also came upon some SysInternals Apps but I don't know how to get the output into AutoIt.Well, thank you in advance, I'm going to sleep now and I will dream about flashing HDD LEDs. Edited January 11, 2008 by Ktulu789 AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Kerros Posted January 9, 2008 Share Posted January 9, 2008 I've been thinking about this for a bit now, and I don't know if waiting for the DQ to empty would be the best way. There are going to be times when the DQ in empty, but the files that you are looking for still do not exists, so your back to looking to make sure that the files are there with FileExist(). You could do a post install process, by adding an entry into the registry RunOnceEx. that would run after windows in installed, so you shouldn't need to check for the files. Kerros===============================================================How to learn scripting: Figure out enough to be dangerous, then ask for assistance. Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 9, 2008 Author Share Posted January 9, 2008 @Kerros: Thanks for the reply! I thought about that and I'll keep the If FileExists() function as I have it right now (it checks ten files). But the DQ will have to be zero for 10 seconds, for the If FileExists() to be run. Kind of a double check.I think that ten seconds of inactivity are enough and I'll check every 500ms, but maybe I will make it be 15 secs.If I don't misunderstand you the RunOnce will be run the next time I reboot the box.But on fast machines I could forget about the disk queue and even the existence of the target files, with a simple Sleep(15.000) would be more than enough.On slow machines it means waiting for the system to finish loading (manually), rebooting (manually), waiting for shutdown and bootup (manually and longer than everything else ) and praying for it to work anyways!Too many manual steps, wich make it easier to put a MsgBox asking the user to wait for the HDD LED to calm down.Or even put a two minute Sleep wich should be enough for even the crappiest computer. If that's not enough instead of making it boot I would wear boots and start kicking that XTra slow box (Xnail/Turtle).Thank you for the reply!! AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 11, 2008 Author Share Posted January 11, 2008 Well, well, this is what I got so far: HotKeySet("^+q","Quit") Func Quit() MsgBox(0,"Disk idle",TimerDiff($Begin)&" ms");Tell me how much time since last HD activity $objWMIService = "" $colClass = "" $objClass = "" Exit EndFunc Global $Runs,$TimerStarted,$objWMIService = ObjGet("winmgmts:\\.\root\cimv2");removed $strComputer="." which seems to be "localhost" While 1 Sleep(10) $colClass = $objWMIService.ExecQuery("Select * from Win32_PerfRawData_PerfDisk_PhysicalDisk") If IsObj($colClass) Then For $objClass In $colClass;Don't like this If $objClass.Name="_Total" Then $TotalQueue=$objClass.CurrentDiskQueueLength Next Select Case $Runs=320;around 5 secs on my PC Quit() Case $TotalQueue>0 Global $Runs=0,$TimerStarted=0 ToolTip("LED") Case $TotalQueue=0 If $TimerStarted=0 Then $Begin=TimerInit() Global $Runs+=1,$TimerStarted=1 EndSelect Else;This didn't happen yet MsgBox(0,"Error","There was an error with performance monitor, continue when the HDD's LED stops flashing.") EndIf WEnd On my PC it's run three times: First HD, Second HD and _Total. Average PCs have only one disk but still the script will check that twice. So if I want to ExecQuery as much as posible I lose time checking the disks alone when I only need _Total. Any way to skip the For loop to go just after _Total? The sleep has to be around 10 ms or else the processor suffers and remember that this is intended to be run on slow computers which maybe it's Achilles' heel. AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
rover Posted January 11, 2008 Share Posted January 11, 2008 $colClass = $objWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfDisk_PhysicalDisk WHERE Name= '_Total'", "WQL") I see fascists... Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 11, 2008 Author Share Posted January 11, 2008 Monitor HDs "activity" 0.99b:Global $Runs,$TimerStarted,$WMIObj=ObjGet("WinMgmts:\\.\Root\CIMv2") While $Runs<>320;320 around 5 secs on my PC Sleep(10) $colClass=$WMIObj.ExecQuery("Select CurrentDiskQueueLength From Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name='_Total'") If IsObj($colClass) Then For $objClass In $colClass;Any other way to do this? $TotalQueue=$objClass.CurrentDiskQueueLength Next If $TotalQueue=0 Then If $TimerStarted=0 Then Global $Begin=TimerInit(),$TimerStarted=1 $Runs+=1 Else Global $Runs=0,$TimerStarted=0 ToolTip("LED") EndIf Else MsgBox(0,"Error","There was an error with performance monitor, continue when the HDD's LED stops flashing.") ExitLoop() EndIf WEnd Run("TheOtherScript.exe");when the HD is more idle, remember: more $Runs means more checks and less probability of false positives Quit() Func Quit() ConsoleWrite(TimerDiff($Begin)&" ms"&@CRLF);Tell me how much time since last HD activity $WMIObj="" $colClass="" $objClass="" Exit EndFuncoÝ÷ Û÷b½g¥ØZ¶+)ëmÊkZ´×"ËbW(Zv¢ëmáh¬Í{HÂÝz¸¶«z+²+µêðk$ájy,¶h½êâ¶Z(¦Ê'*'qæî¶Ø^Ç¢¶ÇÊÞvéÝj{m¢g¢¯zÚ0®+^¶¢²'5ìm)Þ°çßNbq*&zØb·m«aj^ç]º¸§×¬¶)àz¹¦Z§¶+â·+ay¦è½ë®*m®éì~=ói¬-(ßÛ/z¼¬µæÈ׶'£hÂkíëbì²)ïzË^v)íå!¯&§uû§rب©b·+("Ú(jYh~+ZºÚ"µÍÛØ[ ÌÍÔ[Ë ÌÍÕ[YÝYÚ[H ÌÍÔ[ÉÉÝÌÌÌÌÝ[ HÙXÜÈÛ^HÂÛY L BY ÌÍÕ[YÝYL[ÛØ[ ÌÍÐYÚ[U[Y[] K ÌÍÕ[YÝYLB ÌÍÔ[ÊÏLBÑ[ÛÛÛÛUÜ]J[YY ÌÍÐYÚ[I[É][ÝÈÉ][ÝÉ[ÐÔNÕ[YHÝÈ]XÚ[YHÚ[ÙHÝXÝ]]The weird thing about this is that this last (shorter, SIMPLER) one takes mostly 4984 ms (sometimes it goes to 5000).What the heck??? Partly it's because WMI works with pointers but even considering that this doesn't make sense to me, some computation is done anyway: as if I write ObjGet("WinMgmts:\\.\Root\Ktulu") the operation will fail.Well, if the first little script results useful to you, say hello!!If you know what the heck is going on with the second script, PLEASE REPLY!! AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
rover Posted January 11, 2008 Share Posted January 11, 2008 (edited) was just about to post 'Select CurrentDiskQueueLength' instead of * as for timing from your example: with sleep(10) - 3570.47613593348 ms without sleep anywhere from 50ms to 130ms GUIGetMsg() in place of sleep - 2510.06203302375 ms of course timing varies as others have commented on sleep and timer accuracy on the forum Global $objWMIService = ObjGet("winmgmts:\\.\root\cimv2") Global $oMyError = ObjEvent("AutoIt.Error","COMErrFunc") While 1 Sleep(10) $colClass = $objWMIService.ExecQuery("SELECT CurrentDiskQueueLength FROM Win32_PerfRawData_PerfDisk_PhysicalDisk WHERE Name= '_Total'", "WQL", 48) If IsObj($colClass) Then For $objClass In $colClass $TotalQueue = $objClass.CurrentDiskQueueLength If $TotalQueue Then Beep(1000,5) ConsoleWrite($TotalQueue&@LF) Next EndIf WEnd Func COMErrFunc();COM error handler $HexNumber=hex($oMyError.number,8) Return Msgbox(0,"COM Error Test","We intercepted a COM Error !" & @CRLF & @CRLF & _ "err.description is: " & @TAB & $oMyError.description & @CRLF & _ "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _ "err.number is: " & @TAB & $HexNumber & @CRLF & _ "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _ "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _ "err.source is: " & @TAB & $oMyError.source & @CRLF & _ "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _ "err.helpcontext is: " & @TAB & $oMyError.helpcontext _ ) SetError(1) ; to check for after this function returns Endfunc Edited January 11, 2008 by rover I see fascists... Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 11, 2008 Author Share Posted January 11, 2008 was just about to post 'Select CurrentDiskQueueLength' instead of * Thank you!!The For loop is redundant as the only object in the collection with that line is CurrentDiskQueueLengthtesting with scriptomatic example for 'Win32_PerfRawData_PerfDisk_PhysicalDisk'shows no other content than CurrentDiskQueueLengthBut there is no other way than the For... In...Well done with the geiger counter, although that the Beep() pauses the script you used it as short as possible! as for timing from your example:with sleep(10) - 3570.47613593348 mswithout sleep anywhere from 50ms to 130msGUIGetMsg() in place of sleep - 2510.06203302375 msof course timing varies as others have commentedon sleep and timer accuracy on the forumYour computer is definitively faster than mine (Athlon64 3500, 1Gb 667), so the script loops faster there, that's why IMO you get shorter times.Without Sleep() 130 ms???? No way! It takes 1,2 seconds here.GuiGetMsg() the point for Sleep(10) is not to take much processor time. When not using Sleep() Task manager shows 100% use. GUIGetMsg() instead of sleep... Good idea but remember that this has to work on slow machines too.It's a matter of balance, the longer the sleep() the more the script misses HD activity, the shorter, you need more processor power.The key aspects to me are:Accurate= low level of false positives (will be enforced with more loops, 320 is just for the example)Light= low processor timeFast= not counting the Sleep() but the rest of the script. Seems that it can't get more improvements now.When you comment about timer accuracy... do you refer to Timer init?It starts to make sense, then, the augment of 2 ms on my second simpler script.About the COMErrFunc(): I thought that with If IsObj($colClass) was enough, anyway I didn't saw that "If" fail yet.Adding an icon and changing it with TraySetIcon() your example can be turned into a HD tray LED which is something I will do for fun in the near future . AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 13, 2008 Author Share Posted January 13, 2008 (edited) Error handler: what kind of errors does it handle?All of the following make the script crash:The target computer doesn't exists.ObjGet("winmgmts:\\.\root\cimv") (wrong NameSpace)$colClass = $objWMIService.ExecQuery("SELECT CurrentDiskQueueLengths FROM Win32_PerfRawData_PerfDisk_PhysicalDisk WHERE Name= '_Total'", "WQL", 48) (wrong ClassName)$TotalQueue = $objClass.AvgDiskBytesPerTransfer (Not included in the ExecQuery)The IsObj() after the ExecQuery doesn't work anyway so I will remove that If completely.This is my first script thingie with COM and I don't know how to perform a basic error checking . Any example would be very appreciated! TIA!Edit: This is gonna be more useful when run on slow computers (at startup) and I wish to check, if possible, things like:Did WMI respond?Is WMI functionality loaded yet (working). Edited January 13, 2008 by Ktulu789 AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 13, 2008 Author Share Posted January 13, 2008 Well, I still wonder about some way of error checking (Did WMI respond? Is WMI functionality loaded yet?) but this is the latest look of the function: WaitHDsIdle() Func WaitHDsIdle() Local $Runs,$TimerStarted,$WMIObj=ObjGet("WinMgmts:\\.\Root\CIMv2") While $Runs<1000;320 around 5 secs on my PC Sleep(10) $ObjCollection=$WMIObj.ExecQuery("Select CurrentDiskQueueLength From Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name='_Total'") For $EnumObj In $ObjCollection $TotalQueue=$EnumObj.CurrentDiskQueueLength Next If $TotalQueue=0 Then If $TimerStarted=0 Then $TimerStarted=TimerInit() $Runs+=1 Else Local $Runs=0,$TimerStarted=0 Beep(1000,5) ToolTip("LED") EndIf WEnd Local $EnumObj="",$ObjCollection="",$WMIObj="",$TimerEnd=TimerDiff($TimerStarted)&" ms" Beep(880,250) EndFunc $TimerEnd= ~15600 ms on my PC. AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Ktulu789 Posted January 13, 2008 Author Share Posted January 13, 2008 Tested on a freshly installed XP SP2. As I said before this is intended to run on first system startup after the unattended installation finishes: I got the following error: AutoIt Error Line -1: Error: Variable used without being declared."Line -1" when I saw that, I went This happened on a VMware virtual machine so I took a snapshot and tested a little.I run the compiled script many times in the VM with the same error, once on my computer and it worked alright (it was the same file, damn it).After various minutes after the VM booted up the script started working perfectly.So I think that maybe it's a problem with WMI. Maybe not all WMI functionality is loaded the first time or perhaps the performance monitor is not loaded either.Remarks on "the first time" because I tested the function with my PC rebooting many times and it never failed.Now I really need error checking . AutoIt is a blessing, I don't know how I was able to use my computer before [Auto]It :-S Link to comment Share on other sites More sharing options...
Hagaren76 Posted July 28, 2010 Share Posted July 28, 2010 (edited) Hello, after more than 2 years of using AutoIt and reading this forum, my first post, better late than never So, needed to detect idle time after windows booting up, saw this post, decided to modify code, hope somebody will find it usefull. ps. Yes, it has error checking expandcollapse popupOpt("MustDeclareVars", 1) Global $WHDI_InstallComErrorHandler = True, $WHDI_ComError = False Global $ObjWHDI_ComError ; --------------- This part for testing purposes only. --------------- Global $WHDI_FnResult $WHDI_FnResult = WaitHDDsIdle(5000, 1000) MsgBox(0, "WaitHDDsIdle result:", $WHDI_FnResult & " @error: " & @error) ; -------------------------------------------------------------------- ; Waits $MaxTimeToWaitInMs for all HDDs in machine to be idle for $IdleTimeInMs. ; Minimum value (for both) is 500. ; Returns elapsed time in ms on success. ; On failure, sets @error to: ; 1 - failed to install WaitHDDsIdle_COMErrorHandler, because another function already exists. Returns 0. ; 2 - failed to get WMI object. Returns 0. ; 3 - COM error. Returns hex number of COM error. ; 4 - $MaxTimeToWaitInMs elapsed (HDDs was not idle for $IdleTimeInMs). Returns 0. ; $Precision: value from 1-10, 5 by default. 1 is most precise. 10 is for slower computers (not tested on slower machines, did not detect cpu usage increase, but let it be). ; If $WHDI_InstallComErrorHandler is true, we install error handler to intercept COM error, ; but, this is not mandatory for function to work. If you dont use autoit com error handler function, ; do enable this (it is enabled by default). Func WaitHDDsIdle($MaxTimeToWaitInMs, $IdleTimeInMs, $Precision = 5) Local $PrecisionCounter = 0 Local $MaxTimeStartInMs, $IdleTimeStartInMs, $IdleTimerStarted = False, $DoStartIdleTimer = False Local $WMIObj, $ObjCollection, $EnumObj, $TotalQueue If $Precision < 1 Or $Precision > 10 Then $Precision = 5 If $MaxTimeToWaitInMs < 500 Then $MaxTimeToWaitInMs = 500 If $IdleTimeInMs < 500 Then $IdleTimeInMs = 500 If $WHDI_InstallComErrorHandler Then If Not Install_WaitHDDsIdle_COMErrorHandler() Then SetError(1) Return 0 EndIf EndIf $MaxTimeStartInMs = TimerInit() $WMIObj = ObjGet("WinMgmts:\\.\Root\CIMv2") If @error Then SetError(2) Return 0 EndIf While 1 Sleep(10) $ObjCollection = $WMIObj.ExecQuery("Select CurrentDiskQueueLength From Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name='_Total'") If $WHDI_ComError Then $WHDI_ComError = False SetError(3) Return "0x" & Hex($ObjWHDI_ComError.number, 8) EndIf For $EnumObj In $ObjCollection $TotalQueue = $EnumObj.CurrentDiskQueueLength If $WHDI_ComError Then $WHDI_ComError = False SetError(3) Return "0x" & Hex($ObjWHDI_ComError.number, 8) EndIf Next If $TotalQueue = 0 Then If Not $IdleTimerStarted Then $DoStartIdleTimer = True Else $IdleTimerStarted = False EndIf $PrecisionCounter += 1 If $Precision = $PrecisionCounter Then If $MaxTimeToWaitInMs < TimerDiff($MaxTimeStartInMs) Then SetError(4) Return 0 EndIf If $DoStartIdleTimer Then $IdleTimeStartInMs = TimerInit() $IdleTimerStarted = True $DoStartIdleTimer = False EndIf If $IdleTimerStarted And ($IdleTimeInMs < TimerDiff($IdleTimeStartInMs)) Then ExitLoop $PrecisionCounter = 0 EndIf WEnd ; $IdleTimeInMs reached. $WMIObj = 0 $ObjCollection = 0 $EnumObj = 0 $TotalQueue = 0 $ObjWHDI_ComError = 0 Return TimerDiff($MaxTimeStartInMs) EndFunc ; Internal function. Func WaitHDDsIdle_COMErrorHandler() $WHDI_ComError = True EndFunc ; Internal function. ; Returns 1 if successfully installed error handler, ; or 0 if error handler function already exists. ; From AutoIt help: You can only have ONE Error Event Handler active per AutoIt script. Func Install_WaitHDDsIdle_COMErrorHandler() Local $ErrFuncName = ObjEvent("AutoIt.Error") If $ErrFuncName <> "" Then Return 0 $ObjWHDI_ComError = ObjEvent("AutoIt.Error", "WaitHDDsIdle_COMErrorHandler") Return 1 EndFunc Edited July 29, 2010 by Hagaren76 Link to comment Share on other sites More sharing options...
Ascend4nt Posted July 29, 2010 Share Posted July 29, 2010 Thanks Hagaren76 for adding that function and making me aware of this thread. I've created a PDH version for my Performance Counters UDF here. My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code) Link to comment Share on other sites More sharing options...
Hagaren76 Posted July 29, 2010 Share Posted July 29, 2010 Bug correction: - $ObjWHDI_ComError object with AutoIt COM error handler was not destroyed after exiting function when there was error detected. expandcollapse popupOpt("MustDeclareVars", 1) Global $WHDI_InstallComErrorHandler = True, $WHDI_ComError = False Global $ObjWHDI_ComError ; --------------- This part for testing purposes only. --------------- Global $WHDI_FnResult $WHDI_FnResult = WaitHDDsIdle(120000, 3000) MsgBox(0, "WaitHDDsIdle result:", $WHDI_FnResult & " @error: " & @error) ; -------------------------------------------------------------------- ; Waits $MaxTimeToWaitInMs for all HDDs in machine to be idle for $IdleTimeInMs. ; Minimum value (for both) is 500. ; Returns elapsed time in ms on success. ; On failure, sets @error to: ; 1 - failed to install WaitHDDsIdle_COMErrorHandler, because another function already exists. Returns 0. ; 2 - failed to get WMI object. Returns 0. ; 3 - COM error. Returns hex number of COM error. ; 4 - $MaxTimeToWaitInMs elapsed (HDDs was not idle for $IdleTimeInMs). Returns 0. ; $Precision: value from 1-10, 5 by default. 1 is most precise. 10 is for slower computers (not tested on slower machines, did not detect cpu usage increase, but let it be). ; If $WHDI_InstallComErrorHandler is true, we install error handler to intercept COM error, ; but, this is not mandatory for function to work. If you dont use autoit com error handler function, ; do enable this (it is enabled by default). Func WaitHDDsIdle($MaxTimeToWaitInMs, $IdleTimeInMs, $Precision = 5) Local $PrecisionCounter = 0 Local $MaxTimeStartInMs, $IdleTimeStartInMs, $IdleTimerStarted = False, $DoStartIdleTimer = False Local $WMIObj, $ObjCollection, $EnumObj, $TotalQueue, $ErrStr, $ErrNum = 0 If $Precision < 1 Or $Precision > 10 Then $Precision = 5 If $MaxTimeToWaitInMs < 500 Then $MaxTimeToWaitInMs = 500 If $IdleTimeInMs < 500 Then $IdleTimeInMs = 500 If $WHDI_InstallComErrorHandler Then If Not Install_WaitHDDsIdle_COMErrorHandler() Then SetError(1) Return 0 EndIf EndIf $MaxTimeStartInMs = TimerInit() $WMIObj = ObjGet("WinMgmts:\\.\Root\CIMv2") If @error Then SetError(2) $WHDI_ComError = False $ObjWHDI_ComError = 0 Return 0 EndIf While 1 Sleep(10) $ObjCollection = $WMIObj.ExecQuery("Select CurrentDiskQueueLength From Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name='_Total'") If $WHDI_ComError Then $WHDI_ComError = False $ErrNum = 3 ExitLoop EndIf For $EnumObj In $ObjCollection $TotalQueue = $EnumObj.CurrentDiskQueueLength If $WHDI_ComError Then $WHDI_ComError = False $ErrNum = 3 ExitLoop EndIf Next If $TotalQueue = 0 Then If Not $IdleTimerStarted Then $DoStartIdleTimer = True Else $IdleTimerStarted = False EndIf $PrecisionCounter += 1 If $Precision = $PrecisionCounter Then If $MaxTimeToWaitInMs < TimerDiff($MaxTimeStartInMs) Then $ErrNum = 4 ExitLoop EndIf If $DoStartIdleTimer Then $IdleTimeStartInMs = TimerInit() $IdleTimerStarted = True $DoStartIdleTimer = False EndIf If $IdleTimerStarted And ($IdleTimeInMs < TimerDiff($IdleTimeStartInMs)) Then ExitLoop $PrecisionCounter = 0 EndIf WEnd ; Was there errors in the loop? Switch $ErrNum Case 0 $ObjWHDI_ComError = 0 Return TimerDiff($MaxTimeStartInMs) Case 3 SetError(3) $ErrStr = "0x" & Hex($ObjWHDI_ComError.number, 8) $ObjWHDI_ComError = 0 Return $ErrStr Case 4 SetError(4) $ObjWHDI_ComError = 0 Return 0 EndSwitch EndFunc ; Internal function. Func WaitHDDsIdle_COMErrorHandler() $WHDI_ComError = True EndFunc ; Internal function. ; Returns 1 if successfully installed error handler, ; or 0 if error handler function already exists. ; From AutoIt help: You can only have ONE Error Event Handler active per AutoIt script. Func Install_WaitHDDsIdle_COMErrorHandler() Local $ErrFuncName = ObjEvent("AutoIt.Error") If $ErrFuncName <> "" Then Return 0 $ObjWHDI_ComError = ObjEvent("AutoIt.Error", "WaitHDDsIdle_COMErrorHandler") Return 1 EndFunc Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now