solzorb Posted July 20, 2008 Share Posted July 20, 2008 Fair warning: I'm new to AutoIt. I've pull code from a couple different places in the forum and put together a piece that HotKey's the Scroll Lock to opening / closing the CD Tray (and automatically closes the tray if left open after five minutes). Thanks to bhoar, bobsobol, and grayfox. Some programs lock the CD for exclusive access (specifically ImgBurn). Unfortunately my code doesn't allow that and I have to close the script to allow the disc to be burned. My question, how can I write the code to relinquish control to a program that wants to lock and then resume the HotKey script once the program is done (I run it as a background exe)? expandcollapse popup#cs ---------------------------------------------------------------------------- AutoIt Version: 3.2.12.1 Author: solzorb (thanks to bhoar, bobsobol, and grayfox) Script Function: Use Scroll Lock key for CD Open/Close with 5-min for auto-close #ce ---------------------------------------------------------------------------- ;----------------------------------------------------- ; Setup Globals Environment ;----------------------------------------------------- Global Const $INVALID_HANDLE_VALUE = 0xFFFFFFFF Global Const $GENERIC_READ = 0x80000000 Global Const $GENERIC_WRITE = 0x40000000 Global Const $FILE_SHARE_READ = 0x00000001 Global Const $FILE_SHARE_WRITE = 0x00000002 Global Const $OPEN_EXISTING = 3 Global Const $IOCTL_SCSI_PASS_THROUGH = 0x0004D004; (0x00000004 << 16) | ((0x0001 | 0x0002) << 14) | (0x0401 << 2) | 0 [from CTL_CODE macro] Global Const $SCSI_IOCTL_DATA_IN = 0x01 Global Const $SCSI_IOCTL_DATA_OUT = 0x00 Global Const $SCSI_IOCTL_DATA_UNSPECIFIED = 0x02 Global Const $SPTCDBSIZE = 0x10; always sixteen, IOCTL_SCSI_PASS_THROUGH requires this - windows checks to make sure the size of $spt = 44. Global Const $REALCDBSIZE = 0x0c; twelve - more compatible than sixteen for ATAPI drives Global Const $SENSEBUFFERSIZE = 0xF0;240 is max (was 32, then 255, which was stupid for byte alignment reasons) Global Const $DATABUFFERSIZE = 0x0400;1024 should handle most calls, except IO, firmware and large changers. Increase? (was 512) Global Const $VK_NUMLOCK = 0x90 Global Const $VK_SCROLL = 0x91 Global Const $VK_CAPITAL = 0x14 Global $cdb Global $spt Global $sptwb ;----------------------------------------------------- ; Main Routine ;----------------------------------------------------- $timer = 0 HotKeySet("{SCROLLLOCK}","ToggleTray") While 1 Sleep(1000) If _GetScrollLock() Then HotKeySet("{SCROLLLOCK}") Send("{SCROLLLOCK off}") HotKeySet("{SCROLLLOCK}","ToggleTray") EndIf If $timer > 0 Then If TimerDiff($timer) >= 300000 Then CreateDLLStructures() $hVolume = OpenVolume(0) If $hVolume <> $INVALID_HANDLE_VALUE Then If IsTrayOpen($hVolume) Then LoadDisc($hVolume) $timer = 0 EndIf EndIf EndIf EndIf WEnd Func ToggleTray() ;Call routine to create structures to use with DLLs CreateDLLStructures() $hVolume = OpenVolume(0) Sleep(95) HotKeySet("{SCROLLLOCK}") Send("{SCROLLLOCK off}") HotKeySet("{SCROLLLOCK}","ToggleTray") If $hVolume <> $INVALID_HANDLE_VALUE Then If IsTrayOpen($hVolume) Then LoadDisc($hVolume) $timer = 0 Else UnLoadDisc($hVolume) $timer = TimerInit() EndIf EndIf EndFunc ;----------------------------------------------------- ; Top-level Function Definitions ;----------------------------------------------------- Func CreateDLLStructures() $CDB_STRUCT = ("ubyte[" & String($SPTCDBSIZE) & "]") $SCSI_PASS_THROUGH = "ushort;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte[3];uint;uint;uint;uint;ubyte[" & String($SPTCDBSIZE) & "]" $SCSI_PASS_THROUGH_WITH_BUFFERS = $SCSI_PASS_THROUGH & ";ubyte[" & String($SENSEBUFFERSIZE) & "];ubyte[" & String($DATABUFFERSIZE) & "]" $cdb = DllStructCreate($CDB_STRUCT) $spt = DllStructCreate($SCSI_PASS_THROUGH);used only for length calculations $sptwb = DllStructCreate($SCSI_PASS_THROUGH_WITH_BUFFERS) EndFunc ;==>CreateDLLStructures Func PopulateCDB_TrayStatus() $CDBCOMMAND = 0xBD;Mechanism Status in hex DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x00, 5) DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x08, 10);Request that the device returns only 08 bytes into our databuffer, which is the defined size of the header We could do more if we had a changer, which would want to give more info, but by setting 8 here, we tell the device not to send more than the header anyway. DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_TrayStatus Func PopulateCDB_LoadDisc() $CDBCOMMAND = 0x1B;Start/Stop Unit DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x03, 5);00000011 = Load Disc and Spin Up DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x00, 10) DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_LoadDisc Func PopulateCDB_UnLoadDisc() $CDBCOMMAND = 0x1B;Start/Stop Unit DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x02, 5);00000010 = Spin Down and UnLoad Disc DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x00, 10) DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_UnLoadDisc Func PopulateSPTWB() $Len_spt = DllStructGetSize($spt) ;Are these necessary if the optical drive is at a drive letter and we pass the handle, right? ;docs seem to suggest that the port driver fills these in if we are using an enumerated device $Bus = 0x00 $ID = 0x00 $Lun = 0x00 DllStructSetData($sptwb, 1, $Len_spt);Length of pre-filler to be set before making call DllStructSetData($sptwb, 2, 0x00);Checked on return from call DllStructSetData($sptwb, 3, $Bus);SCSI bus # - I believe the port driver fills this in DllStructSetData($sptwb, 4, $ID);SCSI ID # - I believe the port driver fills this in DllStructSetData($sptwb, 5, $Lun);SCSI Lun # -I believe the port driver fills this in DllStructSetData($sptwb, 6, $REALCDBSIZE);Length of CDB to be set before making call (12 for ATAPI compatibility)? DllStructSetData($sptwb, 7, $SENSEBUFFERSIZE);Length of Sense buffer to be set before making call - or always 32? DllStructSetData($sptwb, 8, $SCSI_IOCTL_DATA_IN);Flag for Data Transfer direction to be set before making call ;item #9 is simple a placehold for byte alignment, so ignore it DllStructSetData($sptwb, 10, $DATABUFFERSIZE);Length of Data buffer to be set before making call - or always 512 DllStructSetData($sptwb, 11, 0x05);Timeout for call - to be set before making call DllStructSetData($sptwb, 12, $Len_spt + $SENSEBUFFERSIZE);Offset from first byte to beginning of data buffer DllStructSetData($sptwb, 13, $Len_spt);Offset from first byte to beginning of sense buffer For $i = 1 To $SPTCDBSIZE DllStructSetData($sptwb, 14, DllStructGetData($cdb, 1, $i), $i);12 bytes of data representing the CDB Next DllStructSetData($sptwb, 15, 0x00, 1);Sense Buffer - leave alone before call DllStructSetData($sptwb, 16, 0x00, 1);Data Buffer - leave alone before call EndFunc ;==>PopulateSPTWB ;----------------------------------------------------- ; Lower-level Function Definitions ;----------------------------------------------------- Func DoSCSICall(ByRef $hVolume) $returnvalue = DllStructCreate("ptr") ;!!! DeviceIOControl expects ptr;long;ptr;long;ptr;long;ptr;ptr !!! $ret = DllCall( _ "kernel32.dll", "int", _ "DeviceIoControl", _ "hwnd", $hVolume, _ "int", $IOCTL_SCSI_PASS_THROUGH, _ "ptr", DllStructGetPtr($sptwb), _ "int", DllStructGetSize($spt), _ "ptr", DllStructGetPtr($sptwb), _ "int", DllStructGetSize($sptwb), _ "int*", $returnvalue, _ "ptr", 0 _ ) If @error Then MsgBox(1, "EXITING...", "DeviceIoControl DLLCall failed with error level: " & String(@error) & "!") exit (1) EndIf If $ret[0] = 0 Then _GetLastErrorMessage("Error in DeviceIoControl call to IOCTL_SCSI_PASS_THROUGH:") exit (1) EndIf EndFunc ;==>DoSCSICall Func IsTrayOpen(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB, in this case 0xBD PopulateCDB_TrayStatus() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) $second_byte = DllStructGetData($sptwb, 16, 2);should be the second byte ;now we need the bit here 00010000 $traystatus = BitAND($second_byte, 0x10) If $traystatus = 0x10 Then Return (True) Else Return (False) EndIf EndFunc ;==>IsTrayOpen Func LoadDisc(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB PopulateCDB_LoadDisc() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) ;TODO: Analyze sense data to verify this worked. EndFunc ;==>LoadDisc Func UnLoadDisc(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB PopulateCDB_UnLoadDisc() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) ;TODO: Analyze sense data to verify this worked. EndFunc ;==>UnLoadDisc Func OpenVolume($cDriveNumber) ; From AUTOIT forums Local $hVolume, $uDriveType, $szVolumeName, $dwAccessFlags Local $szRootName = "\\.\CdRom" & $cDriveNumber ;We need write access in order to send scsi commands. $dwAccessFlags = BitOR($GENERIC_READ, $GENERIC_WRITE) $szVolumeName = "\\.\CdRom0" ;in addition to getting the handle, the following also verifies write access, which is required to use the scsi pass through $hVolume = DllCall( _ "kernel32.dll", "hwnd", _ "CreateFile", _ "str", $szVolumeName, _ "long", $dwAccessFlags, _ "long", BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), _ "ptr", 0, _ "long", $OPEN_EXISTING, _ "long", 0, _ "long", 0 _ ) If @error Then MsgBox(1, "EXITING...", "CreateFile DLLCall failed!") exit (1) EndIf Return $hVolume[0] EndFunc ;==>OpenVolume ;=============================================== ; _GetLastErrorMessage($DisplayMsgBox="") ; Format the last windows error as a string and return it ; if $DisplayMsgBox <> "" Then it will display a message box w/ the error ; Return Window's error as a string ;=============================================== 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") $LastError = $ret[0] $ret = DllCall("kernel32.dll", "int", "FormatMessage", _ "int", $FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr", 0, _ "int", $LastError, _ "int", 0, _ "ptr", DllStructGetPtr($p), _ "int", 4096, _ "ptr", 0) $s = DllStructGetData($p, 1) If $DisplayMsgBox <> "" Then MsgBox(0, "_GetLastErrorMessage", $DisplayMsgBox & @CRLF & String($LastError) & "-" & $s) Return $s EndFunc ;==>_GetLastErrorMessage Func _GetNumLock() Local $ret $ret = DllCall("user32.dll","long","GetKeyState","long",$VK_NUMLOCK) Return $ret[0] EndFunc Func _GetScrollLock() Local $ret $ret = DllCall("user32.dll","long","GetKeyState","long",$VK_SCROLL) Return $ret[0] EndFunc Link to comment Share on other sites More sharing options...
solzorb Posted August 11, 2008 Author Share Posted August 11, 2008 In case anyone runs across this, I got it figured out a while ago with some more digging. Simple enough but wasn't sure how to do it at the time. CloseVolume($hVolume) Func CloseVolume($hVolume) Local $rVal = DllCall("kernel32.dll", "hwnd", "CloseHandle", "hwnd", $hVolume) If @error Then Return SetError(-1, -1, 0) Return $rVal[0] EndFunc ;==>_CloseVolume Below is the final set of code I'm using, it got tweaked a little more to fix an issue (Scroll Lock didn't always turn off as planned). expandcollapse popup#cs ---------------------------------------------------------------------------- AutoIt Version: 3.2.12.1 Author: solzorb (thanks to bhoar, bobsobol, garyfrost, and grayfox) Script Function: Use Scroll Lock key for CD Open/Close with 5-min for auto-close #ce ---------------------------------------------------------------------------- ;----------------------------------------------------- ; Setup Globals Environment ;----------------------------------------------------- Global Const $INVALID_HANDLE_VALUE = 0xFFFFFFFF Global Const $GENERIC_READ = 0x80000000 Global Const $GENERIC_WRITE = 0x40000000 Global Const $FILE_SHARE_READ = 0x00000001 Global Const $FILE_SHARE_WRITE = 0x00000002 Global Const $OPEN_EXISTING = 3 Global Const $IOCTL_SCSI_PASS_THROUGH = 0x0004D004; (0x00000004 << 16) | ((0x0001 | 0x0002) << 14) | (0x0401 << 2) | 0 [from CTL_CODE macro] Global Const $SCSI_IOCTL_DATA_IN = 0x01 Global Const $SCSI_IOCTL_DATA_OUT = 0x00 Global Const $SCSI_IOCTL_DATA_UNSPECIFIED = 0x02 Global Const $SPTCDBSIZE = 0x10; always sixteen, IOCTL_SCSI_PASS_THROUGH requires this - windows checks to make sure the size of $spt = 44. Global Const $REALCDBSIZE = 0x0c; twelve - more compatible than sixteen for ATAPI drives Global Const $SENSEBUFFERSIZE = 0xF0;240 is max (was 32, then 255, which was stupid for byte alignment reasons) Global Const $DATABUFFERSIZE = 0x0400;1024 should handle most calls, except IO, firmware and large changers. Increase? (was 512) Global Const $VK_NUMLOCK = 0x90 Global Const $VK_SCROLL = 0x91 Global Const $VK_CAPITAL = 0x14 Global $cdb Global $spt Global $sptwb ;----------------------------------------------------- ; Main Routine ;----------------------------------------------------- $timer = 0 HotKeySet("{SCROLLLOCK}","ToggleTray") While 1 If _GetScrollLock() Then HotKeySet("{SCROLLLOCK}") Send("{SCROLLLOCK off}") HotKeySet("{SCROLLLOCK}","ToggleTray") EndIf If $timer > 0 Then If TimerDiff($timer) >= 300000 Then CreateDLLStructures() $hVolume = OpenVolume(0) If $hVolume <> $INVALID_HANDLE_VALUE Then If IsTrayOpen($hVolume) Then LoadDisc($hVolume) $timer = 0 EndIf EndIf CloseVolume($hVolume) EndIf EndIf Sleep(1000) WEnd Func ToggleTray() ;Call routine to create structures to use with DLLs CreateDLLStructures() $hVolume = OpenVolume(0) Sleep(95) If $hVolume <> $INVALID_HANDLE_VALUE Then If IsTrayOpen($hVolume) Then LoadDisc($hVolume) $timer = 0 Else UnLoadDisc($hVolume) $timer = TimerInit() EndIf EndIf CloseVolume($hVolume) EndFunc ;----------------------------------------------------- ; Top-level Function Definitions ;----------------------------------------------------- Func CreateDLLStructures() $CDB_STRUCT = ("ubyte[" & String($SPTCDBSIZE) & "]") $SCSI_PASS_THROUGH = "ushort;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte;ubyte[3];uint;uint;uint;uint;ubyte[" & String($SPTCDBSIZE) & "]" $SCSI_PASS_THROUGH_WITH_BUFFERS = $SCSI_PASS_THROUGH & ";ubyte[" & String($SENSEBUFFERSIZE) & "];ubyte[" & String($DATABUFFERSIZE) & "]" $cdb = DllStructCreate($CDB_STRUCT) $spt = DllStructCreate($SCSI_PASS_THROUGH);used only for length calculations $sptwb = DllStructCreate($SCSI_PASS_THROUGH_WITH_BUFFERS) EndFunc ;==>CreateDLLStructures Func PopulateCDB_TrayStatus() $CDBCOMMAND = 0xBD;Mechanism Status in hex DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x00, 5) DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x08, 10);Request that the device returns only 08 bytes into our databuffer, which is the defined size of the header We could do more if we had a changer, which would want to give more info, but by setting 8 here, we tell the device not to send more than the header anyway. DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_TrayStatus Func PopulateCDB_LoadDisc() $CDBCOMMAND = 0x1B;Start/Stop Unit DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x03, 5);00000011 = Load Disc and Spin Up DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x00, 10) DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_LoadDisc Func PopulateCDB_UnLoadDisc() $CDBCOMMAND = 0x1B;Start/Stop Unit DllStructSetData($cdb, 1, $CDBCOMMAND, 1) DllStructSetData($cdb, 1, 0x00, 2) DllStructSetData($cdb, 1, 0x00, 3) DllStructSetData($cdb, 1, 0x00, 4) DllStructSetData($cdb, 1, 0x02, 5);00000010 = Spin Down and UnLoad Disc DllStructSetData($cdb, 1, 0x00, 6) DllStructSetData($cdb, 1, 0x00, 7) DllStructSetData($cdb, 1, 0x00, 8) DllStructSetData($cdb, 1, 0x00, 9) DllStructSetData($cdb, 1, 0x00, 10) DllStructSetData($cdb, 1, 0x00, 11) DllStructSetData($cdb, 1, 0x00, 12) ;The next four are not used for ATAPI compatibility, but should be set to zero anyway. DllStructSetData($cdb, 1, 0x00, 13) DllStructSetData($cdb, 1, 0x00, 14) DllStructSetData($cdb, 1, 0x00, 15) DllStructSetData($cdb, 1, 0x00, 16) EndFunc ;==>PopulateCDB_UnLoadDisc Func PopulateSPTWB() $Len_spt = DllStructGetSize($spt) ;Are these necessary if the optical drive is at a drive letter and we pass the handle, right? ;docs seem to suggest that the port driver fills these in if we are using an enumerated device $Bus = 0x00 $ID = 0x00 $Lun = 0x00 DllStructSetData($sptwb, 1, $Len_spt);Length of pre-filler to be set before making call DllStructSetData($sptwb, 2, 0x00);Checked on return from call DllStructSetData($sptwb, 3, $Bus);SCSI bus # - I believe the port driver fills this in DllStructSetData($sptwb, 4, $ID);SCSI ID # - I believe the port driver fills this in DllStructSetData($sptwb, 5, $Lun);SCSI Lun # -I believe the port driver fills this in DllStructSetData($sptwb, 6, $REALCDBSIZE);Length of CDB to be set before making call (12 for ATAPI compatibility)? DllStructSetData($sptwb, 7, $SENSEBUFFERSIZE);Length of Sense buffer to be set before making call - or always 32? DllStructSetData($sptwb, 8, $SCSI_IOCTL_DATA_IN);Flag for Data Transfer direction to be set before making call ;item #9 is simple a placehold for byte alignment, so ignore it DllStructSetData($sptwb, 10, $DATABUFFERSIZE);Length of Data buffer to be set before making call - or always 512 DllStructSetData($sptwb, 11, 0x05);Timeout for call - to be set before making call DllStructSetData($sptwb, 12, $Len_spt + $SENSEBUFFERSIZE);Offset from first byte to beginning of data buffer DllStructSetData($sptwb, 13, $Len_spt);Offset from first byte to beginning of sense buffer For $i = 1 To $SPTCDBSIZE DllStructSetData($sptwb, 14, DllStructGetData($cdb, 1, $i), $i);12 bytes of data representing the CDB Next DllStructSetData($sptwb, 15, 0x00, 1);Sense Buffer - leave alone before call DllStructSetData($sptwb, 16, 0x00, 1);Data Buffer - leave alone before call EndFunc ;==>PopulateSPTWB ;----------------------------------------------------- ; Lower-level Function Definitions ;----------------------------------------------------- Func DoSCSICall(ByRef $hVolume) $returnvalue = DllStructCreate("ptr") ;!!! DeviceIOControl expects ptr;long;ptr;long;ptr;long;ptr;ptr !!! $ret = DllCall( _ "kernel32.dll", "int", _ "DeviceIoControl", _ "hwnd", $hVolume, _ "int", $IOCTL_SCSI_PASS_THROUGH, _ "ptr", DllStructGetPtr($sptwb), _ "int", DllStructGetSize($spt), _ "ptr", DllStructGetPtr($sptwb), _ "int", DllStructGetSize($sptwb), _ "int*", $returnvalue, _ "ptr", 0 _ ) If @error Then MsgBox(1, "EXITING...", "DeviceIoControl DLLCall failed with error level: " & String(@error) & "!") exit (1) EndIf If $ret[0] = 0 Then _GetLastErrorMessage("Error in DeviceIoControl call to IOCTL_SCSI_PASS_THROUGH:") exit (1) EndIf EndFunc ;==>DoSCSICall Func IsTrayOpen(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB, in this case 0xBD PopulateCDB_TrayStatus() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) $second_byte = DllStructGetData($sptwb, 16, 2);should be the second byte ;now we need the bit here 00010000 $traystatus = BitAND($second_byte, 0x10) If $traystatus = 0x10 Then Return (True) Else Return (False) EndIf EndFunc ;==>IsTrayOpen Func LoadDisc(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB PopulateCDB_LoadDisc() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) ;TODO: Analyze sense data to verify this worked. EndFunc ;==>LoadDisc Func UnLoadDisc(ByRef $hVolume) ;Call routine to set up the CDB of this SCSI transaction's SRB PopulateCDB_UnLoadDisc() ;Call routine to set up the SCSI_PASS_THROUGH_WITH_BUFFERS stucture - this is general purpose, though the sizes of globals might need to be adjusted for certain SRBs PopulateSPTWB(); to ensure a fresh SRB each time ;Perform the SCSI transaction DoSCSICall($hVolume) ;TODO: Analyze sense data to verify this worked. EndFunc ;==>UnLoadDisc Func OpenVolume($cDriveNumber) ; From AUTOIT forums Local $hVolume, $uDriveType, $szVolumeName, $dwAccessFlags Local $szRootName = "\\.\CdRom" & $cDriveNumber ;We need write access in order to send scsi commands. $dwAccessFlags = BitOR($GENERIC_READ, $GENERIC_WRITE) $szVolumeName = "\\.\CdRom0" ;in addition to getting the handle, the following also verifies write access, which is required to use the scsi pass through $hVolume = DllCall( _ "kernel32.dll", "hwnd", _ "CreateFile", _ "str", $szVolumeName, _ "long", $dwAccessFlags, _ "long", BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), _ "ptr", 0, _ "long", $OPEN_EXISTING, _ "long", 0, _ "long", 0 _ ) If @error Then MsgBox(1, "EXITING...", "CreateFile DLLCall failed!") exit (1) EndIf Return $hVolume[0] EndFunc ;==>OpenVolume Func CloseVolume($hVolume) Local $rVal = DllCall("kernel32.dll", "hwnd", "CloseHandle", "hwnd", $hVolume) If @error Then Return SetError(-1, -1, 0) Return $rVal[0] EndFunc ;==>_CloseVolume ;=============================================== ; _GetLastErrorMessage($DisplayMsgBox="") ; Format the last windows error as a string and return it ; if $DisplayMsgBox <> "" Then it will display a message box w/ the error ; Return Window's error as a string ;=============================================== 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") $LastError = $ret[0] $ret = DllCall("kernel32.dll", "int", "FormatMessage", _ "int", $FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr", 0, _ "int", $LastError, _ "int", 0, _ "ptr", DllStructGetPtr($p), _ "int", 4096, _ "ptr", 0) $s = DllStructGetData($p, 1) If $DisplayMsgBox <> "" Then MsgBox(0, "_GetLastErrorMessage", $DisplayMsgBox & @CRLF & String($LastError) & "-" & $s) Return $s EndFunc ;==>_GetLastErrorMessage Func _GetNumLock() Local $ret $ret = DllCall("user32.dll","long","GetKeyState","long",$VK_NUMLOCK) Return $ret[0] EndFunc Func _GetScrollLock() Local $ret $ret = DllCall("user32.dll","long","GetKeyState","long",$VK_SCROLL) Return $ret[0] 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