; http://www.xstandard.com/en/documentation/xmd5/ #include #include #include #include #include #include #include #include #include #include #Include #include Global $Secs, $Mins, $Hour, $Time Dim $MenuPath, $Diff, $LVSelect, $iIndex Dim $szDrive, $szDir, $szFName, $szExt Dim $dll = DllOpen("user32.dll") AdlibEnable("_Exit") ; Initialize error handler $oMyError = ObjEvent("AutoIt.Error","MyErrFunc") ; Declare Objects $oMD5 = ObjCreate("XStandard.MD5") ;"ActiveX MD5 Hash/CheckSum If Not IsObj($oMD5) Then MsgBox(48,"Error","You don't have the MD5 COM object installed on !!") Exit EndIf ;---------------------------------------- Register MSG --------------------------------- GUIRegisterMsg($WM_MENUSELECT,"MouseOverMenu") ;----------------------------------------- Main GUI ------------------------------------ $Gui = GuiCreate("Duplicate File Finder" , 975, 771,(@DesktopWidth-975)/2, (@DesktopHeight-840)/2 , _ $WS_OVERLAPPEDWINDOW + $WS_VISIBLE + $WS_CLIPSIBLINGS) ;----------------------------------------- ListView ------------------------------------ $ListView1 = GUICtrlCreateListView("Duplicate Files |Date |Size in Kb |MD5 Hash ", 10, 45, 957, 478,-1, BitOR($LVS_SHOWSELALWAYS,$LVS_REPORT)) GUICtrlSendMsg($listview1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_HEADERDRAGDROP, $LVS_EX_HEADERDRAGDROP) ;Drag & Drop GUICtrlSendMsg($listview1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT) GUICtrlSendMsg($listview1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_TRACKSELECT, $LVS_EX_TRACKSELECT) GUICtrlSetImage($ListView1, "compstui.dll", -15) GUICtrlSetResizing ($ListView1,$GUI_DOCKAUTO) _GUICtrlListView_SetColumnWidth ($ListView1, 0,600) _GUICtrlListView_SetColumnWidth ($ListView1, 3,300) _GUICtrlListView_SetHoverTime ($ListView1,500) ; Set Hoover to x Sec. $ListView2 = GUICtrlCreateListView("Related Duplicate Files |Date |Size in Kb |MD5 Hash ", 10, 530, 957, 200,-1,$LVS_REPORT) GUICtrlSendMsg($listview1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_HEADERDRAGDROP, $LVS_EX_HEADERDRAGDROP) ; Drag & Drop GUICtrlSendMsg($listview1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT) GUICtrlSetImage($ListView2, "compstui.dll", -16) GUICtrlSetResizing ($ListView2,$GUI_DOCKAUTO) _GUICtrlListView_SetColumnWidth ($ListView2, 0,600) _GUICtrlListView_SetColumnWidth ($ListView2, 3,300) ;------------------------------------ Labels ------------------------------------------- $Progressbar1 = GUICtrlCreateProgress (167,732,800,15) GUICtrlSetColor(-1,32250) ; not working with Windows XP Style $ProgressLabel = GUICtrlCreateLabel("Processing MD5 Checksum : ",10 ,732 ,155,15) $PathLabel = GUICtrlCreateLabel("Reading Files : ",10 ,750 ,695,18,$SS_SUNKEN) $TimeLabel = GUICtrlCreateLabel("Time Elapsed : ",710 ,750 ,135,18,$SS_SUNKEN) $VersionLabel = GUICtrlCreateLabel("MD5 Version - " & $oMD5.Version,850 ,750 ,120,18,$SS_SUNKEN) ;------------------------------------ Menu --------------------------------------------- Dim $sPath = @MyDocumentsDir $sShortPath = StringSplit($sPath,"\") $nFileMenu1 = GUICtrlCreateMenu(" &Open") $nFileSelFolder1= GUICtrlCreateMenuItem("Select Folder ...",$nFileMenu1) GUICtrlSetState(-1,$GUI_DEFBUTTON) $nFileSelFolder2= GUICtrlCreateMenuItem("Export to File",$nFileMenu1) $nFileSelFolder0= GUICtrlCreateMenuItem("",$nFileMenu1) $nFileSelFolder3 = GUICtrlCreateMenuItem($sShortPath[1]&"\ ...\" & $sShortPath[$sShortPath[0]] ,$nFileMenu1) $nFileMenu2 = GUICtrlCreateMenu("&Info") $nFileSelFolderH= GUICtrlCreateMenuItem("Help" ,$nFileMenu2) $nFileSelFolderA= GUICtrlCreateMenuItem("About ...",$nFileMenu2) ;------------------------------------ Button ------------------------------------------- $bScan = GuiCtrlCreateButton("Scan ...", 10, 2, 40, 40, BitOr($BS_BOTTOM,$BS_ICON)) GUICtrlSetImage ($bScan, "shell32.dll",-219) GUICtrlSetTip($bScan,"Press F3 to Scan") HotKeySet("{F3}", "_FindDups_F3") ;------------------------------------- Input -------------------------------------------- $Group = GUICtrlCreateGroup("Filters ", 100, 5, 400, 30) $sExtention = GUICtrlCreateLabel("File Extention : ",110 ,18 ,80,15) $sFileSize = GUICtrlCreateLabel("File Size in Kb : ",270 ,18 ,70 ,15) $sFilter = GUICtrlCreateInput ("*", 200, 14, 40, 17) GUICtrlSetTip($sFilter,"Extention like PDF, ZIP, EXE, ... ") $sSize = GUICtrlCreateInput ("1", 350, 14, 60, 17) GUICtrlSetTip($sSize,"Input a Size number to filter on ... ") ;-------------------------------------- Context Menu ------------------------------------ $OptionsContext = GUICtrlCreateContextMenu($ListView2) $OptionsFile1 = GUICtrlCreateMenuItem("Open File ", $OptionsContext) $OptionsFile2 = GUICtrlCreateMenuItem("Delete File ", $OptionsContext) ;-------------------------------------- Group ------------------------------------------- $Group = GUICtrlCreateGroup("Statistics ", 620, 5, 300, 30) $ItemsCnt = GUICtrlCreateLabel("Duplicate Items : 0" , 630, 18, 160, 15) $FilesCnt = GUICtrlCreateLabel("Number of Files Processed : 0" , 740, 18, 160, 15) ;-------------------------------------- DB Init ----------------------------------------- _SQLite_Startup () _SQLite_Open () ; open :memory: Database _SQLite_Exec (-1, "CREATE TABLE Duplicates (File,Date,Size,md5);") _SQLite_Exec (-1, "CREATE TABLE Bookmarks (Pointer,ShortPointer);") ;GUI handling ;------------ GuiSetState() GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; Simple HeaderSort Global $B_DESCENDING [_GUICtrlListView_GetColumnCount ($ListView1) ] While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE _SQLite_Exec (-1, "DROP TABLE Duplicates;") _SQLite_Exec (-1, "DROP TABLE Bookmarks;") _SQLite_Close () _SQLite_Shutdown () DllClose($dll) Exit Case $nFileSelFolder1 $MenuPath = FileSelectFolder("Select a Folder to Scan ...", "", "", $sPath) Case $nFileSelFolder3 $MenuPath = FileSelectFolder("Select a Folder to Scan ...", "", "", $sPath) Case $nFileSelFolder2 _Export() Case $nFileSelFolderH Help() Case $nFileSelFolderA About() Case $bScan If $MenuPath = "" then MsgBox(48,"Error","No Folders selected !!") Else _FindDups(GUICtrlRead($sFilter),GUICtrlRead($sSize)) EndIf Case $OptionsFile1 $LVSelect = _GUICtrlListView_GetItemText($ListView1, Int(_GUICtrlListView_GetSelectedIndices($ListView1)), 0) $DuplicateFilePath = _PathSplit($LVSelect,$szDrive, $szDir, $szFName, $szExt) $Zxtension = StringSplit($DuplicateFilePath[4],".") If StringInStr(Assoc($DuplicateFilePath[4]),":\") Then ShellExecute($DuplicateFilePath[3]&$DuplicateFilePath[4],"",$DuplicateFilePath[1]&$DuplicateFilePath[2]) EndIf Case $OptionsFile2 $iIndex = _GUICtrlListView_GetSelectedIndices ($ListView2) $LVSelect = _GUICtrlListView_GetItemText($ListView2, int($iIndex), 0) If MsgBox(1,"Important","Are you sure you want to delelete " & @CR & @CR & $LVSelect) = 1 Then _FileDelete($LVSelect,int($iIndex)) EndIf Case $nMsg = $GUI_EVENT_PRIMARYDOWN $Pos = GUIGetCursorInfo() If IsArray($Pos) Then If ($Pos[4] == $listview1) Then If $iIndex <> _GUICtrlListView_GetSelectedIndices ($ListView1) Then $iIndex = _GUICtrlListView_GetSelectedIndices ($ListView1) ; Bug _GUICtrlListView_GetSelectedIndices returns a string i/o Int $LVSelect = _GUICtrlListView_GetItemText($ListView1, int($iIndex), 3) _SelectDups($LVSelect) EndIf EndIf EndIf EndSwitch WEnd ;--------------------------------------- Functions ---------------------------------- Func _FindDups_F3() _FindDups(GUICtrlRead($sFilter),GUICtrlRead($sSize)) EndFunc Func _FindDups($sExt, $sFSize) Local $hQuery, $aRow local $sPathMenu, $i, $y ;$hWnd = WinGetHandle("Duplicate File Finder") ;$hMain = _GUICtrlMenu_GetMenu ($hWnd) ;$hFile = _GUICtrlMenu_GetItemSubMenu ($hMain, 0) _GUICtrlListView_DeleteAllItems ($ListView1) _GUICtrlListView_DeleteAllItems ($ListView2) GuiCtrlSetData($PathLabel,"Reading Files : ") GuiCtrlSetData($TimeLabel,"Time Elapsed : ") GuiCtrlSetData($ItemsCnt,"Duplicate Items : 0") GuiCtrlSetData($FilesCnt,"Number of Files Processed : 0") _SQLite_Exec (-1, "DELETE FROM Duplicates;") If $MenuPath = "" Then MsgBox(0,"Error","No valid Selection made ... Try again") Return Else $sPath = $MenuPath $sShortPath = StringSplit($sPath,"\") $ShortMenu = $sShortPath[1]&"\ ...\"&$sShortPath[$sShortPath[0]] _SQLite_Exec (-1, 'INSERT INTO Bookmarks (Pointer,ShortPointer) VALUES' & '("' & $sPath & '","' & $ShortMenu & '");') ;_SQlite_Query (-1, "SELECT Count(*) From (SELECT DISTINCT(Pointer) FROM Bookmarks);", $hQuery) ; While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ; consolewrite("Counter" & $aRow[0] & @CRLF) ; $y = $aRow[0] ; WEnd _SQlite_Query (-1, "SELECT DISTINCT(Pointer) FROM Bookmarks;", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;consolewrite("Pointer " & $aRow[0] & @CRLF) WEnd _SQlite_Query (-1, "SELECT DISTINCT(ShortPointer) FROM Bookmarks;", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;consolewrite("ShortPointer " &$aRow[0] & @CRLF) GUICtrlSetData($nFileSelFolder3,$aRow[0]) WEnd EndIf $Begin = TimerInit() GuiCtrlSetData($PathLabel,"Reading Files : ") $aFilesList = _FileListToArrayEx ($sPath, "*."&$sExt) For $n = 1 To $aFilesList[0] GUICtrlSetData ($Progressbar1,($n/$aFilesList[0])*100) $sFileSize = Round(FileGetSize($aFilesList[$n])/1024,2) $sFileDate = FileGetTime($aFilesList[$n], 1) $sDateStamp = $sFileDate[2] & "/" & $sFileDate[1] & "/" & $sFileDate[0] If $sFileSize >= $sFSize Then $oDict1_key = $oMD5.GetCheckSumFromFile($aFilesList[$n]) ; Or Reverse $oMD5.GetCheckSumFromString _SQLite_Exec (-1, 'INSERT INTO Duplicates(File,Date,Size,md5) VALUES' & _ '("' & $aFilesList[$n] & '","' & $sDateStamp & '","' & $sFileSize & '","' & $oDict1_key & '");') EndIf Sleep (25) _TicksToTime(Int(TimerDiff($Begin)), $Hour, $Mins, $Secs ) Local $sTime = $Time ; save current time to be able to test and avoid flicker.. $Time = StringFormat("%02i:%02i:%02i", $Hour, $Mins, $Secs) GuiCtrlSetData($TimeLabel,"Time Elapsed : " & $Time ) Next GuiCtrlSetData($FilesCnt,"Number of Files Processed : " & $aFilesList[0]) _SQlite_Query (-1, "SELECT * FROM Duplicates GROUP BY md5 HAVING COUNT(*) > 1;", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;ConsoleWrite(StringFormat(" %-10s %-10s %-10s %-10s ", $aRow[0], $aRow[1]) & @CR) $DataCol = GUICtrlCreateListViewItem($aRow[0] & "|" & $aRow[1] & "|" & $aRow[2] & "|" & $aRow[3],$ListView1) WEnd GuiCtrlSetData($ItemsCnt,"Duplicate Items : " & _GUICtrlListView_GetItemCount ($ListView1)) _GUICtrlListView_SetColumnWidth ($ListView1, 0,$LVSCW_AUTOSIZE) ; AutoSize Listview, needs to be called after filling the LV EndFunc Func _SelectDups($LVSelect) Local $hQuery, $aRow _GUICtrlListView_DeleteAllItems ($ListView2) _SQlite_Query (-1, "SELECT * FROM Duplicates WHERE md5='" & $LVSelect & "';", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;ConsoleWrite(StringFormat(" %-10s %-10s %-10s %-10s ", $aRow[0], $aRow[1]) & @CR) $DataCol = GUICtrlCreateListViewItem($aRow[0] & "|" & $aRow[1] & "|" & $aRow[2] & "|" & $aRow[3],$ListView2) WEnd _GUICtrlListView_SetColumnWidth ($ListView2, 0,$LVSCW_AUTOSIZE) EndFunc Func _Export() Local $hQuery, $aRow, $avExport $file = FileOpen(@ScriptDir & "\Duplicate Files.csv",2) FileWrite($file,"Path" & ";" & "Date" & ";" & "Size / Kb" & ";" & "Md5" & @LF) _SQlite_Query (-1, "SELECT * FROM Duplicates WHERE md5 IN (SELECT md5 FROM Duplicates GROUP BY md5 HAVING COUNT(*) > 1) ORDER BY md5;", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;ConsoleWrite( $aRow[0] & ";" & $aRow[1] & ";" & StringReplace($aRow[2],".",",") & ";" & $aRow[3] & @LF) FileWrite($file,$aRow[0] & ";" & $aRow[1] & ";" & StringReplace($aRow[2],".",",") & ";" & $aRow[3] & @LF) WEnd FileClose($file) MsgBox(64,"Info ... ","Report finished.") EndFunc Func _FileListToArrayEx($sPath, $sMask='*') Local $i, $j, $RetList[1], $DirsArr = _FileListToArray($sPath, '*', 2), $SubDirFiles, $FilesArr $FilesArr = _FileListToArray($sPath, $sMask, 1) For $i = 1 To UBound($FilesArr) - 1 ReDim $RetList[UBound($RetList)+1] $RetList[UBound($RetList)-1] = $sPath & "\" & $FilesArr[$i] GuiCtrlSetData($PathLabel,"Reading Files : " & $sPath & "\" & $FilesArr[$i]) Next If UBound($DirsArr) > 0 Then For $i = 1 To $DirsArr[0] $SubDirFiles = _FileListToArrayEx($sPath & "\" & $DirsArr[$i], $sMask) If $SubDirFiles[0] > 0 Then For $j = 1 To $SubDirFiles[0] ReDim $RetList[UBound($RetList)+1] $RetList[UBound($RetList)-1] = $SubDirFiles[$j] GuiCtrlSetData($PathLabel,"Reading Files : " & $SubDirFiles[$j]) Next Else $FilesArr = _FileListToArray($sPath & "\" & $DirsArr[$i], $sMask, 1) For $j = 1 To UBound($FilesArr) - 1 ReDim $RetList[UBound($RetList)+1] $RetList[UBound($RetList)-1] = $sPath & "\" & $DirsArr[$i] & "\" & $FilesArr[$j] Next EndIf Next EndIf $RetList[0] = UBound($RetList) - 1 Return $RetList EndFunc Func _FileDelete($Filename,$Index) FileDelete($Filename) _SQLite_Exec (-1, 'DELETE FROM Duplicates Where File="'& $Filename & '";') _GUICtrlListView_DeleteItem($ListView2,$Index) EndFunc Func Assoc($Filename) If StringRight($Filename, 3) = "exe" Or StringInStr($Filename, ".") = 0 Then Return -1 $Ext = StringRight($Filename, 3) $Descr = RegRead("HKEY_CLASSES_ROOT\" & "." & $Ext, "") $Program = RegRead("HKEY_CLASSES_ROOT\" & $Descr & "\Shell\Open\Command", "") $Program = StringReplace($Program, '"', "") $Match = StringInStr($Program, ".exe") If $Match = 0 Then Return $Filename EndIf $Program = SubString($Program, 1, $Match + 3, 1, 1) Return $Program EndFunc Func SubString($String, $start, $end, $StartOccur, $EndOccur) Local $Match1 Local $Match2 Local $i If IsString($start) Then $Match1 = StringInStr($String, $start, 0, $StartOccur) If $Match1 = 0 Then Return 1 Else $Match1 = $start EndIf If IsString($end) Then $Match2 = StringInStr($String, $end, 0, $EndOccur) If $Match2 = 0 Then Return 11 Else $Match2 = $end EndIf If $end = -1 Then $NewString = StringMid($String, $Match1) Else For $i = 1 To 3 If IsNumber($Match2) Then ExitLoop Select Case $i = 1 $Match2 = StringInStr($String, $end) Case $i = 2 $TempString = StringTrimLeft($String, $Match1) $Match2 = StringInStr($TempString, $end) $Match2 = $Match1 + $Match2 EndSelect If $Match2 > 0 Then ExitLoop ElseIf $i = 3 Then Return 1 EndIf Next $NewString = StringTrimLeft($String, $Match1 - 1) $NewString = StringTrimRight($NewString, StringLen($String) - $Match2) EndIf If IsNumber($NewString) Then Return 2 Return $NewString EndFunc Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) ; HeaderSort Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView $hWndListView = $ListView1 If Not IsHWnd($ListView1) Then $hWndListView = GUICtrlGetHandle($ListView1) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iIDFrom = DllStructGetData($tNMHDR, "IDFrom") $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView Switch $iCode Case $LVN_COLUMNCLICK ; A column was clicked Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) _GUICtrlListView_SimpleSort ($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem")) ; No return value EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc Func MouseOverMenu($hWndGUI, $MsgID, $WParam, $LParam) Local $id = BitAnd($WParam, 0xFFFF), $hQuery, $aRow ;ConsoleWrite( "hWndGui= "&$hWndGUI& @LF &"MsgId= "&$MsgID& @LF &"WParam= " &$WParam& @LF &"$LParam= "&$LParam& @LF) ;ConsoleWrite("ID= "& $id & @LF) ;ConsoleWrite(GUICtrlRead ($id,1) & @LF) $sMenuText= GUICtrlRead ($id,1) ;ConsoleWrite("test" & $sMenuText & @LF) ToolTip("") If $ID > 13 Then _SQlite_Query (-1, "SELECT DISTINCT(Pointer) FROM Bookmarks WHERE Shortpointer='"& $sMenuText & "';", $hQuery) While _SQLite_FetchData ($hQuery, $aRow) = $SQLITE_OK ;consolewrite($aRow[0] & @CRLF) ;ConsoleWrite("Output " & $aRow[0] & @LF) Tooltip($aRow[0]) WEnd EndIf Return $GUI_RUNDEFMSG EndFunc Func Help() MsgBox(64,"Help info", _ "IMPORTANT : " & @CRLF & _ "When selecting a folder to scan it is recommended not to select the top level 'C:' drive" & @CRLF & _ "This will take to much time and CPU, to scan and process. Better is select a smaller range to scan." & @CRLF & _ @CRLF & _ "USAGE :" & @CRLF & _ "To start, hoover the mouse over an item in the top listview." & @CRLF & _ "On the bottem listview you will see all duplicate items appear" & @CRLF & @CRLF & _ "Richt click an item in the bottom listview, and select OPEN or DELETE." & @CRLF & _ "OPEN will run the file. If there is an associated application on your system to run it" & @CRLF & @CRLF & _ "Press F3 to start scanning and ESC to quit while processing the MD5 checksums" & @CRLF & _ @CRLF ) EndFunc Func About() $GUI = GUICreate ("About ..." , 450 , 130) GUICtrlCreateLabel ("IMPORTANT : " & @CRLF & _ "This application uses the MD5 Com object from :" & @CRLF, 10 , 15, 400,40) $link_1 = GUICtrlCreateLabel ("http://www.xstandard.com/en/documentation/xmd5/", 10 , 45, 420,20) GUICtrlSetFont (-1 , 13 , 600) GUICtrlSetColor (-1 ,0x004080) GUICtrlSetCursor (-1 , 0) GUICtrlCreateLabel ("As well as the SQLite database component." & @CRLF & _ "Make sure both are properly installed on your machine." & @CRLF & _ @CRLF, 10 , 75, 400,40) GUISetState (@SW_SHOW , $GUI) While 1 $msg = GUIGetMsg () If $msg = $gui_event_close Then Exit If $msg = $link_1 Then ShellExecute ("http://www.xstandard.com/en/documentation/xmd5/",1) EndIf WEnd EndFunc Func MyErrFunc() $HexNumber=hex($oMyError.number,8) Msgbox(0,"COM Error Test","We intercepted a COM Error !" & @CRLF & @CRLF & _ "err.description is: " & @TAB & $oMyError.description & @CRLF & _ "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _ "err.number is: " & @TAB & $HexNumber & @CRLF & _ "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _ "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _ "err.source is: " & @TAB & $oMyError.source & @CRLF & _ "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _ "err.helpcontext is: " & @TAB & $oMyError.helpcontext _ ) SetError(1) ; to check for after this function returns Endfunc Func _Exit() If _IsPressed("1b", $dll) Then MsgBox(0,"Esc Key Pressed", "Quit Application") Exit EndIf EndFunc