CD-DVD-Wechsel erkennen

  • Hallo!

    Ich möchte gerne ein Script schreiben, dass im Hintergrund läuft und mein CD-Laufwerk überwacht. Sobald eine Änderung ansteht (CDTray öffnen gedrückt, CD-Tray schließen gedrückt) möchte ich das gerne mitgeteilt bekommen. Ist das irgendwie möglich?

    Genial wäre es noch, wenn ich auf den Eject-Knopf meine Laufwerks drücke, erst mein Script weiterabgearbeitet würde und danach das Medium erst ausgeworfen würde.

    Kennt da jemand vielleicht einen Ansatz? Ich wüsste überhaupt nicht, wo ich da anfangen sollte. Wenn ich per DriveGetStatus() oder ähnlichem arbeite, würde ja die ganze Zeit mein Laufwerk laufen. Daher müsste es irgendeine Abfrage eines Events oder so sein.

    Würde mich freuen, wenn ihr mir da weiterhelfen könntet :)

    Grüße,
    Buffo

  • Hehe, das Topic kenne ich doch :D

    Der heißt ja genau wie ich (wink mit dem Zaunpfahl) ;)

    Normalerweise hasse ich auch diese Crosspostings, aber da dort bisher so wenig Feedback oder eben nichts funktionierendes zurückkam, habe ich mir überlegt das Problem hier auch noch zu schildern, da ich dafür möglichst schnell eine Lösung hätte.

    Da ich mich erst heute angemeldet habe, weiß ich leider noch nicht, was für fähige Leute sich hier im Forum aufhalten, ich hoffe, dass es hier auch echte Freaks gibt ;)

    Grüße,
    Buffo

    • Offizieller Beitrag

    Hi,

    kein Problem.

    Reicht dir das so?

    Spoiler anzeigen
    [autoit]

    _checkCD('D:\', True)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(1000)
    If _checkCD('D:\') Then
    ConsoleWrite("Info : Status changed!" & @CRLF)
    _checkCD('D:\', True)
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _checkCD($drive, $start = False)
    Local $returnCode = 0
    If $start Then
    Global $drive_label = DriveGetLabel($drive)
    Global $drive_status = DriveStatus($drive)
    Else
    If $drive_label <> DriveGetLabel($drive) Then $returnCode += 1
    If $drive_status <> DriveStatus($drive) Then $returnCode += 2
    EndIf
    Return $returnCode
    EndFunc ;==>_checkCD

    [/autoit]

    So long,

    Mega

  • Danke für deine Hilfestellung :)

    Doch leider ist das genau das was ich nicht möchte, da ja so bei jeder Anfrage wieder auf das Laufwerk zugegriffen wird.

    Es muss doch irgendwelche Events geben, die man abfragen kann, ohne dass man selber direkt aufs Laufwerk zugreift, um das Anlaufen zu vermeiden.

    Grüße,
    Buffo

    • Offizieller Beitrag

    Hi,

    also bei mir läuft nichts an.

    Spoiler anzeigen
    [autoit]


    _checkCD('D:\', True)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(1000)
    If _checkCD('D:\') Then
    Switch _checkCD('D:\')
    Case 1
    ConsoleWrite("Info : opened!" & @CRLF)
    Case 2
    ConsoleWrite("Info : closed!" & @CRLF)
    Case 3
    ConsoleWrite("Info : CD gewechselt!" & @CRLF)
    EndSwitch
    _checkCD('D:\', True)
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _checkCD($drive, $start = False)
    If $start Then
    Global $drive_label = DriveGetLabel($drive)
    Global $drive_status = DriveStatus($drive)
    Else
    If $drive_status <> DriveStatus($drive) And $drive_status = 'READY' Then Return 1
    If $drive_status <> DriveStatus($drive) And $drive_status = 'NOTREADY' Then Return 2
    If $drive_label <> DriveGetLabel($drive) Then Return 3
    EndIf
    Return 0
    EndFunc ;==>_checkCD

    [/autoit]

    So long,

    Mega

  • Ne, CD-Laufwerk läuft dabei doch nicht an. Es wird doch nur Label und Status abgefragt. Ich hab mal eine etwas andere Variante gebaut:

    Spoiler anzeigen
    [autoit]

    #NoTrayIcon

    [/autoit] [autoit][/autoit] [autoit]

    main()

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItStart()
    Opt("MustDeclareVars", 1)
    EndFunc ;==>OnAutoItStart

    [/autoit] [autoit][/autoit] [autoit]

    Func main()
    Local Const $S_CD = "D:"
    Local $as_cdc = ""
    _CDChanged($S_CD, $as_cdc)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    _CDChanged($S_CD, $as_cdc)
    Switch $as_cdc[0]
    Case 1
    ConsoleWrite($S_CD & " (Tray closed)" & @CR)
    Case 2
    ConsoleWrite($S_CD & " (Tray opened)" & @CR)
    Case 3
    ConsoleWrite($S_CD & " (Label changed)" & @CR)
    EndSwitch
    Sleep(500)
    WEnd
    EndFunc ;==>main

    [/autoit] [autoit][/autoit] [autoit]

    Func _CDChanged(Const $S_PATH, ByRef $as_cdc)
    If IsArray($as_cdc) Then
    ReDim $as_cdc[3]
    $as_cdc[0] = 0

    [/autoit] [autoit][/autoit] [autoit]

    Local $s_tmp = DriveGetLabel($S_PATH)
    If $s_tmp <> $as_cdc[1] Then
    $as_cdc[0] = 3
    $as_cdc[1] = $s_tmp
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $s_tmp = DriveStatus($S_PATH)
    If $s_tmp <> $as_cdc[2] Then
    If $s_tmp = "READY" Then $as_cdc[0] = 1
    If $s_tmp = "NOTREADY" Then $as_cdc[0] = 2
    $as_cdc[2] = $s_tmp
    EndIf
    Else
    Dim $as_cdc[3] = [0, DriveGetLabel($S_PATH), DriveStatus($S_PATH) ]
    EndIf
    EndFunc ;==>_CDChanged

    [/autoit]
  • Wow!

    Ihr seid die geilsten :D

    Ich hatte die Tage mit DriveGetStatus() herumexperimentiert und ich könnte schwören, dass das Laufwerk immer angefangen ist zu laufen. Aber dieses hier funktioniert. Beide Varianten einwandfrei!

    Vielen lieben Dank!

    Grüße,
    Buffo

  • hii

    ja ok macht das was ich gedacht hab. das problem war nur das cd laufwerk. im skript ist es d bei mir e. habe es mal geändert und es hat gefunzt. aber ich habe einen laptop und da läuft das cd laufwerk auf jeden fall mit dem skript an ohne nicht.


    mfg bjoerni

    Einmal editiert, zuletzt von bjoerni (31. Oktober 2007 um 07:00)

  • bjoerni:
    Das Problem hatte ich bei meinen Experimenten ja auch erst. Aber jetzt geht es komischerweise auch ohne. Selbst wenn ich einfach

    Code
    MsgBox(0, "Status", DriveStatus("G:\"))


    nutze, läuft das Laufwerk nicht an, das war vorher aber definitiv der Fall. Vielleicht hilft ja ein Neustart, da irgendwas in Windows nicht korrekt ist?

    @all:
    Ihr kennt nicht zufällig eine Möglichkeit beim Druck auf den Eject-Button den Auswurf "abzufangen" und erst später wieder freizugeben, wenn das gewüsnchte Script durchgelaufen ist? ;)

    Grüße,
    Buffo

    • Offizieller Beitrag

    Hi,

    sowas?

    http://www.autoitscript.com/forum/index.php?act=Search&CODE=show&searchid=410f9bdae1b79a132dff2e2cc9a30468&search_in=posts&result_type=topics&highlite=%2B_DriveInfo

    Spoiler anzeigen
    [autoit]

    Opt("WinTitleMatchMode", 4)

    [/autoit] [autoit][/autoit] [autoit]

    $hwnd = WinGetHandle("classname=Progman")
    $user32 = DllOpen("user32.dll")
    Global Const $lciWM_SYSCommand = 274
    Global Const $lciSC_MonitorPower = 61808
    Global Const $lciPower_Off = 2
    Global Const $lciPower_On = -1

    [/autoit] [autoit][/autoit] [autoit]

    $drive = StringLeft(@ScriptFullPath, 2) & "\"
    $code = _DriveInfo($drive)
    While 1
    While FileExists(@ScriptFullPath)
    Sleep(50)
    WEnd
    ProcessClose("taskmgr.exe")
    $pid = Run("taskmgr.exe", @SystemDir, @SW_HIDE)
    While not ( _DriveInfo($drive) = $code )
    While not FileExists(@ScriptFullPath)
    DllCall($user32, "int", "SendMessage", "hwnd", $hwnd, "int", $lciWM_SYSCommand, "int", $lciSC_MonitorPower, "int", $lciPower_Off)
    BlockInput(1)
    Sleep(20)
    WEnd
    WEnd
    ProcessClose($pid)
    DllCall($user32, "int", "SendMessage", "hwnd", $hwnd, "int", $lciWM_SYSCommand, "int", $lciSC_MonitorPower, "int", $lciPower_On)
    BlockInput(0)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _DriveInfo( $drv )
    Return DriveGetFileSystem($drv)&DriveGetLabel($drv)&DriveGetSerial($drv)&DriveGetType($drv)&DriveSpaceTotal($drv)&DriveStatus($drv)&FileGetSize(@ScriptFullPath)
    EndFunc

    [/autoit]

    So long,

    Mega

  • Xenobiologist :

    Dein Link behält eine Search- oder Session-ID, man kann ihn leider nicht verfolgen.

    Das Script funktioniert bei mir nicht. Habe als Taskmanager ProcessExplorer und Autoeun aus. Hat es eventuell damit was zu tun?

    Was machen die DLLCalls? Kannst du da ein paar Worte drüber verlieren? Würde mich sehr freuen :)

    Grüße,
    Buffo

    • Offizieller Beitrag

    Hallo,

    meinst Du sowas?

    Spoiler anzeigen
    [autoit]

    If @AutoItVersion < "3.2.9.5" Then
    MsgBox(0,"Hinweis", "Es wird mindestens AutoIt Verson 3.2.9.5 benötigt!")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Konstantendefinition
    Global Const $OPEN_EXISTING = 0x00000003
    Global Const $IOCTL_STORAGE_EJECT_MEDIA = 0x002D4808
    Global Const $IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804
    Global Const $FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
    Global Const $GENERIC_WRITE = 0x40000000
    Global Const $GENERIC_READ = 0x80000000
    Global Const $INVALID_HANDLE_VALUE = 0xFFFFFFFF

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagOSVERSIONINFO = _
    "long dwOSVersionInfoSize;" & _
    "long dwMajorVersion;" & _
    "long dwMinorVersion;" & _
    "long dwBuildNumber;" & _
    "long dwPlatformId;" & _
    "char szCSDVersion[128]"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagOVERLAPPED = _
    "long ternal;" & _
    "long ternalHigh;" & _
    "long offset;" & _
    "long offsetHigh;" & _
    "long hEvent"

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $var = DriveGetDrive("CDROM")

    [/autoit] [autoit][/autoit] [autoit]

    If Not @error Then
    For $i = 1 To $var[0]
    LockDrive($var[$i])
    Next

    ConsoleWrite("CDROM-Laufwerk(e) sind gesperrt!" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Sleep(5000)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $var[0]
    LockDrive($var[$i], False)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("CDROM-Laufwerk(e) sind freigegeben!" & @CRLF)
    Endif

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Name: LockDrive
    ; Description: Auswurfknopf am CDROM-Laufwerk sperren
    ; Parameter(s): $szDrive = Laufwerksbuchstabe des CDROM-Laufwerks (z.B. "D:")
    ; (optional) $bLock = True (default) -> sperren
    ; False -> freigeben
    ; Requirement(s): keine
    ; Return Value(s): keine
    ; Author(s): bernd670
    ; Hinweis: Das Laufwerk wird erst wieder freigegeben wenn das Freigeben
    ; genau so oft aufgerufen wird wie das Sperren.
    ;===============================================================================
    Func LockDrive($szDrive, $bLock = True)

    [/autoit] [autoit][/autoit] [autoit]

    Local $lpOutBuffer
    Local $lpInBuffer = DllStructCreate("long Data")
    Local $lpBytesReturned = DllStructCreate("long Data")
    Local $lpOverlapped = DllStructCreate($tagOVERLAPPED)

    DllStructSetData($lpInBuffer, "Data", $bLock)

    [/autoit] [autoit][/autoit] [autoit]

    $hLwStatus = _KNL32_CreateFile("\\.\" & $szDrive, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, 0, $OPEN_EXISTING, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    If $hLwStatus <> $INVALID_HANDLE_VALUE Then
    $iResult = _KNL32_DeviceIoControl( _
    $hLwStatus, _
    $IOCTL_STORAGE_MEDIA_REMOVAL, _
    DllStructGetPtr($lpInBuffer), _
    DllStructGetSize($lpInBuffer), _
    $lpOutBuffer, _
    0, _
    DllStructGetPtr($lpBytesReturned), _
    DllStructGetPtr($lpOverlapped) _
    )

    $iResult = _KNL32_CloseHandle($hLwStatus)
    EndIf
    EndFunc ;==>LockDrive

    [/autoit] [autoit][/autoit] [autoit]

    ; http://msdn2.microsoft.com/en-us/library/aa363858.aspx
    Func _KNL32_CreateFile ($lpFileName, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes, $hTemplateFile)
    Local $aResult = DllCall("kernel32.dll", "long", "CreateFile", _
    "str", $lpFileName, _
    "uint", $dwDesiredAccess, _
    "uint", $dwShareMode, _
    "ptr", $lpSecurityAttributes, _
    "uint", $dwCreationDisposition, _
    "uint", $dwFlagsAndAttributes, _
    "hwnd", $dwFlagsAndAttributes _
    )

    Return $aResult[0]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; http://msdn2.microsoft.com/en-us/library/aa363216.aspx
    Func _KNL32_DeviceIoControl ($hDevice, $dwIoControlCode, $lpInBuffer, $nInBufferSize, $lpOutBuffer, $nOutBufferSize, $lpBytesReturned, $lpOverlapped)
    Local $aResult = DllCall("kernel32.dll", "long", "DeviceIoControl", _
    "hwnd", $hDevice, _
    "uint", $dwIoControlCode, _
    "ptr", $lpInBuffer, _
    "uint", $nInBufferSize, _
    "ptr", $lpOutBuffer, _
    "uint", $nOutBufferSize, _
    "uint*", $lpBytesReturned, _
    "ptr", $lpOverlapped _
    )

    [/autoit] [autoit][/autoit] [autoit]

    Return $aResult[0]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; http://msdn2.microsoft.com/en-us/library/ms724211.aspx
    Func _KNL32_CloseHandle ($hObject)
    Local $aResult = DllCall("kernel32.dll", "long", "CloseHandle", "hwnd", $hObject)

    Return $aResult[0]
    EndFunc

    [/autoit]
  • bernd670 : Danke für das nette Script :)

    Leider ist es nicht ganz das was ich Suche. Die Laufwerke sollen schon geöffnet werden können, nur möchte ich bevor das passiert, noch eine Funktion ausführen.

    Kann auch sein, dass ich etwas übersehe und man das Script dafür auch nutzen kann.

    Wenn dem so ist, könnt ihr mir weiterhelfen?

    Kleines Beispiel:

    CD liegt im Laufwerk, Auswurftaste wird gedrückt, bevor der Vorgang fortgesetzt wird, möchte ich gerne eine MessageBox mit dem Volumenamen angezeigt bekommen und jetzt kann das Medium ausgeworfen werden.

    Ist das irgendwie möglich?

    Grüße,
    Buffo