Kerros Posted April 15, 2010 Posted April 15, 2010 I have been working on a script to query and change write cache settings on various hard drives, both SATA and SAS, as part of a larger automation suite. The following functions work correctly but if run enough times in a row, sometimes as little as 2, will crash Autoit with a rc -1073741819.It tends to crash sooner if I enclude more functions, even the standard functions such as array.au3. (Note: I'm not saying Array.au3 causes the crash only that by including those functions my script crashes more often.)I based these functions on the information provided on the MSDN IOCTL_DISK_SET_CACHE_INFORMATION Control Code.expandcollapse popup#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #RequireAdmin #include-once ;~ #include<Array.au3> #include<Constants.au3> #include<String.au3> Global Const $Method_Buffered = 0 Global Const $File_Any_Access = 0 Global Const $File_Read_Access = 1 Global Const $File_Write_Access = 2 Global Const $IOCTL_DISK_BASE =0x00000007 Global Const $IOCTL_DISK_GET_CACHE_INFORMATION = '0x' & CTL_CODE($IOCTL_DISK_BASE, 0x0035, $Method_Buffered, $FILE_READ_ACCESS) Global Const $IOCTL_DISK_SET_CACHE_INFORMATION = '0x' & CTL_CODE($IOCTL_DISK_BASE, 0x0036, $Method_Buffered, BitXOR($FILE_READ_ACCESS, $FILE_WRITE_ACCESS)) Global $DriveNum = 1 ;Must be a valid drive number as shown in Disk Management for $icc = 1 to 1000 ConsoleWrite('-------------------------------' & @CR) ConsoleWrite('Loop#:'&$icc&@CRLF) ConsoleWrite('Write Cache: '&_IOCTL_DISK_GET_CACHE_INFORMATION($DriveNum)&@CRLF) _IOCTL_DISK_SET_CACHE_INFORMATION($DriveNum,1) ;1 enables, 0 disables Next Func _IOCTL_DISK_GET_CACHE_INFORMATION($DriveNum) Local $WriteCacheEnabled, $vDrive Local $BlocksPrefetch = DllStructCreate('dword Minimum;dword Maximum;') Local $ScalarPrefetch = DllStructCreate('dword Minimum;dword Maximum;dword MaximumBlocks;', DllStructGetPtr($BlocksPrefetch)) Local $DiskInformation = 'BOOLEAN ParametersSavable; BOOLEAN ReadCacheEnabled; BOOLEAN WriteCacheEnabled; dword ReadRetentionPriority[3];dword WriteRetentionPriority[3]; word DisablePrefetchTransferLength; BOOLEAN PrefetchScaler;' Local $Disk_Cache_Information = DllStructCreate($DiskInformation, DllStructGetPtr($ScalarPrefetch)) If $Disk_Cache_Information = 0 Then ConsoleWrite('Error in Disk_Cache_Information: ' & @error & @CR) Exit EndIf $vDrive = OpenDrive($DriveNum) If $vDrive = 0 Then Exit DllCall("kernel32.dll", "int", _ "DeviceIoControl", _ "ptr", $vDrive, _ "dword", $IOCTL_DISK_GET_CACHE_INFORMATION, _ "ptr", 0, _ "dword", 0, _ "ptr", DllStructGetPtr($Disk_Cache_Information), _ "dword", DllStructGetSize($Disk_Cache_Information), _ "dword*", 0, _ "ptr", 0 _ ) If @error <> 0 Then _GetLastErrorMessage("Error in DeviceIoControl call to IOCTL_DISK_GET_CACHE_INFORMATION:" & String(@error) & "!") SetError(-1,0,-1) return -1 EndIf $WriteCacheEnabled = DllStructGetData($Disk_Cache_Information, "WriteCacheEnabled") CloseDrive($vDrive) $vDrive = 0 $Disk_Cache_Information = 0 $DiskInformation = 0 $ScalarPrefetch = 0 $BlocksPrefetch = 0 Return $WriteCacheEnabled EndFunc ;==>_IOCTL_DISK_GET_CACHE_INFORMATION Func _IOCTL_DISK_SET_CACHE_INFORMATION($DriveNum,$Switch= 1) Local $vDrive Local $BlocksPrefetch = DllStructCreate('dword Minimum;dword Maximum;') Local $ScalarPrefetch = DllStructCreate('dword Minimum;dword Maximum;dword MaximumBlocks;', DllStructGetPtr($BlocksPrefetch)) Local $DiskInformation = 'BOOLEAN ParametersSavable; BOOLEAN ReadCacheEnabled; BOOLEAN WriteCacheEnabled; dword ReadRetentionPriority[3];dword WriteRetentionPriority[3]; word DisablePrefetchTransferLength; BOOLEAN PrefetchScaler;' Local $Disk_Cache_Information = DllStructCreate($DiskInformation, DllStructGetPtr($ScalarPrefetch)) If $Disk_Cache_Information = 0 Then ConsoleWrite('Error in Disk_Cache_Information: ' & @error & @CR) Exit EndIf local $returned = DllStructCreate('int;') DllStructSetData($Disk_Cache_Information,'WriteCacheEnabled',$Switch) If @error <> 0 Then _GetLastErrorMessage("Error in DeviceIoControl call to IOCTL_DISK_GET_CACHE_INFORMATION:" & String(@error) & "!") SetError(-1,0,-1) return -1 EndIf $vDrive = OpenDrive($DriveNum) If $vDrive = 0 Then Exit DllCall("kernel32.dll", "int", _ "DeviceIoControl", _ "ptr", $vDrive, _ "dword", $IOCTL_DISK_SET_CACHE_INFORMATION, _ "ptr", DllStructGetPtr($Disk_Cache_Information), _ "dword", DllStructGetSize($Disk_Cache_Information), _ "ptr", 0, _ "dword", 0, _ "dword*", DllStructGetPtr($returned), _ "ptr", 0 _ ) If @error <> 0 Then _GetLastErrorMessage("Error in DeviceIoControl call to IOCTL_DISK_GET_CACHE_INFORMATION:" & String(@error) & "!") SetError(-1,0,-1) return -1 EndIf CloseDrive($vDrive) $vDrive = 0 $Disk_Cache_Information = 0 $DiskInformation = 0 $ScalarPrefetch = 0 $BlocksPrefetch = 0 EndFunc ;==>_IOCTL_DISK_SET_CACHE_INFORMATION Func CTL_CODE($DeviceType, $Function, $Method, $Access) ;~ Converted to autoit from the MSDN msdn.microsoft.com/en-us/library/ms904001.aspx ;~ #define CTL_CODE(DeviceType, Function, Method, Access) ( ;~ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) ;~ ) Return Hex(BitXOR(BitShift($DeviceType, -16), BitShift($Access, -14), BitShift($Function, -2), $Method)) EndFunc ;==>CTL_CODE Func OpenDrive($driveNum) Local $vDrive ;Get handle to drive $vDrive = DllCall( _ "kernel32.dll", "hwnd", _ "CreateFile", _ "str", "[url="file://\.PhysicalDrive"]\\.\PhysicalDrive[/url]" & String($driveNum), _ "dword", BitOR($GENERIC_READ, $GENERIC_WRITE), _ "dword", BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), _ "ptr", 0, _ "dword", $OPEN_EXISTING, _ "dword", 0, _ "ptr", 0 _ ) If @error <> 0 Then MsgBox(1, "EXITING...", "CreateFile DLLCall failed!") Exit (1) EndIf Return $vDrive[0] EndFunc ;==>OpenDrive Func CloseDrive($vDrive) Local $rVal = DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $vDrive) If @error Then Return SetError(-1, -1, 0) Return $rVal[0] EndFunc ;==>CloseDrive Func _GetLastErrorMessage($DisplayMsgBox = "") Local $ret, $s Local $p = DllStructCreate("char[4096]") Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 If @error Then Return "" $ret = DllCall("Kernel32.dll", "int", "GetLastError") $ret = DllCall("kernel32.dll", "int", "FormatMessage", _ "int", $FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr", 0, _ "int", $ret[0], _ "int", 0, _ "ptr", DllStructGetPtr($p), _ "int", 4096, _ "ptr", 0) $s = DllStructGetData($p, 1) $p = 0 If $DisplayMsgBox <> "" Then MsgBox(0, "_GetLastErrorMessage", $DisplayMsgBox & @CRLF & $s) Return $s EndFunc ;==>_GetLastErrorMessage As these are functions with locally declared variables I would have guessed that the variables would clear after each run, but it seems like something is being retained after the function exits. Can anyone see where I am going wrong with this DllCall? Kerros===============================================================How to learn scripting: Figure out enough to be dangerous, then ask for assistance.
PsaltyDS Posted April 15, 2010 Posted April 15, 2010 This looks wrong already: Func _IOCTL_DISK_GET_CACHE_INFORMATION($DriveNum) Local $WriteCacheEnabled, $vDrive Local $BlocksPrefetch = DllStructCreate('dword Minimum;dword Maximum;') Local $ScalarPrefetch = DllStructCreate('dword Minimum;dword Maximum;dword MaximumBlocks;', DllStructGetPtr($BlocksPrefetch)) ; ... EndFunc ;==>_IOCTL_DISK_GET_CACHE_INFORMATION You create a struct with two DWORDs (with an odd trailing ";" in it), then create another struct on the same address space with three DWORDs? Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
doudou Posted April 15, 2010 Posted April 15, 2010 This looks wrong already: Func _IOCTL_DISK_GET_CACHE_INFORMATION($DriveNum) Local $WriteCacheEnabled, $vDrive Local $BlocksPrefetch = DllStructCreate('dword Minimum;dword Maximum;') Local $ScalarPrefetch = DllStructCreate('dword Minimum;dword Maximum;dword MaximumBlocks;', DllStructGetPtr($BlocksPrefetch)) ; ... EndFunc ;==>_IOCTL_DISK_GET_CACHE_INFORMATION You create a struct with two DWORDs (with an odd trailing ";" in it), then create another struct on the same address space with three DWORDs? It's more than that, in the next line he creates a third struct on the same pointer: Local $Disk_Cache_Information = DllStructCreate($DiskInformation, DllStructGetPtr($ScalarPrefetch)) Somehow it makes no sense... UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ
doudou Posted April 15, 2010 Posted April 15, 2010 It should be actually: Local $DiskInformation = "BOOLEAN ParametersSavable;BOOLEAN ReadCacheEnabled;BOOLEAN WriteCacheEnabled;int ReadRetentionPriority;int WriteRetentionPriority;WORD DisablePrefetchTransferLength;BOOLEAN PrefetchScalar;WORD Minimum;WORD Maximum;WORD MaximumBlocks;" Local $Disk_Cache_Information = DllStructCreate($DiskInformation) UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ
Kerros Posted April 15, 2010 Author Posted April 15, 2010 It should be actually: Local $DiskInformation = "BOOLEAN ParametersSavable;BOOLEAN ReadCacheEnabled;BOOLEAN WriteCacheEnabled;int ReadRetentionPriority;int WriteRetentionPriority;WORD DisablePrefetchTransferLength;BOOLEAN PrefetchScalar;WORD Minimum;WORD Maximum;WORD MaximumBlocks;" Local $Disk_Cache_Information = DllStructCreate($DiskInformation) Thank you, that seems to have fixed the issue. As for why I did the structs that I did, reviewing the MSDN showed an overlapped structure, so I was trying to follow this structure: union { struct { USHORT Minimum; USHORT Maximum; USHORT MaximumBlocks; } ScalarPrefetch; struct { USHORT Minimum; USHORT Maximum; } BlockPrefetch; }; I know my understand of this is very low, but it seems like you are not using an overlapped structure there. Just trying to gain some insite so I don't have this same issue in the future. Kerros===============================================================How to learn scripting: Figure out enough to be dangerous, then ask for assistance.
doudou Posted April 15, 2010 Posted April 15, 2010 (edited) Thank you, that seems to have fixed the issue. As for why I did the structs that I did, reviewing the MSDN showed an overlapped structure, so I was trying to follow this structure: union { struct { USHORT Minimum; USHORT Maximum; USHORT MaximumBlocks; } ScalarPrefetch; struct { USHORT Minimum; USHORT Maximum; } BlockPrefetch; }; I know my understand of this is very low, but it seems like you are not using an overlapped structure there. Just trying to gain some insite so I don't have this same issue in the future. Members of a union are located at the same address and the union itself occupies the amount of memory of the size of the largest member. In this case ScalarPrefetch is the largest of the two, so you take only this in the DllStruct declaration and can then access the substructs accordingly: Local $BlocksPrefetch = DllStructCreate('dword Minimum;dword Maximum;', DllStructGetPtr($Disk_Cache_Information, 'Minimum')) ; or Local $ScalarPrefetch = DllStructCreate('dword Minimum;dword Maximum;dword MaximumBlocks;', DllStructGetPtr($Disk_Cache_Information, 'Minimum')) Edited April 15, 2010 by doudou UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ
Kerros Posted April 15, 2010 Author Posted April 15, 2010 Ok, so what you did was take the larger of the 2 structures and include the elements in the main structure thereby bypassing the need to combine two structures. Thank you for your help and explanation. It makes much more sense now. Kerros Kerros===============================================================How to learn scripting: Figure out enough to be dangerous, then ask for assistance.
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