Nikolas92

Weird problem when $DBT_DEVICECOMPLETEREMOVAL is triggered?

6 posts in this topic

#1 ·  Posted (edited)

I am trying to make gui to automate saving selected files and folders from CD, but for some reason when CD is ejected, then button disappears from gui and treeview items dont get removed. I think that problem is with GuiRegisterMsg. Anyone can help me how to fix it?

#NoTrayIcon
#RequireAdmin
#include <GUIConstants.au3>
#include <GUIConstantsEx.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>
#Include <GuiTreeView.au3>
#Include <File.au3>
#include <WinAPIFiles.au3>
#include <WinAPI.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)
Opt("WinTitleMatchMode", 3)
Opt('GUIOnEventMode', 1)
Opt('GUICloseOnEsc' , 1)

FileDelete (@ScriptDir & "\Unstoppable.ucb")
Global $CheckBoxCount = 0
Global $CheckedItems = ''
Global Const $DBT_DEVICEARRIVAL = 0x00008000
Global Const $DBT_DEVICECOMPLETEREMOVAL = 0x00008004
Global Const $DBT_DEVTYP_VOLUME = 0x00000002

Global $hGUI = GUICreate("Waiting for disc...", 530, 400, -1, -1)
Global $hTreeView = _GUICtrlTreeView_Create($hGUI, 0, 0, 530, 370, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_CHECKBOXES))
Global $recover = GUICtrlCreateButton("Recover", 0, 370, 80, 30, $SS_Center)
GUISetBkColor(0xCECECE)
GUICtrlSetOnEvent($recover, '_Recover')
GUISetOnEvent($GUI_EVENT_CLOSE, '_AllExit')
$hImage = _GUIImageList_Create(16, 16, 5, 2)
_GUIImageList_AddIcon($hImage, @SystemDir & "\shell32.dll", 4)
_GUIImageList_AddIcon($hImage, @SystemDir & "\shell32.dll", 54)
_GUICtrlTreeView_SetNormalImageList($hTreeView, $hImage)
GUIRegisterMsg($WM_DEVICECHANGE, "DeviceChange")
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW, $hGUI)

$Temp = DriveGetDrive("CDROM")
If IsArray($Temp) Then
   For $j = 1 to $Temp[0]
      If DriveStatus($Temp[$j]) = 'READY' Then
         $hItem = _GUICtrlTreeView_AddChild($hTreeView, '', StringUpper($Temp[$j]), 0)
         _GUICtrlTreeView_SetChildren($hTreeView, $hItem, True)
         WinSetTitle($hGUI, WinGetTitle($hGUI), 'Select files and folders to recover:')
      EndIf
   Next
EndIf

While 1
   Sleep(1000)
WEnd

Func _AllExit()
   GUIDelete($hGUI)
   Exit
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
   #forceref $hWnd, $iMsg, $wParam
   Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
   $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
   $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
   $iCode = DllStructGetData($tNMHDR, "Code")
   Switch $hWndFrom
   Case $hTreeView
      Switch $iCode
      Case $NM_CLICK
         $aPos = GUIGetCursorInfo($hGUI)
         $ObjectClicked = _GUICtrlTreeView_HitTest($hTreeView, $aPos[0], $aPos[1])
         $cItem = _GUICtrlTreeView_HitTestItem($hTreeView, $aPos[0], $aPos[1])
         If $ObjectClicked = '16' Then
            If _GUICtrlTreeView_GetExpanded($hTreeView, $cItem) = True Then
               ControlTreeView($hGUI, "", $hTreeView, "Collapse", $cItem)
            Else
               $sSelectedPath = StringReplace(_GUICtrlTreeView_GetTree($hTreeView, $cItem), "|", "\")
               If _GUICtrlTreeView_GetChildCount($hTreeView, $cItem) <= 0 Then
                  _SearchFolder($cItem, $sSelectedPath)
               EndIf
            EndIf
         ElseIf $ObjectClicked = '64' Then
            If _GUICtrlTreeView_GetChecked($hTreeView, $cItem) = False Then
               ; checked
               $CheckBoxCount = $CheckBoxCount + 1
               $sSelectedPath = StringReplace(_GUICtrlTreeView_GetTree($hTreeView, $cItem), "|", "\")
               If not StringInStr($sSelectedPath, '\') Then $sSelectedPath = $sSelectedPath & '\'
               $CheckedItems = $CheckedItems & $sSelectedPath & @CRLF
            Else
               ; unchecked
               $CheckBoxCount = $CheckBoxCount - 1
               $sSelectedPath = StringReplace(_GUICtrlTreeView_GetTree($hTreeView, $cItem), "|", "\")
               If not StringInStr($sSelectedPath, '\') Then $sSelectedPath = $sSelectedPath & '\'
               $CheckedItems = StringReplace($CheckedItems, $sSelectedPath & @CRLF, '')
            EndIf
         EndIf
      Case $NM_DBLCLK
         $aPos = GUIGetCursorInfo($hGUI)
         $ObjectClicked = _GUICtrlTreeView_HitTest($hTreeView, $aPos[0], $aPos[1])
         $cItem = _GUICtrlTreeView_HitTestItem($hTreeView, $aPos[0], $aPos[1])
         If $ObjectClicked = '2' or $ObjectClicked = '4' Then
            If _GUICtrlTreeView_GetExpanded($hTreeView, $cItem) = True Then
               ControlTreeView($hGUI, "", $hTreeView, "Collapse", $cItem)
            Else
               $sSelectedPath = StringReplace(_GUICtrlTreeView_GetTree($hTreeView, $cItem), "|", "\")
               If _GUICtrlTreeView_GetChildCount($hTreeView, $cItem) <= 0 Then
                  _SearchFolder($cItem, $sSelectedPath)
               EndIf
            EndIf
         EndIf
      Case $TVN_SELCHANGINGA, $TVN_SELCHANGINGW
         Return 1
      Case $NM_SETFOCUS
         Return 1
      EndSwitch
   EndSwitch
   Return $GUI_RUNDEFMSG
EndFunc

Func _SearchFolder($cParent, $sPath)
   $aFolderList = _FileListToArray($sPath, "*", $FLTA_FOLDERS)
   If IsArray($aFolderList) Then
      For $i = 1 To $aFolderList[0]
         $hItem = _GUICtrlTreeView_AddChild($hTreeView, $cParent, $aFolderList[$i], 0)
         _GUICtrlTreeView_SetChildren($hTreeView, $hItem, True)
      Next
   EndIf
   $aFileList = _FileListToArray($sPath, "*", $FLTA_FILES)
   If IsArray($aFileList) Then
      For $i = 1 To $aFileList[0]
         _GUICtrlTreeView_AddChild($hTreeView, $cParent, $aFileList[$i], 1, 1)
      Next
   EndIf
   If _GUICtrlTreeView_GetChildCount($hTreeView, $cParent) <= 0 Then
      _GUICtrlTreeView_SetChildren($hTreeView, $cParent, False)
   EndIf
EndFunc

Func DeviceChange($hWndGUI, $msg, $wParam, $lParam)
   Local $DriveLetter
   Local Const $DeviceType = GetDeviceType($lParam)
   If $DeviceType = $DBT_DEVTYP_VOLUME Then
      Local Const $UnitMask = GetUnitMask($lParam)
      $DriveLetter = GetDriveLetterFromUnitMask($UnitMask) & ":"
   EndIf
   Switch $wParam
   Case $DBT_DEVICECOMPLETEREMOVAL
      If DriveGetType($DriveLetter) = "CDROM" Then
         $hItem = _GUICtrlTreeView_FindItem($hTreeView, $DriveLetter)
         If $hItem <> '0' Then _GUICtrlTreeView_Delete($hTreeView, $hItem)
         $Temp = DriveGetDrive("CDROM")
         If IsArray($Temp) Then
            $ready = 'no'
            For $j = 1 to $Temp[0]
               If DriveStatus($Temp[$j]) = 'READY' Then
                  $ready = 'yes'
                  ExitLoop
               EndIf
            Next
         EndIf
         If $ready = 'yes' Then
            $RecoverList = StringSplit($CheckedItems, @LF)
            If IsArray($RecoverList) Then
               For $i = 1 to $RecoverList[0] - 1
                  If StringInStr($RecoverList[$i], $DriveLetter & '\') Then
                     $CheckBoxCount = $CheckBoxCount - 1
                     $CheckedItems = StringReplace($CheckedItems, $RecoverList[$i] & @LF, '')
                  EndIf
               Next
            EndIf
         Else
            $CheckBoxCount = 0
            $CheckedItems = ''
            WinSetTitle($hGUI, WinGetTitle($hGUI), 'Waiting for disc...')
         EndIf
      EndIf
   Case $DBT_DEVICEARRIVAL
      If DriveGetType($DriveLetter) = "CDROM" Then
         $hItem = _GUICtrlTreeView_FindItem($hTreeView, $DriveLetter)
         If $hItem <> '0' Then _GUICtrlTreeView_Delete($hTreeView, $hItem)
         $hItem = _GUICtrlTreeView_AddChild($hTreeView, '', $DriveLetter, 0)
         _GUICtrlTreeView_SetChildren($hTreeView, $hItem, True)
         WinSetTitle($hGUI, WinGetTitle($hGUI), 'Select files and folders to recover:')
      EndIf
   EndSwitch
   Return
EndFunc;==DeviceChange

Func GetUnitMask($lParam)
   ; Create a struct from $lParam which contains a pointer to a Windows-created struct.
   Local Const $tagDEV_BROADCAST_VOLUME = "dword dbcv_size; dword dbcv_devicetype; dword dbcv_reserved; dword dbcv_unitmask; word dbcv_flags"
   Local Const $DEV_BROADCAST_VOLUME = DllStructCreate($tagDEV_BROADCAST_VOLUME, $lParam)
   Local Const $UnitMask = DllStructGetData($DEV_BROADCAST_VOLUME, "dbcv_unitmask")
   Return $UnitMask
EndFunc ;==>GetUnitMask

Func GetDeviceType($lParam)
   ; Create a struct from $lParam which contains a pointer to a Windows-created struct.
   Local Const $tagDEV_BROADCAST_VOLUME = "dword dbcv_size; dword dbcv_devicetype; dword dbcv_reserved; dword dbcv_unitmask; word dbcv_flags"
   Local Const $DEV_BROADCAST_VOLUME = DllStructCreate($tagDEV_BROADCAST_VOLUME, $lParam)
   Local Const $DeviceType = DllStructGetData($DEV_BROADCAST_VOLUME, "dbcv_devicetype")
   Return $DeviceType
EndFunc ;==>GetDeviceType

Func GetDriveLetterFromUnitMask($UnitMask)
   Local Const $Drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   Local $Count = 0
   Local $Pom = $UnitMask
   While $Pom <> 0
      $Pom = BitShift($Pom, 1)
      $Count += 1
   WEnd
   If $Count >= 1 And $Count <= 26 Then
      Return StringMid($Drives, $Count, 1)
   Else
      Return SetError(1, 0, '?')
   EndIf
EndFunc ;==>GetDriveLetterFromUnitMask

Func _Recover()
   Local $sRetFolder, $sRetFile, $path, $sDrive, $sDir, $sFolderName, $sExtension, $CDROM
   If $CheckBoxCount = '0' Then
      MsgBox(0, '', 'You have to check at least 1 file or folder before clicking Recover.')
      Return
   Else
      Local $ProgressGui = GUICreate('', 220, 39, (@DesktopWidth-220)/2-35, 0, $WS_CAPTION)
      Local $CurrentActivity = GUICtrlCreateLabel('', 3, 1, 213, 35, $SS_CENTER)
      GUICtrlSetFont($CurrentActivity, 11, 0, 0, "Verdana")
      GUISetState(@SW_HIDE, $hGUI)
      GUISetState(@SW_SHOW, $ProgressGui)
      GUICtrlSetData($CurrentActivity, "Recovering files and folders...")
      $sRetFile = ''
      $sRetFolder = ''
      $RecoverList = StringSplit($CheckedItems, @LF)
      _PathSplit(StringStripCR($RecoverList[1]), $sDrive, $sDir, $sFolderName, $sExtension)
      $CDROM = $sDrive
      For $i = 1 to $RecoverList[0] - 1
         $path = StringStripCR($RecoverList[$i])
         If StringInStr(FileGetAttrib($path), "D") = 0 Then
            ; File
            $sRetFile = $sRetFile & $path & '|' & @DesktopDir & '\Recovered' & @CRLF
         Else
            ; Folder
            _PathSplit($path, $sDrive, $sDir, $sFolderName, $sExtension)
            $sRetFolder = $sRetFolder & $path & '|' & @DesktopDir & '\Recovered\' & $sFolderName & $sExtension & @CRLF
         EndIf
      Next
      FileOpen(@ScriptDir & "\Unstoppable.ucb", $FO_UTF8 + $FO_APPEND)
      FileWrite(@ScriptDir & "\Unstoppable.ucb", @CRLF)
      FileWrite(@ScriptDir & "\Unstoppable.ucb", $sRetFolder)
      FileWrite(@ScriptDir & "\Unstoppable.ucb", $sRetFile)
      RegDelete('HKCU\Software\Roadkil')
      RegWrite('HKCU\Software\Roadkil', 'Lic_Unstp','REG_BINARY', Binary('0x31'))
      RegWrite('HKCU\Software\Roadkil', 'Settings_Unstp', 'REG_BINARY', Binary('0x0f27050000000000'))
      RunWait(@ScriptDir & '\UnstoppableCopier.exe' & ' +urateiwfz "' & @ScriptDir & '\Unstoppable.ucb' & '"')
      GUICtrlSetData($CurrentActivity, "Recovering finished. Ejecting disc...")
      FileDelete (@ScriptDir & "\Unstoppable.ucb")
      $hItem = _GUICtrlTreeView_FindItem($hTreeView, $CDROM)
      _GUICtrlTreeView_Delete($hTreeView, $hItem)
      WinSetTitle($hGUI, WinGetTitle($hGUI), 'Waiting for disc...')
      $CheckBoxCount = 0
      $CheckedItems = ''
      $hVolume = _WinAPI_CreateFile('\\.\' & $CDROM, 2, 2, 6)
      _WinAPI_DeviceIoControl($hVolume, $FSCTL_DISMOUNT_VOLUME)
      _WinAPI_DeviceIoControl($hVolume, $IOCTL_STORAGE_EJECT_MEDIA)
      _WinAPI_CloseHandle($hVolume)
      GUISetState(@SW_HIDE, $ProgressGui)
      GUISetState(@SW_SHOW, $hGUI)
      GUIDelete($ProgressGui)
      Return
   EndIf
EndFunc

 

Edited by Nikolas92

Share this post


Link to post
Share on other sites



This is how error looks, it appears when I eject CD without checking anything or clicking on button.

Untitled.gif

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Well i dont have a cdrom so i had to test with

DriveGetDrive("FIXED")

but its really an external hd, and after i eject it, the only thing that happens is the tree no longer can go recursive/show more files or folders (for this Hdd but for the others works as normal)

Button stays there anyway. As i couldn't reproduce the problem, im not going to be of much help.

Edited by careca

Spoiler

Paster - Main function is to paste text, but has more functions.

OpenW - Open With... alternative, Open any file with any application, set it's icon, set application as default.

Renamer - Rename files and folders, remove portions of text from the filename etc.

BeatsPlayer - Music player.

Params Tool - Right click an exe to see it's parameters or execute them.

Regedit Control - Registry browsing history, quickly jump into any saved key.

Time4Shutdown - Write the time for shutdown in minutes.

Power Profiles Tool - Set a profile as active, delete, duplicate, export and import.

Firefox Profile Backup - Backup/restore previously saved profile.

Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes.

NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s.

IUIAutomation - Topic with framework and examples

Share this post


Link to post
Share on other sites

when drive is ejected, then its tree should also be removed, but that doesnt happen for me in case when button disappears (then tree doesnt get removed)

Share this post


Link to post
Share on other sites

Anyone have idea why randomly when $DBT_DEVICECOMPLETEREMOVAL is triggered function _GUICtrlTreeView_Delete($hTreeView, $hItem) fails and button gets deleted?

 

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