RecycleFile (Windows)

Share your advanced PureBasic knowledge/code with the community.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

RecycleFile (Windows)

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

UPDATE: See corrected code further down (dated Mon Feb 11, 2008).
The example in this first particular post is faulty and not 100% reliable.



This procedure lets you "delete" files by sending them to the Recycle Bin (also
known as the Trash Can) instead of permanently deleting them as DeleteFile does.
Note that there is a bit of a delay after calling this procedure to the time the
file(s) is recycled... I don't know if this can be sped up, but I doubt it. You
can use this with wildcards (*?) too, just like DeleteFile does. Enjoy!


; RecycleFile by PB -- do what you want with it. :)
; Usage: RecycleFile(file$)
; Same as DeleteFile() except files go to the bin.
;
Procedure RecycleFile(file$)
SHFileOp.SHFILEOPSTRUCT
SHFileOp\pFrom=@file$
SHFileOp\wFunc=#FO_DELETE
SHFileOp\fFlags=#FOF_ALLOWUNDO
SHFileOperation_(SHFileOp)
EndProcedure


PB - Registered PureBasic Coder


Edited by - PB on 17 August 2002 07:01:53
Andy
User
User
Posts: 16
Joined: Wed Jun 18, 2003 8:32 pm
Location: Switzerland

Addendum: RecycleFile (Windows)

Post by Andy »

One little thing I think should be corrected here - Microsoft write for the pFrom-value:
An additional NULL character must be appended to the end of the final name to indicate the end of pFrom.
So we need two NULLs at the end of the string. I have do this so (not so elegant, could be possibly more efficient - but it works :wink:):

Code: Select all

Procedure _RecycleFile(file$)
  ; RecycleFile by PB -- do what you want with it.  
  ; Usage: RecycleFile(file$)
  ; Same as DeleteFile() except files go to the bin.
  ; Modified by Andy (PB 3.91)
  s=Len(file$)+3
  MemoryID=AllocateMemory(s)
  For i=s-3 To s-1
    PokeB(MemoryID+i,0)
  Next
  PokeS(MemoryID,file$)
  SHFileOp.SHFILEOPSTRUCT
  SHFileOp\pFrom=MemoryID
  SHFileOp\wFunc=#FO_DELETE
  SHFileOp\fFlags=#FOF_ALLOWUNDO | #FOF_SILENT
  result = SHFileOperation_(@SHFileOp)
  FreeMemory(MemoryID)
  ProcedureReturn result
EndProcedure
Andy

12.5.04 Edit: Some little corrections... :wink:
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Addendum: RecycleFile (Windows)

Post by PB »

A belated thanks to Andy for fixing my tip: I needed this fix today. :)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

How about -

Code: Select all

Procedure RecycleFile(file$)
        SHFileOp.SHFILEOPSTRUCT
        SHFileOp\pFrom=@file$
        SHFileOp\wFunc=#FO_DELETE
        SHFileOp\fFlags=#FOF_ALLOWUNDO | #FOF_NOCONFIRMATION ; without #FOF_NOCONFIRMATION you get a messagerequester asking to confirm sending to recycle bin
        SHFileOperation_(SHFileOp)
EndProcedure
I've been using this for years, is there something I've missed?
Mike.
(I'm never going to catch up with the improvements to this program)
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

@MikeB: What you posted is basically the same code as my tip at the top of
this thread. It doesn't always work, even though I too thought it did. This is
because the filename MUST end with 2 x Chr(0) to work 100% correctly,
because Windows uses Chr(0) to separate multiple filenames. So an extra
Chr(0) is needed to signify the end of the file list.

In other words, you can recycle 2 files with one string:

file$ = "Name1"+Chr(0)+"Name2"+Chr(0)+Chr(0)

The last Chr(0) is needed, even if you only use one filename. I suffered this
problem yesterday, where the tip I gave (and you gave above) just wouldn't
recycle the files I was giving it. When I used Andy's tip, which adds the extra
required Chr(0), it all worked perfectly. I highly recommend you use it too.

In my own twisted coding way I modified Andy's addition to look like the
following, because a return value of 0 for SHFileOperation means success,
not failure. So the code below returns 0 for failure, and 1 for success.

Code: Select all

Procedure RecycleFile(file$)
  #FOF_NOERRORUI=$400 ; PureBasic doesn't recognise this constant (as of v4.20 Beta 2).
  s=Len(file$)+3 : m=AllocateMemory(s) : For p=s-3 To s-1 : PokeB(m+p,0) : Next : PokeS(m,file$)
  SHFileOp.SHFILEOPSTRUCT : SHFileOp\pFrom=m : SHFileOp\wFunc=#FO_DELETE
  SHFileOp\fFlags=#FOF_ALLOWUNDO|#FOF_NOERRORUI : ok=SHFileOperation_(SHFileOp)
  If ok=0 : ok=1 : Else : ok=0 : EndIf : FreeMemory(m)
  ProcedureReturn ok
EndProcedure
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
akj
Enthusiast
Enthusiast
Posts: 665
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

Surely the code:

Code: Select all

For p=s-3 To s-1 : PokeB(m+p,0) : Next
is redundant as the documentation for AllocateMemory() states that the memory area will be initialised with nulls.
Anthony Jordan
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> Surely [For/Next] is redundant as the documentation for AllocateMemory()
> states that the memory area will be initialised with nulls

Correct! :) Here is the amended code, now also with error-checking in case
AllocateMemory couldn't be done. Works 100% perfectly on all files I tested.

Code: Select all

Procedure RecycleFile(file$)
  #FOF_NOERRORUI=$400
  m=AllocateMemory(Len(file$)+2)
  If m
    PokeS(m,file$) : SHFileOp.SHFILEOPSTRUCT : SHFileOp\pFrom=m : SHFileOp\wFunc=#FO_DELETE
    SHFileOp\fFlags=#FOF_ALLOWUNDO|#FOF_NOERRORUI : ok=SHFileOperation_(SHFileOp) : FreeMemory(m)
    If ok=0 : ok=1 : Else : ok=0 : EndIf
  EndIf
  ProcedureReturn ok
EndProcedure
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

Thanks for the explanation, I understand what is going on now, although as far as I know it has worked in the past. However since I normally replace the file with a longer version, hence overwriting the original, it would not be obvious if it had not finished in the trashcan unless I wanted to recover it and so far I haven't. So I have been assuming it was working because it did a few years ago when I tested it! :oops:
Mike.
(I'm never going to catch up with the improvements to this program)
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> I have been assuming it was working because it did a few years ago when
> I tested it! :oops:

Same here. It did work for me in the past, too. You're not alone. But like I said,
the other day when I used it in an app, it didn't, so I don't know if PureBasic is
now doing something "correctly" or what. :)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
Blue
Addict
Addict
Posts: 884
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re:

Post by Blue »

PB wrote:> [...]
AllocateMemory couldn't be done. Works 100% perfectly on all files I tested.

Code: Select all

Procedure RecycleFile(file$)
  #FOF_NOERRORUI=$400
  m=AllocateMemory(Len(file$)+2)
  If m
    PokeS(m,file$) : SHFileOp.SHFILEOPSTRUCT : SHFileOp\pFrom=m : SHFileOp\wFunc=#FO_DELETE
    SHFileOp\fFlags=#FOF_ALLOWUNDO|#FOF_NOERRORUI : ok=SHFileOperation_(SHFileOp) : FreeMemory(m)
    If ok=0 : ok=1 : Else : ok=0 : EndIf
  EndIf
  ProcedureReturn ok
EndProcedure
For this to work in Unicode, I think StringByteLength(file$) MUST replace Len(file$) in the 2nd line of the Procedure :

Code: Select all

m=AllocateMemory(StringByteLength(file$)+4)
I was experiencing random crashes with this code until I started using StringByteLength()
"That's not a bug..." said the programmer. "it's a feature! "
"Oh! I see..." replied the blind man.
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: RecycleFile (Windows)

Post by Danilo »

Yes, or you use sizeof() combined with Len():

Code: Select all

Procedure RecycleFile(file$)
    Protected m, result, SHFileOp.SHFILEOPSTRUCT
    m = AllocateMemory( ( Len(file$)+2 ) * SizeOf(Character) )
    If m
        PokeS(m,file$)
        SHFileOp\pFrom  = m
        SHFileOp\wFunc  = #FO_DELETE
        SHFileOp\fFlags = #FOF_ALLOWUNDO|#FOF_NOERRORUI
        result = SHFileOperation_(SHFileOp)
        FreeMemory(m)
        ProcedureReturn Bool(result = 0)
    EndIf
EndProcedure
User avatar
Blue
Addict
Addict
Posts: 884
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: RecycleFile (Windows)

Post by Blue »

Danilo wrote:Yes, or you use sizeof() combined with Len():

Code: Select all

Procedure RecycleFile(file$)
    [...]
    m = AllocateMemory( ( Len(file$)+2 ) * SizeOf(Character) )
    [...]
EndProcedure
Great ! I never could think of anything really useful to do with the SizeOf() instruction.
But I see now that it can be cleverly used. :shock:
Thank you, Danilo.
This is turning out to be a good day : I learned something new ! :D
"That's not a bug..." said the programmer. "it's a feature! "
"Oh! I see..." replied the blind man.
Post Reply