Jump to content

How to detect SD card insertion and removal?


Recommended Posts

I tried this, but it doesnt work correctly>

; msdn.microsoft.com/en-us/library/aa363217%28VS.85%29.aspx
; www.autoitscript.com/forum/topic/121108-registerdevicenotifications
; www.autoitscript.com/forum/topic/47352-stringsplit-by-length
; stackoverflow.com/a/13880732
; www.codeproject.com/articles/35212/wm-devicechange-problem

#include <GUIConstants.au3>
#include <Constants.au3>
#include <WinAPI.au3>
#include <Array.au3>

Global Const $tagDEV_BROADCAST_HANDLE = "dword dbch_size; dword dbch_devicetype; dword dbch_reserved; handle dbch_handle; ptr dbch_hdevnotify; char dbch_eventguid[255]; long dbch_nameoffset; byte dbch_data[1]"
Global Const $tagDEV_BROADCAST_HDR = "dword dbch_size; dword dbch_devicetype; dword dbch_reserved"
Global Const $tagDEV_BROADCAST_VOLUME = "dword dbcv_size; dword dbcv_devicetype; dword dbcv_reserved; dword dbcv_unitmask; dword dbcv_flags"
Global Const $DBT_DEVNODES_CHANGED = 0x00000007
Global Const $DBT_DEVICEARRIVAL = 0x00008000
Global Const $DBT_DEVICEREMOVECOMPLETE = 0x00008004
Global Const $DBT_CUSTOMEVENT = 0x00008006
Global Const $DBT_DEVTYP_HANDLE = 0x00000006
Global Const $DBT_DEVTYP_VOLUME = 0x00000002
Global Const $DBTF_MEDIA = 0x0001
Global Const $DBTF_NET = 0x0002
Global Const $device_notify_window_handle = 0x0000

Global $DrivesToMonitor = ''
Global $NotificationHandlesOfDrives = ''
Global $MonitoredDrives[1][3] = [[1]]
Global $hGUI = GUICreate('', 0, 0, 0, 0, BitOR($DS_SETFOREGROUND, $WS_POPUP), BitOR($WS_EX_CONTROLPARENT, $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST))
GUIRegisterMsg($wm_devicechange, window_proc)

While 1
  Sleep(1000)
WEnd

Func window_proc(Const $h_wnd, Const $msg, Const $w_param, Const $lParam)
   ConsoleWrite($w_param & @CRLF)
   Switch $w_param
   Case $DBT_CUSTOMEVENT
      $StructDevHDR = DllStructCreate($tagDEV_BROADCAST_HDR, $lParam)
      Switch DllStructGetData($StructDevHDR, "dbch_devicetype")
      Case $DBT_DEVTYP_HANDLE
         $StructDevHandle = DllStructCreate($tagDEV_BROADCAST_HANDLE, $lParam)
         $DeviceNotificationHandle = DllStructGetData($StructDevHandle, "dbch_hdevnotify")
         $GUID = _GuidCorrection(DllStructGetData($StructDevHandle, "dbch_eventguid"))
         StringRegExpReplace($GUID, '-', '-')
         If @extended > 3 Then $GUID = StringLeft($GUID, StringInStr($GUID, '-', 0, -1) - 1) & '}'
         If UBound($MonitoredDrives) - 1 > 0 Then
            For $i = 1 to UBound($MonitoredDrives) - 1
               If $DeviceNotificationHandle = $MonitoredDrives[$i][2] Then
                  ConsoleWrite('Drive ' & $MonitoredDrives[$i][0] & ' - Event: ' & $GUID & @CRLF)
                  ExitLoop
               EndIf
            Next
         EndIf
      EndSwitch
   Case $DBT_DEVICEREMOVECOMPLETE
      $StructDevHDR = DllStructCreate($tagDEV_BROADCAST_HDR, $lParam)
      Switch DllStructGetData($StructDevHDR, "dbch_devicetype")
      Case $DBT_DEVTYP_HANDLE
         $StructDevHandle = DllStructCreate($tagDEV_BROADCAST_HANDLE, $lParam)
         $DeviceNotificationHandle = DllStructGetData($StructDevHandle, "dbch_hdevnotify")
         If StringInStr($NotificationHandlesOfDrives, $DeviceNotificationHandle) Then _UnregisterDeviceNotification($lParam)
      Case $DBT_DEVTYP_VOLUME
         $StructDevVolume = DllStructCreate($tagDEV_BROADCAST_VOLUME, $lParam)
         $iUnitMask = DllStructGetData($StructDevVolume, "dbcv_unitmask")
         $iFlags = DllStructGetData($StructDevVolume, "dbcv_flags")
         $sDrive = StringUpper(_GetDriveLetterFromUnitMask($iUnitMask))
         $NewDrives = StringSplit($sDrive, ', ', $STR_ENTIRESPLIT)
         For $i = 1 to $NewDrives[0]
            ConsoleWrite($NewDrives[$i] & ' device removed'& @CRLF)
            If StringInStr($DrivesToMonitor, $NewDrives[$i]) Then _UnregisterDeviceNotification('', $NewDrives[$i])
         Next
      EndSwitch
   Case $DBT_DEVICEARRIVAL
      $StructDevHDR = DllStructCreate($tagDEV_BROADCAST_HDR, $lParam)
      Switch DllStructGetData($StructDevHDR, "dbch_devicetype")
      Case $DBT_DEVTYP_VOLUME
         $StructDevVolume = DllStructCreate($tagDEV_BROADCAST_VOLUME, $lParam)
         $iUnitMask = DllStructGetData($StructDevVolume, "dbcv_unitmask")
         $iFlags = DllStructGetData($StructDevVolume, "dbcv_flags")
         $sDrive = StringUpper(_GetDriveLetterFromUnitMask($iUnitMask))
         $NewDrives = StringSplit($sDrive, ', ', $STR_ENTIRESPLIT)
         For $i = 1 to $NewDrives[0]
            ConsoleWrite($NewDrives[$i] & ' device arrival'& @CRLF)
            If StringInStr($DrivesToMonitor, $NewDrives[$i]) Then _UnregisterDeviceNotification('', $NewDrives[$i])
            _RegisterDeviceNotificationForVolume($NewDrives[$i])
         Next
      EndSwitch
   EndSwitch
EndFunc

Func _GuidCorrection($sGuid)
   If StringLeft($sGuid, 2) = '0x' Then
      $sGuid = Binary($sGuid)
   Else
      $sGuid = StringToBinary($sGuid)
   EndIf
   If StringLeft($sGuid, 2) = '0x' Then $sGuid = StringTrimLeft($sGuid, 2)
   $length = StringLen($sGuid)
   Switch $length
   Case 0 to 19
      Return '{}'
   Case 20
      Return '{' & _FixOrder(StringLeft($sGuid, 8)) & '-' & _FixOrder(StringMid($sGuid, 9, 4)) & '-' & _FixOrder(StringMid($sGuid, 13, 4)) & '-' & StringRight($sGuid, 4) & '}'
   Case Else
      Return '{' & _FixOrder(StringLeft($sGuid, 8)) & '-' & _FixOrder(StringMid($sGuid, 9, 4)) & '-' & _FixOrder(StringMid($sGuid, 13, 4)) & '-' & StringMid($sGuid, 17, 4) & '-' & StringRight($sGuid, $length - 20) & '}'
   EndSwitch
EndFunc

Func _FixOrder($sString)
   $size = 2
   $count = Ceiling(StringLen($sString)/$size)
   $start = 1
   $tmp = ''
   For $i = 1 To $count
      $tmp = StringMid($sString, $start, $size) & $tmp
      $start += $size
   Next
   Return $tmp
EndFunc

Func _GetDriveLetterFromUnitMask($UnitMask)
   $ReceivedDrives = ''
   For $i = 0 to 25
      If BitAND($UnitMask, 0x1) Then $ReceivedDrives = $ReceivedDrives & Chr($i + Asc('A')) & ':' & ', '
      $UnitMask = BitShift($UnitMask, 1)
   Next
   Return StringTrimRight($ReceivedDrives, 2)
EndFunc

Func _RegisterDeviceNotificationForVolume($DriveLetter)
   $hVolume = _WinAPI_CreateFile('\\.\' & $DriveLetter, 2, 2+4, 2+4)
   If $hVolume = 0 Then Return SetError(1, 0, False)
   $NotificationFilter = DllStructCreate($tagDEV_BROADCAST_HANDLE)
   DllStructSetData($NotificationFilter, "dbch_size", DllStructGetSize($NotificationFilter))
   DllStructSetData($NotificationFilter, "dbch_devicetype", $DBT_DEVTYP_HANDLE)
   DllStructSetData($NotificationFilter, "dbch_handle", $hVolume)
   $RegisteredHandle = DllCall("user32.dll", "handle", "RegisterDeviceNotificationW", "handle", $hGUI, "ptr", DllStructGetPtr($NotificationFilter), "dword", $device_notify_window_handle)
   If @error Then Return SetError(2, 0, False)
   $DrivesToMonitor = $DrivesToMonitor & $DriveLetter & '|'
   $NotificationHandlesOfDrives = $NotificationHandlesOfDrives & $RegisteredHandle[0] & '|'
   $MonitoredDrives[0][0] += 1
   ReDim $MonitoredDrives[$MonitoredDrives[0][0]][3]
   $MonitoredDrives[$MonitoredDrives[0][0] - 1][0] = StringUpper($DriveLetter)
   $MonitoredDrives[$MonitoredDrives[0][0] - 1][1] = DriveGetType($DriveLetter)
   $MonitoredDrives[$MonitoredDrives[0][0] - 1][2] = $RegisteredHandle[0]
   _WinAPI_CloseHandle($hVolume)
   ConsoleWrite('Device ' & $DriveLetter & ' registered.' & @CRLF)
   ConsoleWrite('NotificationHandle: ' & $RegisteredHandle[0] & @CRLF)
   Return True
EndFunc

Func _UnregisterDeviceNotification($lParam = '', $DriveLetter = '')
   Local $NotificationHandle = ''
   If $lParam <> '' Then
      $broadcast_handle = DllStructCreate($tagDEV_BROADCAST_HANDLE, $lParam)
      $NotificationHandle = DllStructGetData($broadcast_handle, "dbch_hdevnotify")
   EndIf
   If $DriveLetter <> '' or $NotificationHandle <> '' Then
      If UBound($MonitoredDrives) - 1 > 0 Then
         For $i = 1 to UBound($MonitoredDrives) - 1
            If $DriveLetter = $MonitoredDrives[$i][0] or ($DriveLetter = '' and $NotificationHandle = $MonitoredDrives[$i][2]) Then
               If $DriveLetter = '' Then $DriveLetter = $MonitoredDrives[$i][0]
               $DrivesToMonitor = StringReplace($DrivesToMonitor, $DriveLetter & '|', '')
               If $lParam = '' Then $NotificationHandle = $MonitoredDrives[$i][2]
               $NotificationHandlesOfDrives = StringReplace($NotificationHandlesOfDrives, $NotificationHandle & '|', '')
               _ArrayDelete($MonitoredDrives, $i)
               $MonitoredDrives[0][0] -= 1
               ReDim $MonitoredDrives[$MonitoredDrives[0][0]][3]
               ExitLoop
            EndIf
         Next
      EndIf
   EndIf
   If $NotificationHandle <> '' and $DriveLetter <> '' Then
      $aRet = DllCall("user32.dll", "bool", "UnregisterDeviceNotification", "ptr", $NotificationHandle)
      If @error Then Return SetError(1, @error, False)
      ConsoleWrite('Notification handle: ' & $NotificationHandle & '. Device ' & $DriveLetter & ' unregistered.' & @CRLF)
      Return True
   Else
      Return False
   EndIf
EndFunc

on insertion only event GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE is detect, but nothing happens on sd card removal. Is there error in example or there is no event for sd card removal?

Link to comment
Share on other sites

Hi @Nikolas92 :)

I don't have an SD card at the moment, so, I can't try your code...
But, did you think to use DriveGetState() ?

Maybe you can manage using that function, without all of this code...

Let us know :) 

Edited by FrancescoDiMuro

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

Question is not about how to use drive * functions, but how to detect  sd card arrival and removal with wm_devicechange so that what I want to do will be started. Nevermind, solved. For SD card insertion event GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE, and for sd card removal to monitor change in registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2

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

  • Recently Browsing   0 members

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