Jump to content

How to check if cd-tray is open or closed


Recommended Posts

just a idea not a working code:

$DISK = DriveGetDrive("CDROM")
$var = DriveStatus($DISK)
For $I = 1 To $DISK[0]
$STATS = DriveStatus($DISK[$I])
If $STATS = "READY" Then
    MsgBox(4096,"Status",$var)
    Else
    MsgBox(4096,"Status", "Drive not ready")
EndIf

you need to work on it to work properly. i am just giving you idea that how can you do it.

for more help see help file and find and see

DriveGetDrive

DriveStatus

sorry for my spelling mistakes. its due to be fast !!!

Link to comment
Share on other sites

This might be the answer :

If drive is open or empty it returns 0 otherwise -1 in autoit , "True " in delphi & others

$strComputer = "."
$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery( _
    "SELECT * FROM Win32_CDROMDrive")
For $objItem in $colItems
    MsgBox(4096, "","Loaded        "& $objItem.MediaLoaded&@CRLF _
                 &" Drive:            "&$objItem.Drive&@CRLF _
                 &" CD/DVD:       "&$objItem.MediaType)
Next

sorry for my spelling mistakes. its due to be fast !!!

Link to comment
Share on other sites

also try this:

it will work 100% for you.

Purpose - Query optical drive(s) directly via SCSI or SCSI-emulation (ATAPI,USB,Firewire) to find out if their tray/door is open or closed instead of the standard methods which really query whether or not media is loaded (all of the microsoft API calls do)
;TODO - parse returned sense info from 0xBD before assuming data is OK
;TODO - support for non-drive-letter optical drives
;TODO - support for changers (both one LUN and multi-lun ones)

;-----------------------------------------------------
; 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 $FSCTL_LOCK_VOLUME = 0x00090018
;Global Const $FSCTL_UNLOCK_VOLUME = 0x00090022
;Global Const $IOCTL_STORAGE_EJECT_MEDIA = 0x002D0808

Global $cdb
Global $spt
Global $sptwb


;-----------------------------------------------------
; Main Routine
;-----------------------------------------------------


;Call routine to create structures to use with DLLs
CreateDLLStructures()
;Call routine to set up the CDB of this SCSI transaction's SRB, in this case 0xBD - Mechanism Status
PopulateCDB()
;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()

;Call routine to iterate through all of the Optical drives in the system and report on the tray status (now calls PopulateSPTWB again after each run)
ShowTrayInfoForAllOpticals()

Exit (0)


;-----------------------------------------------------
; 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()
    $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, 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

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

Func ShowTrayInfoForAllOpticals()
    $var = DriveGetDrive("cdrom")
   
    If Not @error Then
        MsgBox(4096, "Found 'em!", "Found " & $var[0] & " optical drive(s)!")
        For $j = 1 To $var[0]
            $hVolume = OpenVolume($var[$j])
            If $hVolume = $INVALID_HANDLE_VALUE Then
                MsgBox(4096, $var[$j] & " is not a valid Optical drive", "There was no optical drive at that drive letter, or you do not have high enough access to talk to it directly.")
            Else
                MsgBox(1, "Drive found", "Hey, drive " & $var[$j] & " (" & String($hVolume) & ") is a good optical drive - let's check the tray...")
                If IsTrayOpen($hVolume, $var[$j]) Then
                    MsgBox(1, "Tray Status", "The Tray for drive " & $var[$j] & " is open.")
                Else
                    MsgBox(1, "Tray Status", "The Tray for drive " & $var[$j] & " is closed.")
                EndIf
            EndIf
            PopulateCDB()
            PopulateSPTWB() ; to ensure a fresh SRB each time
            ConsoleWrite("Closed? " & _CloseVolume($hVolume) & @LF)
        Next
    Else
        MsgBox(4096, "No optical drives", "There were no optical drives found in your system")
    EndIf
EndFunc   ;==>ShowTrayInfoForAllOpticals


;-----------------------------------------------------
; Lower-level Function Definitions
;-----------------------------------------------------


Func IsTrayOpen(ByRef $hVolume, $drive)
    $LONG_type = ("ptr")
    $returnvalue = DllStructCreate($LONG_type)
   
    ;!!! 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_ptr", $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
   
    ;check the sense buffer first, otherwise the data buffer is undefined?
    ;guess I should learn how to do that.
   
    ;For $i = 1 To $SENSEBUFFERSIZE
    ;   $temp = DllStructGetData($sptwb, 15, $i)
    ;   If $temp = 0x00 Then
    ;   Else
    ;      MsgBox(1, "Sense Buffer Data Found", "Non zero value found at sense buffer byte [" & $i & "]:  [" & $temp & "]")
    ;   EndIf
    ;Next
   
    ;For $i = 1 To $DATABUFFERSIZE
    ;   $temp = DllStructGetData($sptwb, 16, $i)
    ;   If $temp = 0x00 Then
    ;   Else
    ;      MsgBox(1, "Data Buffer Data Found", "Non zero value found at data buffer byte [" & $i & "]:  [" & $temp & "]")
    ;   EndIf
    ;Next
   
   
    $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)
        ;MsgBox(1, "Tray Status", "The Tray for drive " & $drive & " is open.")
    Else
        Return (False)
        ;MsgBox(1, "Tray Status", "The Tray for drive " & $drive & " is closed.")
    EndIf
   
   
EndFunc   ;==>IsTrayOpen

Func OpenVolume($cDriveLetter)
    ;   From AUTOIT forums
    Local $hVolume, $uDriveType, $szVolumeName, $dwAccessFlags
    If StringLen($cDriveLetter) = 1 Then
        $cDriveLetter = $cDriveLetter & ":"
    ElseIf StringLen($cDriveLetter) = 2 Then
        ;do nothing
    ElseIf StringLen($cDriveLetter) = 3 Then
        $cDriveLetter = StringLeft($cDriveLetter, 2)
    Else
        Return $INVALID_HANDLE_VALUE
    EndIf
   
    Local $szRootName = $cDriveLetter & "\"
   
    $uDriveType = DriveGetType($szRootName)
    Select
        Case $uDriveType == "Removable"
            $dwAccessFlags = BitOR($GENERIC_READ, $GENERIC_WRITE)
        Case $uDriveType == "CDROM"
            ;We need write access in order to send scsi commands.
            $dwAccessFlags = BitOR($GENERIC_READ, $GENERIC_WRITE)
            ;$dwAccessFlags = $GENERIC_READ
        Case Else
            Return $INVALID_HANDLE_VALUE
    EndSelect
   
    $szVolumeName = "\\.\" & $cDriveLetter & ""
    ;$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", "int", "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

maybe you will need to update it but i hope it is the last solution which will work for you.

is it helpful for you?

Edited by FastHelper

sorry for my spelling mistakes. its due to be fast !!!

Link to comment
Share on other sites

It works for all optical drives (SCSI, IDE/ATA/PATA, SATA, Firewire, USB) that I have tested, though success via USB may be limited by the bridge chipset in use at the time.

Here's a snippet you could combine with the above approach for locking/unlocking the drive:

CODE
Func PopulateCDB_LockTray(ByRef $cdb)

$fname = "PopulateCDB_LockTray"

$CDBCOMMAND = 0x1E ;Prevent/Allow Medium Removal

DllStructSetData($cdb, 1, $CDBCOMMAND, 1)

DllStructSetData($cdb, 1, 0x00, 2)

DllStructSetData($cdb, 1, 0x00, 3)

DllStructSetData($cdb, 1, 0x00, 4)

DllStructSetData($cdb, 1, 0x01, 5); Lock = Set bit 0 to 1

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_LockTray

Func PopulateCDB_UnLockTray(ByRef $cdb)

$fname = "PopulateCDB_UnLockTray"

$CDBCOMMAND = 0x1E ;Prevent/Allow Medium Removal

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); Unlock = Set bit 0 to 0

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_UnLockTray

sorry for my spelling mistakes. its due to be fast !!!

Link to comment
Share on other sites

hey...sorry if it doesn't link with the discussion...but I was wondering...how could I select an object in a form by its value?...could this be possible?

I have to do a script on a webpage that doesn't have "names" for the buttons in it...just values...for example in the form named "TZ" I do have a button with no name...but with the value "Next"...how could I select it?....Thanks! :)

Link to comment
Share on other sites

hey...sorry if it doesn't link with the discussion...but I was wondering...how could I select an object in a form by its value?...could this be possible?

I have to do a script on a webpage that doesn't have "names" for the buttons in it...just values...for example in the form named "TZ" I do have a button with no name...but with the value "Next"...how could I select it?....Thanks! :)

@Zozel: If you keep hijacking other people's topics to post unrelated questions, you are going to get yourself banned. It doesn't cost anything to start your own topic.

:)

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
Link to comment
Share on other sites

@Zozel: If you keep hijacking other people's topics to post unrelated questions, you are going to get yourself banned. It doesn't cost anything to start your own topic.

:)

Ok...I'm very sorry if I disturbed anyone... :)
Link to comment
Share on other sites

@FastHelper - It is improper to copy and paste someone elses code. Post links to the original source to give the original author credit and save space in the database.

Original post:

#201790

thanks for the keen eye and the re-link, weaponx. :)

-brendan

Link to comment
Share on other sites

  • 6 months later...

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

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