Probleme mit SHFileOperation_ (delete)

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Probleme mit SHFileOperation_ (delete)

Beitrag von Agent »

Hallo.

Ich habe im Forum eine Routine gefunden, um Dateien in den Papierkorb zu verschieben:

Code: Alles auswählen

Procedure SK_RecycleFile(file$, ask.b=0, noerror.b=0, progress.b=1) ; PB3+4
  Define.l result

  ; #define FOF_SILENT      0x0004     // keine Angabe über  
  ;                                    // Fortschritt 
  ; #define FOF_NOERRORUI   0x0400     // keine Fehler-UI 
  ; #define FOF_ALLOWUNDO   0x0040     // für Papierkorb  
  ;                                    // erforderlich! 
  ; #define FOF_NOCONFIRMATION 0x0010  // keine Rückfrage

  SHFileOp.SHFILEOPSTRUCT 
  SHFileOp\pFrom        = @file$ 
  SHFileOp\wFunc        = #FO_DELETE 
  SHFileOp\fFlags       = #FOF_ALLOWUNDO
  
  If ask=0
    SHFileOp\fFlags | #FOF_NOCONFIRMATION
  EndIf
  If noerror=1
    SHFileOp\fFlags | $0400
  EndIf
  If progress=0
    SHFileOp\fFlags | #FOF_SILENT
  EndIf
  
  result = SHFileOperation_(SHFileOp) 
  
  CompilerIf #PB_Compiler_Debugger
    Debug "SK_Recyclefile: "+file$
    Debug "SK_Recyclefile: Result = "+Str(result)
  CompilerEndIf
  ; Liefert 0 (NULL) zurück wenn alles ok
  ; 1026 : Datei nicht vorhanden
  
  If result = 0
    result = #True
  EndIf
  
  ProcedureReturn result
EndProcedure 
Diese Routine funktioniert grundsätzlich. Nun möchte ich aber alle Dateien in einem Ordner löschen. Hierzu nutze ich eine kleine modifizierte Routine zum Einlesen der Dateien in eine Linklist:

Code: Alles auswählen


NewList ReadDirInfo$()

Procedure.l SK_ReadDirFast(Path.s="", SubDirs.b=1) ; PB4
  Shared ReadDirInfo$()
  Protected Dir.l
   
  If Right(Path,1)<>"\" : Path+"\" : EndIf
  Dir.l = ExamineDirectory(#PB_Any, Path, "")
  
  If IsDirectory(Dir)
    While NextDirectoryEntry(Dir)       

      name$ = DirectoryEntryName(Dir)
  
      If DirectoryEntryType(Dir) = #PB_DirectoryEntry_File
        AddElement(ReadDirInfo$())
        ReadDirInfo$() = Path + name$
        Debug "FILE: "+name$
      ElseIf DirectoryEntryType(Dir) = #PB_DirectoryEntry_Directory And SubDirs; Dir      
        Debug "DIR: "+name$
        If name$<>"." And name$<>".."
          SK_ReadDirFast(Path + name$, SubDirs)
        EndIf
      EndIf
     
    Wend
   
    FinishDirectory(Dir)  
  
  Else
    ProcedureReturn  #False 
  EndIf
  
  ProcedureReturn #True

EndProcedure 

Versuche ich nun über den Code:

Code: Alles auswählen

Debug sk_readdirfast("D:\Tests\Delete\")
ForEach  readdirinfo$()
  Debug SK_RecycleFile(readdirinfo$())
Next
alle Dateien löschen zu lassen, so werden nur ein Teil der Dateien gelöscht, alle anderen Enden mit einem Fehler 1026 von SHFileOperation. Die Dateien sind aber weder offen noch ähnliches, sie können über ein anderes beliebiges Programm gelöscht werden.

Hat jemand eine Idee?
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
Kiffi
Beiträge: 10715
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Probleme mit SHFileOperation_ (delete)

Beitrag von Kiffi »

habe mal ein wenig recherchiert. Dieser Fehler scheint öfters aufzutreten.
Und zwar anscheinend immer sporadisch (sprich: einige Dateien werden
gelöscht, andere wiederum nicht). Das Problem wird wohl darin liegen, dass
pFrom und pTo Doppelnull-terminiert sein müssen.

(In Deinem Fall natürlich nur pFrom)

Weitere Infos im Posting von Kurzer:
http://www.purebasic.fr/german/viewtopi ... 055#154055

Grüße ... Kiffi
a²+b²=mc²
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Hi Kiffi.

DAnke für die Recherche. Ist mir noch nie untergekommen.
Werde es aber mal testen!
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Es kann eine Liste von Files übergeben werden, alle 0 terminiert, der letze
00 (WC) terminiert. Wenn man nur einen übergibt, ist dies der letzte.
Die Wahrscheinlichkeit das sich im Speicher hinter diesem String eine
weitere 0 befindet ist groß, aber wie man sieht nicht immer wahr.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Hallo nochmal.

Habs getestet. Funktioniert wunderbar mit Dateien. Leider nicht mit Verzeichnissen. Was muss ich dabei beachten?
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

*Nochmal nachfrag*

Leider funzt das nicht mit Ordnern, gibt es hier was spezielles zu beachten?

Vorab danke.
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Agent hat geschrieben:*Nochmal nachfrag*

Leider funzt das nicht mit Ordnern, gibt es hier was spezielles zu beachten?

Vorab danke.
Keine Ahnung, liegt wohl an den Ordnernamen. Wahrscheinlich ohne
Backslash, aber mußte selber testen.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Kiffi
Beiträge: 10715
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

Agent hat geschrieben:Leider funzt das nicht mit Ordnern, gibt es hier was spezielles zu beachten?
funktioniert u.U. nur mit leeren Ordnern. Kannst Du das mal (neben dem
Tipp von Thomas) ausprobieren?

Grüße ... Kiffi
a²+b²=mc²
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Hallo.

Nein, lag nicht an den Backslashs. Habe das Problem aber gelöst. Thomas hat mich aber auf die Idee gebracht mit der Doppel-NULL-Terminierung.

Leider ist es damit nicht getan einfach ZWEI NULL-Bytes hintendran zu hängen, denn dann gehen zwar die Ordner, aber nicht mehr die Dateien. Also habe ich kurzum die Proc so gestaltet, das bei DAteien EINE NULL und bei Ordnern ZWEI NULLEN angehängt werden.

Die fertige Proc sieht dann so aus und läuft bisher auch gut:
Zu beachten ist hierbei natürlich, das ein Ordner in JEDEM Fall mit einem Backslash endet - dürfte aber logisch sein wenn man sich den Code betrachtet.

Code: Alles auswählen


Procedure SK_Recycle(file$, ask.b=0, noerror.b=0, silent.b=0) ; PB3+4
  Define.l result

  ; #define FOF_SILENT      0x0004     // keine Angabe über  
  ;                                    // Fortschritt 
  ; #define FOF_NOERRORUI   0x0400     // keine Fehler-UI 
  ; #define FOF_ALLOWUNDO   0x0040     // für Papierkorb  
  ;                                    // erforderlich! 
  ; #define FOF_NOCONFIRMATION 0x0010  // keine Rückfrage
  #FOF_NOERRORUI = $400
  
  If Right(file$, 1) = "\"
    Debug "adding to dir 2 ZEROS"
    file$ =  file$ + "  "
    PokeB(@file$ + Len(file$)-2, 0)  
    PokeB(@file$ + Len(file$)-1, 0)  
  Else
    Debug "adding to FILE a ZERO"
    file$ =  file$ + " "
    PokeB(@file$ + Len(file$)-1, 0)     
  EndIf
  

  SHFileOp.SHFILEOPSTRUCT 
  SHFileOp\pFrom        = @file$ 
  SHFileOp\wFunc        = #FO_DELETE 
  SHFileOp\fFlags       = #FOF_ALLOWUNDO
  
  If ask=0
    SHFileOp\fFlags | #FOF_NOCONFIRMATION
  EndIf
  If noerror=1
    SHFileOp\fFlags | #FOF_NOERRORUI
  EndIf
  If silent=1
    SHFileOp\fFlags | #FOF_SILENT
  EndIf
  
  result = SHFileOperation_(SHFileOp) 
  
  CompilerIf #PB_Compiler_Debugger
    If Right(file$, 1) = "\"
      Debug "SK_Recycle: DIR: "+file$
    Else
      Debug "SK_Recycle: FILE: "+file$
    EndIf 
  CompilerEndIf
  ; Liefert 0 (NULL) zurück wenn alles ok
  ; 1026 : Datei nicht vorhanden
  
  If result = #S_OK
    result = #True
  EndIf
  
  ProcedureReturn result
EndProcedure 
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

ADD:

Als Optimierung könnte man natürlich noch abfragen ob es sich um ein Ordner oder eine Datei handelt ;-)
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Antworten