Title: Home made RecycleBin
Question: How to restore files from the recycle bin and delete files present in the recycle bin.
Answer:
To restore as well as delete file from the bin you need to make use of the following functions.
function SHQueryRecycleBin(pszrtootpath:pchar;QUERYRBINFO:pshqueryrbinfo):integer;stdcall;external 'shell32' name 'SHQueryRecycleBinA'; //used to get the number of files in the bin.
function _FindFirstChangeNotification(lpPathName: PChar;bWatchSubtree:TWinBool;dwNotifyFilter:
DWORD): THandle;stdcall; external kernel32 name 'FindFirstChangeNotificationA';
// used to notify the program when user has deleted a file
function SHEmptyRecycleBin(hwnd:thandle;pszRootPath:pchar;dwFlags:integer):integer;stdcall;external 'shell32.dll' name'SHEmptyRecycleBinA'; //This function empties the recycle bin.
In delphi the function FindFirstChangeNotification is already declared but in Delphi 3 and above it does not work correctly.If the second parameter is true then the function always returns an invalid handle.(visit http://members.aye.net/~bstowers/delphi/bugs/ for more info).
So you need to redeclare the FindFirstChangeNotification function as shown below.
type
TWinBool = (winFalse, winTrue);
function _FindFirstChangeNotification(lpPathName: PChar;bWatchSubtree:TWinBool;dwNotifyFilter:
DWORD): THandle;stdcall; external kernel32 name 'FindFirstChangeNotificationA';
The above function is used to refresh the list of files in the recyclebin when the user deletes a file.
To use this function we have to first create a thread.This thread checks continuosly checks whether any file was deleted and then refreshes the list of deleted items.
For more information see delphi tips 'SHQUERYBINFO', 'SHemptyrecycleBin',
'Get the list of files from bin'.
Here is the code of the thread.
unit Unit2;
interface
uses
Classes,SysUtils,windows;
type
TFileChangeNotify = class(TThread)
private
protected
procedure Execute; override;
procedure filenotify;//refreshes the list when user has deleted a file.
end;
var
qh1:thandle;
implementation
uses
unit1;
procedure TFileChangeNotify.filenotify;
begin
form1.refreshlist;
end;
procedure TFileChangeNotify.Execute;
var
pdir:pchar;
st:integer;
tmp:boolean;
begin
pdir:='C:\';
qh1:=0;
qh1:=_FindFirstChangeNotification(pdir,Twinbool(1),FILE_NOTIFY_CHANGE_LAST_WRITE);
while true do
begin
st:=WaitForSingleObject(qh1,INFINITE);
if st=WAIT_OBJECT_0 then
begin
Synchronize(filenotify);
SHUpdateRecycleBinIcon;
end;
tmp:=findnextchangenotification(qh1);
if tmp=false then
Terminate;
end;
end;
end.
You need to add a Tlistview control to your form, and add two columns to it.
Here is the code of main program.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Menus, ComCtrls,unit2;{unit2 is the unit in which the thread resides}
const SHERB_NOCONFIRMATION = $1;
const SHERB_NOPROGRESSUI = $2;
const SHERB_NOSOUND = $4;
type TWinBool = (winFalse, winTrue);
type Tfbuf=packed record
data:array[0..255]of char;
u1:array[0..3] of char;
recno:smallint;
u2:array[0..18] of char;
end;
type SHQUERYRBINFO =packed record
cbSize:integer;
i64Size:int64;
i64NumItems:int64;
end;
pshqueryrbinfo =^SHQUERYRBINFO;
function SHQueryRecycleBin(pszrtootpath:pchar;QUERYRBINFO:pshqueryrbinfo):integer;stdcall;external 'shell32' name 'SHQueryRecycleBinA';
function _FindFirstChangeNotification(lpPathName: PChar;bWatchSubtree:TWinBool;dwNotifyFilter: DWORD): THandle;stdcall; external kernel32 name 'FindFirstChangeNotificationA';
function SHUpdateRecycleBinIcon:integer;stdcall;external 'shell32.dll';
function SHEmptyRecycleBin(hwnd:thandle;pszRootPath:pchar;dwFlags:integer):integer;stdcall;external 'shell32.dll' name'SHEmptyRecycleBinA';
type
TForm1 = class(TForm)
RBinList: TListView;
MainMenu1: TMainMenu;
file1: TMenuItem;
View1: TMenuItem;
Refresh1: TMenuItem;
Edit1: TMenuItem;
SelectAll1: TMenuItem;
Restore1: TMenuItem;
N1: TMenuItem;
Delete1: TMenuItem;
N2: TMenuItem;
Close1: TMenuItem;
InvertSelection1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure Refresh1Click(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure file1Click(Sender: TObject);
procedure SelectAll1Click(Sender: TObject);
procedure InvertSelection1Click(Sender: TObject);
procedure Restore1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Close1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Delete1Click(Sender: TObject);
private
{ Private declarations }
public
qh:thandle;
procedure refreshlist;
function updateinfo(fname:string):boolean;//Makes appropriate changes to the INFO2 file
//present in recycled folder.
procedure Restorefiles;//restores the selected files from the recycle bin.
procedure deletefiles;//deletes the selected files from the recycle bin.
end;
var
Form1: TForm1;
rbinfo:SHQUERYRBINFO;
reccount:integer;
fhandle:integer;
monitorthread:TFileChangeNotify;
implementation
{$R *.DFM}
procedure tform1.deletefiles;
var
i:integer;
sname:string;
dname:string;
begin
monitorthread.Suspend;
for i:=0 to rbinlist.Items.Count-1 do
begin
if rbinlist.Items[i].Selected=true then
begin
sname:=ExtractFileDrive(rbinlist.Items[i].SubItems[0]) + '\Recycled\DC'+rbinlist.Items[i].SubItems[1]+ExtractFileExt(rbinlist.Items[i].caption);
dname:=rbinlist.Items[i].SubItems[0]+rbinlist.Items[i].caption;
deleteFile(sname);
updateinfo(dname);
end;
end;
monitorthread.Resume;
end;
function tform1.updateinfo(fname:string):boolean;
var
rbuff:Tfbuf;
fread:integer;
tsize:integer;
aname:pchar;
ch: char;
begin
result:=false;
ch:=#0;
fhandle:=fileopen('C:\recycled\info2',fmOpenReadWrite or fmShareDenyNone);
if fhandle0 then
begin
tsize:=GetFileSize(fhandle,nil);
setfilepointer(fhandle,20,nil,FILE_BEGIN);
fread:=20;
while(fread begin
fread:=fread+fileread(fhandle,rbuff,280);
if rbuff.data[0]#0 then
begin
aname:=pchar(@rbuff.data[0]);
if StrComp(aname,pchar(fname))=0 then
begin
setfilepointer(fhandle,-280,nil,FILE_CURRENT);
filewrite(fhandle,ch,1);
result:=true;
break;
end;
end;
end;
fileclose(fhandle);
end;
end;
procedure tform1.refreshlist;
var
rbuff:Tfbuf;
fread:integer;
tsize:integer;
aname:pchar;
fitem:tlistitem;
dname:pchar;
iconhandle:thandle;
tmp:word;
iconid:integer;
icon:ticon;
begin
monitorthread.Suspend;
zeromemory(@rbuff,sizeof(rbuff));
rbinlist.Items.Clear;
fhandle:=fileopen('C:\recycled\info2',fmOpenRead);
if fhandle0 then
begin
tsize:=GetFileSize(fhandle,nil);
setfilepointer(fhandle,20,nil,FILE_BEGIN);
fread:=20;
while(fread begin
fread:=fread+fileread(fhandle,rbuff,280);
if rbuff.data[0]#0 then
begin
aname:=pchar(@rbuff.data[0]);
dname:=pchar((ExtractFileDrive(aname)+'\Recycled\DC'+inttostr
(rbuff.recno)+extractfileext(aname)));
iconhandle:=ExtractAssociatedIcon(HInstance,dname,tmp);
icon.Handle:=iconhandle;
iconid:=largeimagelist.AddIcon(icon);
fitem:=rbinlist.Items.add;
fitem.ImageIndex:=iconid;
fitem.Caption:=ExtractFileName(aname);
fitem.SubItems.Add(ExtractFilePath(aname));
fitem.SubItems.add(inttostr(rbuff.recno));
end;
end;
fileclose(fhandle);
end;
rbinfo.cbSize:=sizeof(rbinfo);
rbinfo.i64NumItems:=0;
rbinfo.i64Size:=0;
SHQueryRecycleBin('C:\',@rbinfo);
if (rbinlist.items.count=0) and (rbinfo.i64Size0) then
SHEmptyRecycleBin(form1.handle,'C:\',SHERB_NOCONFIRMATION or SHERB_NOPROGRESSUI);
monitorthread.resume;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
monitorthread:=TFileChangeNotify.Create(false);
end;
procedure TForm1.Refresh1Click(Sender: TObject);
begin
refreshlist;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
rbinlist.width:=form1.width-8;
rbinlist.height:=form1.height-48;
end;
procedure TForm1.file1Click(Sender: TObject);
begin
if rbinlist.SelCount0 then
begin
restore1.enabled:=true;
Delete1.enabled:=true;
end
else
begin
restore1.enabled:=false;
Delete1.enabled:=false;
end;
end;
procedure TForm1.SelectAll1Click(Sender: TObject);
var
i:integer;
begin
for i:= 0 to rbinlist.Items.Count-1 do
rbinlist.Items[i].Selected:=true;
end;
procedure TForm1.InvertSelection1Click(Sender: TObject);
var
i:integer;
begin
for i:= 0 to rbinlist.Items.Count-1 do
rbinlist.Items[i].Selected:=not(rbinlist.Items[i].Selected);
end;
procedure tform1.Restorefiles;
var
i:integer;
sname:string;
dname:string;
begin
monitorthread.Suspend;
for i:=0 to rbinlist.Items.Count-1 do
begin
if rbinlist.Items[i].Selected=true then
begin
sname:=ExtractFileDrive(rbinlist.Items[i].SubItems[0]) + '\Recycled\DC'+rbinlist.Items[i].SubItems[1]+ExtractFileExt(rbinlist.Items[i].caption);
dname:=rbinlist.Items[i].SubItems[0]+rbinlist.Items[i].caption;
MoveFile(pchar(sname),pchar(dname));
updateinfo(dname);
end;
end;
monitorthread.Resume;
end;
procedure TForm1.Restore1Click(Sender: TObject);
begin
restorefiles;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if qhINVALID_HANDLE_VALUE then
FindCloseChangeNotification(qh);
monitorthread.Terminate;
end;
procedure TForm1.Close1Click(Sender: TObject);
begin
form1.close;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
refreshlist;
end;
procedure TForm1.Delete1Click(Sender: TObject);
begin
deletefiles;
end;
end.