Sign in to follow this  
Followers 0
Nikolas92

How to detect SD card insertion and removal?

7 posts in this topic

#1 ·  Posted

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?

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

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

I will always thank you for the time you spent for me.
I'm here to ask, and from your response, I'd like to learn.
By my knowledge, I can help someone else, and "that someone" could help in turn another, and so on.

Share this post


Link to post
Share on other sites

#3 ·  Posted

DriveGetState? You mean DriveStatus? How would that work for detecting when is SD card inserted and removed (without using loop)?

Share this post


Link to post
Share on other sites

#4 ·  Posted

@Nikolas92

Yeah, I would mean DriveStatus...

As I said, at the moment I don't have an SD to test any solution for you...

But, where do you insert the SD Card? In a card reader via USB, in a card-slot of a Notebook?

:) 


Click here to see my signature:

Spoiler

I will always thank you for the time you spent for me.
I'm here to ask, and from your response, I'd like to learn.
By my knowledge, I can help someone else, and "that someone" could help in turn another, and so on.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

in 3G modem (and phone), via usb.

Edited by Nikolas92

Share this post


Link to post
Share on other sites

#6 ·  Posted

So, when you plug the SD card in the modem, you have the drive in the drive list ( This PC -> C: , D: , ... ), right?

In this case, you can keep the work with Drive* functions :) 

Tell me if you need any help :) 


Click here to see my signature:

Spoiler

I will always thank you for the time you spent for me.
I'm here to ask, and from your response, I'd like to learn.
By my knowledge, I can help someone else, and "that someone" could help in turn another, and so on.

Share this post


Link to post
Share on other sites

#7 ·  Posted

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

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