Sign in to follow this  
Followers 0
Joline

[SOLVED] How to use "RegisterDeviceNotification"

26 posts in this topic

#1 ·  Posted (edited)

I want to use the "RegisterDeviceNotification" function from "user32.dll" to get a notification if a usb device is attempt to remove

(WM_DEVICECHANGE -> $DBT_DEVICEQUERYREMOVE). Can anybody help me to translate the Visual Basic call into a correct AutoIt-call?

Public Type DEV_BROADCAST_DEVICEINTERFACE
  dbcc_size As Long
  dbcc_devicetype As Long
  dbcc_reserved As Long
  dbcc_classguid As GUID
  dbcc_name As Long
End Type

Public Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = &H4
Public Const DEVICE_NOTIFY_WINDOW_HANDLE = 0

Public Const DBT_DEVTYP_DEVICEINTERFACE     As Long = 5

Public Declare Function RegisterDeviceNotification Lib "user32.dll" _
            Alias "RegisterDeviceNotificationA" ( _
            ByVal hRecipient As Long, _
            NotificationFilter As Any, _
            ByVal Flags As Long) As Long
Public Declare Function UnregisterDeviceNotification Lib "user32.dll" _
             (ByVal hRecipient As Long) As Long

Public Function DoRegisterDeviceInterface(hWnd As Long, ByRef hDevNotify As Long) As Boolean
    Dim NotificationFilter As DEV_BROADCAST_DEVICEINTERFACE
        
    NotificationFilter.dbcc_size = Len(NotificationFilter)
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
    
    hDevNotify = RegisterDeviceNotification(hWnd, NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE Or DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
    
    If hDevNotify = 0 Then
        MsgBox "RegisterDeviceNotification failed: " & CStr(Err.LastDllError), vbOKOnly
        DoRegisterDeviceInterface = False
        Exit Function
    End If
    
    DoRegisterDeviceInterface = True
End Function

Dim hDevNotify As Long

Sub Main()
'...
    Call DoRegisterDeviceInterface(Me.hWnd, hDevNotify)
'...
    Call UnregisterDeviceNotification(hDevNotify)
'...
End Sub

I've no idea how to define a type DEV_BROADCAST_DEVICEINTERFACE, how to fill it and how to pass all parameters to the function call. ;)

Dim $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = &H4
Dim $DEVICE_NOTIFY_WINDOW_HANDLE = 0

Dim $DBT_DEVTYP_DEVICEINTERFACE As Long = 5

$hwnd = WinGetHandle(???)  ; How to find my own window handle?
$Flags = $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES + $DEVICE_NOTIFY_WINDOW_HANDLE  ; How to do the boolean operation "OR"?

$hDevNotify = DllCall("user32.dll", "long", "RegisterDeviceNotification", "hwnd", $hwnd, ??? , "long", $Flags) ; How to pass a type/structure?

$result = DllCall("user32.dll", "long", "UnregisterDeviceNotification", "hRecipient", $hDevNotify)

Thank you.

Joline

Edited by Joline

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

I'd imagine that you could do something like this:

#cs
    this is a struct -- I assume
    Public Type DEV_BROADCAST_DEVICEINTERFACE
        dbcc_size As Long
        dbcc_devicetype As Long
        dbcc_reserved As Long
        dbcc_classguid As GUID
        dbcc_name As Long
    End Type
#ce

; now you can store and retrieve data with DllStructSetData and DllStructGetData
DllStructCreate("long dbcc_size; long dbcc_devicetype; long dbcc_reserved; int dbcc_classguid; long dbcc_name")

1) Use DllStructGetPtr()

2) Pass that pointer to a struct when using DllCall()

quick example:

$DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate("long dbcc_size; long dbcc_devicetype; long dbcc_reserved; int dbcc_classguid; long dbcc_name")

$DllPtr = DllStructGetPtr($DEV_BROADCAST_DEVICEINTERFACE)

$hDevNotify = DllCall("user32.dll", "long", "RegisterDeviceNotification", "hwnd", $hwnd, $DllPtr , "long", $Flags)
Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

Thanks for your answer. This is my code now:

#include <GUIConstantsEx.au3>

Global $aDrives = DriveGetDrive('ALL')

Global Const $WM_DEVICECHANGE = 0x0219

GUICreate('USB-Handler')
GUIRegisterMsg($WM_DEVICECHANGE, 'MY_WM_DEVICECHANGE')

;ToDo -> RegisterDeviceNotification 
Global Const $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004
Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000

Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

$hWnd = WinGetHandle('USB-Handler')
ConsoleWrite("$hWnd: " & $hWnd & @CR)

$DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate("long dbcc_size; long dbcc_devicetype; long dbcc_reserved; int dbcc_classguid; long dbcc_name")
$DllPtr = DllStructGetPtr($DEV_BROADCAST_DEVICEINTERFACE)
ConsoleWrite("$DllPtr: " & $DllPtr & @CR)

$Flags = $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES + $DEVICE_NOTIFY_WINDOW_HANDLE  ; How to do the boolean operation "OR"?
ConsoleWrite("$Flags: " & $Flags & @CR)

$hDevNotify = DllCall("user32.dll", "long", "RegisterDeviceNotification", "hwnd", $hWnd, $DllPtr , "long", $Flags)
ConsoleWrite("$hDevNotify: " & $hDevNotify & @CR)
 
While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    ;ToDo ...
EndFunc   ;==>MY_WM_DEVICECHANGE

But unfortunately the return code of the DllCall "RegisterDeviceNotification" is 0.

$hWnd: 0x008109E6
$DllPtr: 0x00CD69A0
$Flags: 4
$hDevNotify: 0

How can I find out what is wrong?

Best regards

Joline

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

OK, I think I made some progress here. Please run this and tell me if it returns anything useful.

#include <Array.au3>

Global $aDrives = DriveGetDrive("ALL")

Global $hWnd = GUICreate("USB-Handler")
Global Const $WM_DEVICECHANGE = 0x0219
GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
;ToDo -> RegisterDeviceNotification

Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000
Global Const $DEVICE_NOTIFY_SERVICE_HANDLE = 0x00000001
Global Const $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004
Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

Global Const $Flags = BitOR($DEVICE_NOTIFY_ALL_INTERFACE_CLASSES, $DEVICE_NOTIFY_WINDOW_HANDLE)

Global $DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate("dword dbcc_size; dword dbcc_devicetype; dword dbcc_reserved; char dbcc_classguid[128]; char dbcc_name[1]")
;~ ConsoleWrite("$DEV_BROADCAST_DEVICEINTERFACE @ERROR: " & @error & @CR)
DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size", DllStructGetSize($DEV_BROADCAST_DEVICEINTERFACE))
DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype", $DBT_DEVTYP_DEVICEINTERFACE)
Global $PtrDEV_BROADCAST_DEVICEINTERFACE = DllStructGetPtr($DEV_BROADCAST_DEVICEINTERFACE)

Global $hDevNotify = DllCall("user32.dll", "handle", "RegisterDeviceNotification", "handle", $hWnd, "ptr", $PtrDEV_BROADCAST_DEVICEINTERFACE, "dword", $Flags)

ConsoleWrite("USB-Handler hwnd: " & $hWnd & @CR)
ConsoleWrite("$PtrDEV_BROADCAST_DEVICEINTERFACE: " & $PtrDEV_BROADCAST_DEVICEINTERFACE & @CR)
ConsoleWrite("$Flags: " & $Flags & @CR)
ConsoleWrite("$hDevNotify: " & $hDevNotify[0] & @CR)
_ArrayDisplay($hDevNotify)

While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    ;ToDo ...
    ConsoleWrite("Something" & @CR)
EndFunc ;==>MY_WM_DEVICECHANGE

Oh and when you run the script, insert or disconnect a usb device.

Edited by jaberwocky6669
1 person likes this

Share this post


Link to post
Share on other sites

Oh, the $hDevNotify has a value now. Great. But unfortunately it doesn't work as expected. ;)

#include <Array.au3>

Global $aDrives = DriveGetDrive("ALL")

Global $hWnd = GUICreate("USB-Handler")
Global Const $WM_DEVICECHANGE = 0x0219
GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
;ToDo -> RegisterDeviceNotification

Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000
Global Const $DEVICE_NOTIFY_SERVICE_HANDLE = 0x00000001
Global Const $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004
Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

Global Const $Flags = BitOR($DEVICE_NOTIFY_ALL_INTERFACE_CLASSES, $DEVICE_NOTIFY_WINDOW_HANDLE)

Global $DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate("dword dbcc_size; dword dbcc_devicetype; dword dbcc_reserved; char dbcc_classguid[128]; char dbcc_name[1]")
;~ ConsoleWrite("$DEV_BROADCAST_DEVICEINTERFACE @ERROR: " & @error & @CR)
DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size", DllStructGetSize($DEV_BROADCAST_DEVICEINTERFACE))
DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype", $DBT_DEVTYP_DEVICEINTERFACE)
Global $PtrDEV_BROADCAST_DEVICEINTERFACE = DllStructGetPtr($DEV_BROADCAST_DEVICEINTERFACE)

Global $hDevNotify = DllCall("user32.dll", "handle", "RegisterDeviceNotification", "handle", $hWnd, "ptr", $PtrDEV_BROADCAST_DEVICEINTERFACE, "dword", $Flags)

ConsoleWrite("USB-Handler hwnd: " & $hWnd & @CR)
ConsoleWrite("$PtrDEV_BROADCAST_DEVICEINTERFACE: " & $PtrDEV_BROADCAST_DEVICEINTERFACE & @CR)
ConsoleWrite("$Flags: " & $Flags & @CR)
ConsoleWrite("$hDevNotify: " & $hDevNotify[0] & @CR)
_ArrayDisplay($hDevNotify)

While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    ;ToDo ...
    Local Const $DBT_DEVICEARRIVAL = 0x8000 ; A device or piece of media has been inserted and is now available.
    Local Const $DBT_DEVICEQUERYREMOVE = 0x8001 ; A device or piece of media is attemped to remove.
    Local Const $DBT_DEVICEREMOVECOMPLETE = 0x8004 ; A device or piece of media has been removed.
    ConsoleWrite("$wParam: " & $wParam & @CR)
EndFunc ;==>MY_WM_DEVICECHANGE

I get notifications for DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE but not for DBT_DEVICEQUERYREMOVE. This is the same behaviour as without "RegisterDeviceNotification". So I think RegisterDeviceNotification doesn't work properly.

Applications can use the RegisterDeviceNotification function to register to receive device notifications. DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE will get EVERY application even without RegisterDeviceNotification. If the application is registered and the DBT_DEVICEQUERYREMOVE is received, a permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal.

Maybe a parameter is missing or wrong. So I'll try a little bit but without any real idea.

Share this post


Link to post
Share on other sites

Does this bring you any closer?

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_AU3Check_Parameters=-w 1 -w 2 -w 3 -w 4 -w 6 -d
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <Misc.au3>

_Singleton(@ScriptName)

HotKeySet("{ESC}", "term")

Global $LastErr

Global $hWnd = GUICreate("USB-Handler")

Global Const $WM_DEVICECHANGE = 0x0219

Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000
Global Const $DEVICE_NOTIFY_SERVICE_HANDLE = 0x00000001
Global Const $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004

Global Const $InterfaceClassGuid = CreateGUIDStruct("D16A55E8-1059-11D2-8FFD-00A0C9A06D32")

;~ Global Const $Flags = BitOr($DEVICE_NOTIFY_WINDOW_HANDLE, $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
Global Const $Flags = $DEVICE_NOTIFY_WINDOW_HANDLE

Global Const $DBT_DEVTYP_OEM = 0x00000000
Global Const $DBT_DEVTYP_VOLUME = 0x00000002
Global Const $DBT_DEVTYP_PORT = 0x00000003
Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005
Global Const $DBT_DEVTYP_HANDLE = 0x00000006

Global $DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate(StringStripWS("uint dbcc_size; uint dbcc_devicetype; uint dbcc_reserved; char dbcc_classguid[128]; char dbcc_name[1]", 7))
;~ ConsoleWrite("$DEV_BROADCAST_DEVICEINTERFACE @ERROR: " & @error & @CR)

DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size", DllStructGetSize($DEV_BROADCAST_DEVICEINTERFACE))
;~ ConsoleWrite("@ERROR: " & @error & @CR)

DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype", $DBT_DEVTYP_DEVICEINTERFACE)
;~ ConsoleWrite("@ERROR: " & @error & @CR)

DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_classguid", $InterfaceClassGuid)
;~ ConsoleWrite("@ERROR: " & @error & @CR)

Global $PtrDEV_BROADCAST_DEVICEINTERFACE = DllStructGetPtr($DEV_BROADCAST_DEVICEINTERFACE)

Global Const $User32 = DllOpen("User32.dll")

Global Const $hDevNotify = DllCall($User32, "handle", "RegisterDeviceNotificationA", "handle", $hWnd, "ptr", $PtrDEV_BROADCAST_DEVICEINTERFACE, "long", $Flags)
ConsoleWrite("$hDevNotify: " & $hDevNotify[0] & " @error: " & @error & @CR)

If $hDevNotify[0] Then
    OnAutoItExitRegister("UnRegisterDevice")
    GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
Else
    ConsoleWrite("Bye" & @LF)
    Exit
EndIf

While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE(Const $hWnd, Const $Msg, Const $wParam, Const $lParam)
    Local Const $DBT_DEVICEARRIVAL = 0x8000 ; A device or piece of media has been inserted and is now available.
    Local Const $DBT_DEVICEQUERYREMOVE = 0x8001 ; A device or piece of media is attemped to remove.
    Local Const $DBT_DEVICEREMOVECOMPLETE = 0x8004 ; A device or piece of media has been removed.

    Switch $wParam
        Case $DBT_DEVICEARRIVAL
            ConsoleWrite(@LF & "DEVICEARRIVAL" & @LF)
            ConsoleWrite(GUIGetMsg() & @LF)
            DeviceData()
        Case $DBT_DEVICEQUERYREMOVE
            ConsoleWrite(@LF & "DEVICEQUERYREMOVE" & @LF)
            ConsoleWrite(GUIGetMsg() & @LF)
            DeviceData()
        Case $DBT_DEVICEREMOVECOMPLETE
            ConsoleWrite(@LF & "DEVICEREMOVECOMPLETE" & @LF)
            ConsoleWrite(GUIGetMsg() & @LF)
            DeviceData()
    EndSwitch
EndFunc ;==>MY_WM_DEVICECHANGE

Func DeviceData()
    ConsoleWrite("dbcc_size: " & DllStructGetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size") & @LF)
    ConsoleWrite("dbcc_devicetype: " & DllStructGetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype") & @LF)
    ConsoleWrite("dbcc_classguid: " & DllStructGetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_classguid") & @LF)
    ConsoleWrite("dbcc_dbcc_name: " & DllStructGetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_dbcc_name") & @LF)
EndFunc ;==>DeviceData

Func term()
    Exit
EndFunc ;==>term

Func UnRegisterDevice()
    Global Const $UnregStatus = DllCall($User32, "BOOL", "UnRegisterDeviceNotificationA", "HDEVNOTIFY", $hDevNotify[0])
    ConsoleWrite($UnregStatus & " @error: " & @error & @CR)
    $LastErr = DllCall("Kernal32.dll", "dword", "GetLastError")
;~  ConsoleWrite("@error: " & @error & @CR)
    ConsoleWrite("Last Error: " & $LastErr & @CR)
    DllClose($User32)
    GUIRegisterMsg($WM_DEVICECHANGE, "")
EndFunc ;==>UnRegisterDevice

; = Function ==========================================================================================================
; Name .....: CreateGUIDStruct
; Syntax ...: CreateGUIDStruct($GUIDstr)
; Param(s) .: $GUIDstr -- String containing a GUID. Cannot be longer or shorter than 36 characters.
; Success ..: A pointer to a _GUID struct containing the GUID string.
; Fail .....: 1 & @error: -1: String was formatted incorrectly.
; Desc. ....: http://msdn.microsoft.com/en-us/library/aa373931%28VS.85%29.aspx
Func CreateGUIDStruct(Const $GUIDstr)
    Switch (IsString($GUIDstr)) And ($GUIDstr <> '') And ($GUIDstr <> ' ') And (StringLen($GUIDstr) = 36)
        Case 1
            Local Const $tmpGUIDstr = StringStripWS($GUIDstr, 8)

            Local Const $GUIDArr = StringSplit($tmpGUIDstr, '-', 2)

            Local Const $dllGUID = DllStructCreate("dword Data1; word Data2; word Data3; byte Data4[8]")

            If StringLen($GUIDArr[0]) = 8 Then
                DllStructSetData($dllGUID, "Data1", $GUIDArr[0])
            EndIf

            If StringLen($GUIDArr[1]) = 4 Then
                DllStructSetData($dllGUID, "Data2", $GUIDArr[1])
            EndIf

            If StringLen($GUIDArr[2]) = 4 Then
                DllStructSetData($dllGUID, "Data3", $GUIDArr[2])
            EndIf

            If StringLen($GUIDArr[3]) = 4 Then
                DllStructSetData($dllGUID, "Data4", StringLeft($GUIDArr[3], 2), 1)
                DllStructSetData($dllGUID, "Data4", StringRight($GUIDArr[3], 2), 2)
            EndIf

            If StringLen($GUIDArr[4]) = 12 Then
                DllStructSetData($dllGUID, "Data4", StringLeft($GUIDArr[4], 2), 3)
                DllStructSetData($dllGUID, "Data4", StringTrimLeft(StringTrimRight($GUIDArr[4], 2), 8), 4)
                DllStructSetData($dllGUID, "Data4", StringTrimLeft(StringTrimRight($GUIDArr[4], 4), 6), 5)
                DllStructSetData($dllGUID, "Data4", StringTrimLeft(StringTrimRight($GUIDArr[4], 6), 4), 6)
                DllStructSetData($dllGUID, "Data4", StringTrimLeft(StringTrimRight($GUIDArr[4], 8), 2), 7)
                DllStructSetData($dllGUID, "Data4", StringRight($GUIDArr[4], 2), 8)
            EndIf

            Return DllStructGetPtr($dllGUID)
        Case 0
            Return SetError(-1, 0, 1)
    EndSwitch
EndFunc ;==>CreateGUIDStruct

Share this post


Link to post
Share on other sites

Does this bring you any closer?

Unfortunately no. ;)

The goal is: I want to safe some files on the USB device BEFORE the USB device is removed. The notification DBT_DEVICEREMOVECOMPLETE is to late for that because there is no access to the device anymore. So if the USB device is attempted to remove (Left mouse click on tray icon and click "remove") I want to be informed about that (DBT_DEVICEQUERYREMOVE) so that I can do something and after that I will release the USB device.

What I've now:

1. A USB device was inserted (DBT_DEVICEARRIVAL). This will happen just if I plug in a USB device. -> working.

2. A USB device is attempted to remove (DBT_DEVICEQUERYREMOVE). Left mouse click on tray icon and click "remove". (After doing this I get immediately the information about finishing remove.) -> not working.

3. A USB device was removed (DBT_DEVICEREMOVECOMPLETE). I get this notification if I pull out (or safely remove -> click on tray icon) a USB device. (But this is to late to d something with this device.) -> working.

Because the notifications DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE get every application. To receive any other notification (like DBT_DEVICEQUERYREMOVE) the application has to call RegisterDeviceNotification. And if I never get DBT_DEVICEQUERYREMOVE I think the registration was not really successful. But otherwise there is no error (=0). Curious.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

From what I gather, DBT_DEVICEQUERYREMOVE will only be announced when the driver for the usb is uninstalled.

Well, I really wanted to help you out but I've come to the limits of my knowledge.

There are some people here that are far more advanced than myself.

Hopefully they will chime in.

Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

I want to use the "RegisterDeviceNotification" function from "user32.dll" to get a notification if a usb device is attempt to remove

(WM_DEVICECHANGE -> $DBT_DEVICEQUERYREMOVE). Can anybody help me to translate the Visual Basic call into a correct AutoIt-call?

Public Type DEV_BROADCAST_DEVICEINTERFACE
  dbcc_size As Long
  dbcc_devicetype As Long
  dbcc_reserved As Long
  dbcc_classguid As GUID
  dbcc_name As Long
End Type

Public Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = &H4
Public Const DEVICE_NOTIFY_WINDOW_HANDLE = 0

Public Const DBT_DEVTYP_DEVICEINTERFACE     As Long = 5

Public Declare Function RegisterDeviceNotification Lib "user32.dll" _
            Alias "RegisterDeviceNotificationA" ( _
            ByVal hRecipient As Long, _
            NotificationFilter As Any, _
            ByVal Flags As Long) As Long
Public Declare Function UnregisterDeviceNotification Lib "user32.dll" _
             (ByVal hRecipient As Long) As Long

Public Function DoRegisterDeviceInterface(hWnd As Long, ByRef hDevNotify As Long) As Boolean
    Dim NotificationFilter As DEV_BROADCAST_DEVICEINTERFACE
        
    NotificationFilter.dbcc_size = Len(NotificationFilter)
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
    
    hDevNotify = RegisterDeviceNotification(hWnd, NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE Or DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
    
    If hDevNotify = 0 Then
        MsgBox "RegisterDeviceNotification failed: " & CStr(Err.LastDllError), vbOKOnly
        DoRegisterDeviceInterface = False
        Exit Function
    End If
    
    DoRegisterDeviceInterface = True
End Function

Dim hDevNotify As Long

Sub Main()
'...
    Call DoRegisterDeviceInterface(Me.hWnd, hDevNotify)
'...
    Call UnregisterDeviceNotification(hDevNotify)
'...
End Sub

I've no idea how to define a type DEV_BROADCAST_DEVICEINTERFACE, how to fill it and how to pass all parameters to the function call. ;)

Dim $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = &H4
Dim $DEVICE_NOTIFY_WINDOW_HANDLE = 0

Dim $DBT_DEVTYP_DEVICEINTERFACE As Long = 5

$hwnd = WinGetHandle(???)  ; How to find my own window handle?
$Flags = $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES + $DEVICE_NOTIFY_WINDOW_HANDLE  ; How to do the boolean operation "OR"?

$hDevNotify = DllCall("user32.dll", "long", "RegisterDeviceNotification", "hwnd", $hwnd, ??? , "long", $Flags) ; How to pass a type/structure?

$result = DllCall("user32.dll", "long", "UnregisterDeviceNotification", "hRecipient", $hDevNotify)

Thank you.

Joline

#Include <WinAPI.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
$TegDEV_BROADCAST_DEVICEINTERFACE = _
"long dbccsize;long dbccdevicetype;long dbccreserved;" & _
"int Data1;short Data2;short Data3;byte Data4[8];long dbccname"

Const $DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004
Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0
Const $DBT_DEVTYP_DEVICEINTERFACE = 5

Main()

Func DoRegisterDeviceInterface($hWnd, ByRef $hDevNotify)
    $NotificationFilter = DllStructCreate($TegDEV_BROADCAST_DEVICEINTERFACE)
    DllStructSetData($NotificationFilter,"dbccsize",DllStructGetSize($NotificationFilter))
    DllStructSetData($NotificationFilter,"dbccdevicetype",$DBT_DEVTYP_DEVICEINTERFACE)
    $hDevNotify = DllCall("User32.dll","HANDLE","RegisterDeviceNotification","HANDLE",$hWnd,"ptr", _
    DllStructGetPtr($NotificationFilter),"DWORD",BitOR($DEVICE_NOTIFY_WINDOW_HANDLE,$DEVICE_NOTIFY_ALL_INTERFACE_CLASSES))
    if (@error) Then
    $hDevNotify = 0
    Else
    $hDevNotify = $hDevNotify[0]
    EndIf
    If $hDevNotify = 0 Then
        MsgBox(0,"MSG","RegisterDeviceNotification failed: " & _WinAPI_GetLastError())
        $DoRegisterDeviceInterface = False
    Return $DoRegisterDeviceInterface
    EndIf

    $DoRegisterDeviceInterface = True
    Return $DoRegisterDeviceInterface
EndFunc

Func Main()
Dim $hDevNotify
$hWnd = GUICreate("My GUI")
GUISetState(@SW_SHOW)
Local $WM_DEVICECHANGE = 0x0219
GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
;'...
    $DoRegisterDeviceInterface = DoRegisterDeviceInterface($hWnd, $hDevNotify)
;'...
;DllCall("User32.dll","HANDLE","UnregisterDeviceNotification","HANDLE",$hDevNotify)
;'...
MsgBox(0,"MSG",$DoRegisterDeviceInterface)
While 1
$msg = GUIGetMsg()
If $msg = $GUI_EVENT_CLOSE Then ExitLoop
WEnd
GUIDelete()
Exit
EndFunc

Func MY_WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
Local $DBT_CONFIGCHANGECANCELED = 0x0019 , _
$DBT_CONFIGCHANGED = 0x0018 , _
$DBT_CUSTOMEVENT = 0x8006 , _
$DBT_DEVICEARRIVAL = 0x8000 , _
$DBT_DEVICEQUERYREMOVE = 0x8001 , _
$DBT_DEVICEQUERYREMOVEFAILED = 0x8002 , _
$DBT_DEVICEREMOVECOMPLETE = 0x8004 , _
$DBT_DEVICEREMOVEPENDING = 0x8003 , _
$DBT_DEVICETYPESPECIFIC = 0x8005 , _
$DBT_DEVNODES_CHANGED = 0x0007 , _
$DBT_QUERYCHANGECONFIG = 0x0017 , _
$DBT_USERDEFINED = 0xFFFF
Switch($wParam)
Case $DBT_CONFIGCHANGECANCELED
MsgBox(0,"MSG","DBT_CONFIGCHANGECANCELED")
Case $DBT_CONFIGCHANGED
MsgBox(0,"MSG","DBT_CONFIGCHANGED")
Case $DBT_CUSTOMEVENT
MsgBox(0,"MSG","DBT_CUSTOMEVENT")
Case $DBT_DEVICEARRIVAL
MsgBox(0,"MSG","DBT_DEVICEARRIVAL")
Case $DBT_DEVICEQUERYREMOVE
MsgBox(0,"MSG","DBT_DEVICEQUERYREMOVE")
Case $DBT_DEVICEQUERYREMOVEFAILED
MsgBox(0,"MSG","DBT_DEVICEQUERYREMOVEFAILED")
Case $DBT_DEVICEREMOVECOMPLETE
MsgBox(0,"MSG","DBT_DEVICEREMOVECOMPLETE")
Case $DBT_DEVICEREMOVEPENDING
MsgBox(0,"MSG","DBT_DEVICEREMOVEPENDING")
Case $DBT_DEVICETYPESPECIFIC
MsgBox(0,"MSG","DBT_DEVICETYPESPECIFIC")
Case $DBT_DEVNODES_CHANGED
MsgBox(0,"MSG","DBT_DEVNODES_CHANGED")
Case $DBT_QUERYCHANGECONFIG
MsgBox(0,"MSG","DBT_QUERYCHANGECONFIG")
Case $DBT_USERDEFINED
MsgBox(0,"MSG","DBT_USERDEFINED")
EndSwitch
Return 1
EndFunc
Edited by wolf9228

صرح السماء كان هنا

 

Share this post


Link to post
Share on other sites

Thank you all but it doesn't work. ;)

Here is a snippet from MSDN:

"The system broadcasts the DBT_DEVICEQUERYREMOVE device event to request permission to remove a device or piece of media. This message is the last chance for applications and drivers to prepare for this removal. However, any application can deny this request and cancel the operation." (DBT_DEVICEQUERYREMOVE Event)

This is what I want to do. As I described, I want to safe some files to the USB device BEFORE it is removed. And as I understand DBT_DEVICEQUERYREMOVE is the right thing to do it.

My understanding:

A USB device is inserted and working. I left-click on the tray icon to remove this device. DBT_DEVICEQUERYREMOVE is sent to any application which has registered. Each of these application now can allow or deny this operation. I want to save something and after that allow the operation. But I get the DEVICEREMOVECOMPLETE message. And this is to late because the device is already removed. :)

Maybe there is an other idea to do this?

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Found this: Capturing Device Events. The part that may be interesting to you is the "DBT_DEVICEQUERYREMOVE" section. Even though I'm sure it's the key I'm at a loss as to what to do with the information.

What I've gathered so far is this: REgister for device notification (done). Use the information sent with a deviceArrival message to find the handle of the new device. Use filecreate with the information to get a handle to the device then use that to load up a dev_braodcast_handle structure.

Found that info here: (http://www.techtalkz.com/microsoft-device-drivers/252416-help-createfile-wm_devicechange-surprise-removal.html)

That's it so far.

Edit:

Got much closer! $lParam contains a pointer to a struct which contains detailed info about the inserted device. I created a DEV_BRADCAST_VOLUME struct which contains the drive letter of the USB device. I will use that drive to open a file stream device and then call RegisterDeviceNotification again but this time with different input data. I hope...

Edit: Currently stuck on opening a file stream to the device.

Edit: Stopping for the night. Here is my current code for all eyes to see.

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_AU3Check_Parameters=-w 1 -w 2 -w 3 -w 4 -w 6 -d
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <WinAPI.au3>
#include <Misc.au3>

_Singleton(@ScriptName)

HotKeySet("{ESC}", "term")

Global Const $hWnd = GUICreate("USB-Handler")

Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x0

Global Const $PtrDEV_BROADCAST_DEVICEINTERFACE = DllStructGetPtr(DEV_BROADCAST_DEVICEINTERFACE())

Global Const $hDevNotify = RegisterDevice($PtrDEV_BROADCAST_DEVICEINTERFACE, $DEVICE_NOTIFY_WINDOW_HANDLE, True)

If $hDevNotify[0] Then
    Global Const $WM_DEVICECHANGE = 0x219
    GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
    OnAutoItExitRegister("UnRegisterDeviceNotification")
Else
    ConsoleWrite("Bye" & @LF)
    Exit
EndIf

While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE(Const $hWnd, Const $Msg, Const $wParam, Const $lParam)
    Local Static $DBT_CONFIGCHANGECANCELED = 0x19
    Local Static $DBT_CONFIGCHANGED = 0x18
    Local Static $DBT_CUSTOMEVENT = 0x8006
    Local Static $DBT_DEVICEARRIVAL = 0x8000 ; A device or piece of media has been inserted and is now available.
    Local Static $DBT_DEVICEQUERYREMOVE = 0x8001 ; A device or piece of media is attemped to remove.
    Local Static $DBT_DEVICEQUERYREMOVEFAILED = 0x8002
    Local Static $DBT_DEVICEREMOVECOMPLETE = 0x8004 ; A device or piece of media has been removed.
    Local Static $DBT_DEVICEREMOVEPENDING = 0x8003
    Local Static $DBT_DEVICETYPESPECIFIC = 0x8005
    Local Static $DBT_DEVNODES_CHANGED = 0x7
    Local Static $DBT_QUERYCHANGECONFIG = 0x17
    Local Static $DBT_USERDEFINED = 0xFFFF

    Switch $wParam
        Case $DBT_DEVICEARRIVAL
            ConsoleWrite("DEVICEARRIVAL" & @LF)

            Local $DEV_BROADCAST_HANDLE = DllStructCreate("dword dbcv_size; dword dbcv_devicetype; dword dbcv_reserved; word dbcv_unitmask; word dbcv_flags", $lParam)

            Local Const $UnitMask = DllStructGetData($DEV_BROADCAST_HANDLE, "dbcv_unitmask")

            Local Const $DriveLetter = GetDriveLetterFromUnitMask($UnitMask)

            _WinAPI_CreateFile("\\\\.\" & $DriveLetter, 2)
            Error("_WinAPI_CreateFile")
        Case $DBT_DEVICEQUERYREMOVE
            ConsoleWrite("DEVICEQUERYREMOVE" & @LF)
        Case $DBT_DEVICEREMOVECOMPLETE
            ConsoleWrite("DEVICEREMOVECOMPLETE" & @LF)
        Case $DBT_CONFIGCHANGECANCELED
            ConsoleWrite("$DBT_CONFIGCHANGECANCELED" & @LF)
        Case $DBT_CONFIGCHANGED
            ConsoleWrite("$DBT_CONFIGCHANGED" & @LF)
        Case $DBT_CUSTOMEVENT
            ConsoleWrite("$DBT_CUSTOMEVENT" & @LF)
        Case $DBT_DEVICEQUERYREMOVEFAILED
            ConsoleWrite("$DBT_DEVICEQUERYREMOVEFAILED" & @LF)
        Case $DBT_DEVICEREMOVEPENDING
            ConsoleWrite("$DBT_DEVICEREMOVEPENDING" & @LF)
        Case $DBT_DEVICETYPESPECIFIC
            ConsoleWrite("$DBT_DEVICETYPESPECIFIC" & @LF)
;~      Case $DBT_DEVNODES_CHANGED
;~          ConsoleWrite("$DBT_DEVNODES_CHANGED" & @LF)
        Case $DBT_QUERYCHANGECONFIG
            ConsoleWrite("$DBT_QUERYCHANGECONFIG" & @LF)
        Case $DBT_USERDEFINED
            ConsoleWrite("$DBT_USERDEFINED" & @LF)
    EndSwitch
EndFunc ;==>MY_WM_DEVICECHANGE

Func GetDriveLetterFromUnitMask(Const $UnitMask)
    Local Const $Drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    Local $Count = 1
    Local $Pom = $UnitMask / 2

    While $Pom <> 0
        $Pom = BitShift($Pom, 1)
        $Count += 1
    WEnd

    Return StringMid($Drives, $Count, 1)
EndFunc ;==>GetDriveLetterFromUnitMask

Func RegisterDevice(Const $StructPtr, Const $Flags, Const $CheckError = False)
    Local COnst $hDevNotify = DllCall("User32.dll", "handle", "RegisterDeviceNotification", "handle", $hWnd, "ptr", $StructPtr, "long", $Flags)
    If $CheckError then Error("RegisterDeviceNotification")
    return $hDevNotify
EndFunc ;==>RegisterDevice

Func DEV_BROADCAST_HANDLE(Const $handle, Const $CheckError = False)
    Local Const $tagDEV_BROADCAST_HANDLE = "dword dbch_size; dword dbch_devicetype; dword dbch_reserved; handle dbch_handle; long dbch_hdevnotify; char dbch_eventguid[128]; long dbch_nameoffset; byte dbch_data[1]"
    Local Const $DEV_BROADCAST_HANDLE = DllStructCreate($tagDEV_BROADCAST_HANDLE)
    If $CheckError Then Error("$DEV_BROADCAST_HANDLE")

    Local Const $DBT_DEVTYP_HANDLE = 0x00000006

    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_size", DllStructGetSize($DEV_BROADCAST_HANDLE))
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_devicetype", $DBT_DEVTYP_HANDLE)
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_handle", $handle)
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_hdevnotify", $hDevNotify)

    Return $DEV_BROADCAST_HANDLE
EndFunc ;==>DEV_BROADCAST_HANDLE

Func DEV_BROADCAST_DEVICEINTERFACE(Const $CheckError = False)
    Local Const $tagDEV_BROADCAST_DEVICEINTERFACE = "dword dbcc_size; dword dbcc_devicetype; dword dbcc_reserved; char dbcc_classguid[128]; char dbcc_name[1];"
    Local Const $DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate($tagDEV_BROADCAST_DEVICEINTERFACE)
    If $CheckError Then Error("DEV_BROADCAST_DEVICEINTERFACE")

    Local Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size", DllStructGetSize($DEV_BROADCAST_DEVICEINTERFACE))
    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype", $DBT_DEVTYP_DEVICEINTERFACE)
    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_name", '0', 1)

    Return $DEV_BROADCAST_DEVICEINTERFACE
EndFunc ;==>DEV_BROADCAST_DEVICEINTERFACE

Func term()
    Exit
EndFunc ;==>term

Func UnRegisterDeviceNotification()
    Local Const $UnregStatus = DllCall("User32.dll", "bool", "UnRegisterDeviceNotification", "hdevnotify", $hDevNotify[0])
    GUIRegisterMsg($WM_DEVICECHANGE, '')
EndFunc ;==>UnRegisterDeviceNotification

Func Error(Const $Oper)
    ConsoleWrite($Oper & ": " & _WinAPI_GetLastErrorMessage() & @LF)
EndFunc ;==>Error
Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

YES!

OK, ok, I lied, lawlz, but I decided to fiddle around and finally got a handle to the usb device! I have this code which displays a message box asking you if you want to continue with ejecting. I dunno if that's exactly what you want but it's a definate step in the right direction.

Tell me if this does what you want, please...

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_AU3Check_Parameters=-w 1 -w 2 -w 3 -w 4 -w 6 -d
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <WinAPI.au3>
#include <Misc.au3>

_Singleton(@ScriptName)

HotKeySet("{ESC}", "term")

Global Const $hWnd = GUICreate("USB-Handler")

Global Const $DBT_DEVTYP_HANDLE = 0x00000006
Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

Global Const $DEVICE_NOTIFY_WINDOW_HANDLE = 0x0

Global Const $PtrDEV_BROADCAST_DEVICEINTERFACE = DllStructGetPtr(DEV_BROADCAST_DEVICEINTERFACE())

Global Const $hDevNotify = RegisterDevice($PtrDEV_BROADCAST_DEVICEINTERFACE, $DEVICE_NOTIFY_WINDOW_HANDLE, True)

If $hDevNotify[0] Then
    Global Const $WM_DEVICECHANGE = 0x219
    GUIRegisterMsg($WM_DEVICECHANGE, "MY_WM_DEVICECHANGE")
    OnAutoItExitRegister("UnRegisterDeviceNotification")
Else
    ConsoleWrite("Bye" & @LF)
    Exit
EndIf

While 1
    Sleep(100)
WEnd

Func MY_WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    Local Static $DBT_CONFIGCHANGECANCELED = 0x19
    Local Static $DBT_CONFIGCHANGED = 0x18
    Local Static $DBT_CUSTOMEVENT = 0x8006
    Local Static $DBT_DEVICEARRIVAL = 0x8000 ; A device or piece of media has been inserted and is now available.
    Local Static $DBT_DEVICEQUERYREMOVE = 0x8001 ; A device or piece of media is attemped to remove.
    Local Static $DBT_DEVICEQUERYREMOVEFAILED = 0x8002
    Local Static $DBT_DEVICEREMOVECOMPLETE = 0x8004 ; A device or piece of media has been removed.
    Local Static $DBT_DEVICEREMOVEPENDING = 0x8003
    Local Static $DBT_DEVICETYPESPECIFIC = 0x8005
    Local Static $DBT_DEVNODES_CHANGED = 0x7
    Local Static $DBT_QUERYCHANGECONFIG = 0x17
    Local Static $DBT_USERDEFINED = 0xFFFF

    Switch $wParam
        Case $DBT_DEVICEARRIVAL
            ConsoleWrite("DEVICEARRIVAL" & @LF)

            Local $DEV_BROADCAST_HANDLE = DllStructCreate("dword dbcv_size; dword dbcv_devicetype; dword dbcv_reserved; word dbcv_unitmask; word dbcv_flags", $lParam)

            Local Const $UnitMask = DllStructGetData($DEV_BROADCAST_HANDLE, "dbcv_unitmask")

            Local Const $DriveLetter = GetDriveLetterFromUnitMask($UnitMask)

            Local Const $Handle = _WinAPI_CreateFile("\\.\" & $DriveLetter & ":", 2)
;~          Error("_WinAPI_CreateFile")

            Global Const $ptrDEV_BROADCAST_HANDLE = DllStructGetPtr(DEV_BROADCAST_HANDLE($Handle))
            RegisterDevice($ptrDEV_BROADCAST_HANDLE, $DBT_DEVTYP_HANDLE)
        Case $DBT_DEVICEQUERYREMOVE
            ConsoleWrite("DEVICEQUERYREMOVE" & @LF)
        Case $DBT_DEVICEREMOVECOMPLETE
            ConsoleWrite("DEVICEREMOVECOMPLETE" & @LF)
        Case $DBT_CONFIGCHANGECANCELED
            ConsoleWrite("$DBT_CONFIGCHANGECANCELED" & @LF)
        Case $DBT_CONFIGCHANGED
            ConsoleWrite("$DBT_CONFIGCHANGED" & @LF)
        Case $DBT_CUSTOMEVENT
            ConsoleWrite("$DBT_CUSTOMEVENT" & @LF)
        Case $DBT_DEVICEQUERYREMOVEFAILED
            ConsoleWrite("$DBT_DEVICEQUERYREMOVEFAILED" & @LF)
        Case $DBT_DEVICEREMOVEPENDING
            ConsoleWrite("$DBT_DEVICEREMOVEPENDING" & @LF)
        Case $DBT_DEVICETYPESPECIFIC
            ConsoleWrite("$DBT_DEVICETYPESPECIFIC" & @LF)
;~      Case $DBT_DEVNODES_CHANGED
;~          ConsoleWrite("$DBT_DEVNODES_CHANGED" & @LF)
        Case $DBT_QUERYCHANGECONFIG
            ConsoleWrite("$DBT_QUERYCHANGECONFIG" & @LF)
        Case $DBT_USERDEFINED
            ConsoleWrite("$DBT_USERDEFINED" & @LF)
    EndSwitch
EndFunc ;==>MY_WM_DEVICECHANGE

Func GetDriveLetterFromUnitMask($UnitMask)
    Local Const $Drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    Local $Count = 1
    Local $Pom = $UnitMask / 2

    While $Pom <> 0
        $Pom = BitShift($Pom, 1)
        $Count += 1
    WEnd

    Return StringMid($Drives, $Count, 1)
EndFunc ;==>GetDriveLetterFromUnitMask

Func RegisterDevice($StructPtr, $Flags, $CheckError = False)
    Local $hDevNotify = DllCall("User32.dll", "handle", "RegisterDeviceNotification", "handle", $hWnd, "ptr", $StructPtr, "long", $Flags)
    If $CheckError Then Error("RegisterDeviceNotification")
    Return $hDevNotify
EndFunc ;==>RegisterDevice

Func UnRegisterDeviceNotification()
    Local Const $UnregStatus = DllCall("User32.dll", "bool", "UnRegisterDeviceNotification", "hdevnotify", $hDevNotify[0])
    GUIRegisterMsg($WM_DEVICECHANGE, '')
EndFunc ;==>UnRegisterDeviceNotification

Func DEV_BROADCAST_HANDLE($Handle, $CheckError = False)
    Local Const $tagDEV_BROADCAST_HANDLE = "dword dbch_size; dword dbch_devicetype; dword dbch_reserved; handle dbch_handle; long dbch_hdevnotify; char dbch_eventguid[128]; long dbch_nameoffset; byte dbch_data[1]"
    Local Const $DEV_BROADCAST_HANDLE = DllStructCreate($tagDEV_BROADCAST_HANDLE)
    If $CheckError Then Error("$DEV_BROADCAST_HANDLE")

    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_size", DllStructGetSize($DEV_BROADCAST_HANDLE))
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_devicetype", $DBT_DEVTYP_HANDLE)
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_handle", $Handle)
    DllStructSetData($DEV_BROADCAST_HANDLE, "dbch_hdevnotify", $hDevNotify)

    Return $DEV_BROADCAST_HANDLE
EndFunc ;==>DEV_BROADCAST_HANDLE

Func DEV_BROADCAST_DEVICEINTERFACE($CheckError = False)
    Local Const $tagDEV_BROADCAST_DEVICEINTERFACE = "dword dbcc_size; dword dbcc_devicetype; dword dbcc_reserved; char dbcc_classguid[128]; char dbcc_name[1];"
    Local Const $DEV_BROADCAST_DEVICEINTERFACE = DllStructCreate($tagDEV_BROADCAST_DEVICEINTERFACE)
    If $CheckError Then Error("DEV_BROADCAST_DEVICEINTERFACE")

    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_size", DllStructGetSize($DEV_BROADCAST_DEVICEINTERFACE))
    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_devicetype", $DBT_DEVTYP_DEVICEINTERFACE)
    DllStructSetData($DEV_BROADCAST_DEVICEINTERFACE, "dbcc_name", '0', 1)

    Return $DEV_BROADCAST_DEVICEINTERFACE
EndFunc ;==>DEV_BROADCAST_DEVICEINTERFACE

Func term()
    Exit
EndFunc ;==>term

Func Error($Oper)
    ConsoleWrite($Oper & ": " & _WinAPI_GetLastErrorMessage() & @LF)
EndFunc ;==>Error
Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

I have this code which displays a message box asking you if you want to continue with ejecting.

There is no message box... ;)

Because of $CheckError=True (line: If $CheckError Then Error("RegisterDeviceNotification")) I get the following messages:

Windows 7:

"RegisterDeviceNotification: The operation completed successfully."

Windows XP:

"RegisterDeviceNotification: The data is invalid."

But $hDevNotify[0] has a value.

Therefore I never get a notification but as long as the script is running, I can not remove the device...

This -> Detecting USB Drive Removal is exactly what I want (but in AutoIt :) ).

I have so less time. Maybe to night I have some time to fiddle around.

Edited by Joline

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

There is no message box... ;)

Because of $CheckError=True (line: If $CheckError Then Error("RegisterDeviceNotification")) I get the following messages:

Windows 7:

"RegisterDeviceNotification: The operation completed successfully."

Windows XP:

"RegisterDeviceNotification: The data is invalid."

But $hDevNotify[0] has a value.

Therefore I never get a notification but as long as the script is running, I can not remove the device...

This -> Detecting USB Drive Removal is exactly what I want (but in AutoIt :) ).

I have so less time. Maybe to night I have some time to fiddle around.

I wonder why I get a messagebox but you dont. I'm running win7 x64.

Do you unhook the device before you run the script?

Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

After trying something I can lock the device from removing but I never get the DBT_DEVICEQUERYREMOVE notification. ;) If I run the script and then insert a device, this device will be locked. I have to finish the script to remove the device properly. This might be ok but if I never get a notification there is no chance to release the device automatically.

As described in the link in the previous post (and also what you have detected) it is necessary to open a file on the USB device and pass the handle to RegisterDeviceNotification. That should be all (if I look to the C# example) but doesn't work in the script. :) What the hell is different?

Share this post


Link to post
Share on other sites

I wonder why I get a messagebox but you dont. I'm running win7 x64.

Which message box? There is no MsgBox in the script code. Or do you mean the message box from windows that the device is locked?

Share this post


Link to post
Share on other sites

I've tried the demo from here: Detecting USB Drive Removal and read the associated description. Because this works exactly like that what I want, I have to analyze this C# code. Maybe this brings me to a solution. (But not tonight. ;) )

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

**FACEPALM** I realize that the reason why the message box popped up was not because the device had been properly registered but because I opened a stream to the device.

Edited by jaberwocky6669

Share this post


Link to post
Share on other sites

I realize that the reason why the message box popped up was not because the device had been properly registered but because I opened a stream to the device.

That's right. ;) Me too. But after stare into the C# code (mentioned above) and fiddling around for hours I couldn'd whats wrong. This C#-Example works properly. And the explanation describes exactly to open a file/stream and register with this handle. blah. That's what you have done with your last code.

Maybe something is still wrong/missing in the NotificationFilter structure. Sadly I'm very busy at the moment but hopefully I'll found some time in the evening to continue...

Share this post


Link to post
Share on other sites

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
Sign in to follow this  
Followers 0