Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Datei aus dem Papierkorb wiederherstellen (https://www.delphipraxis.net/181581-datei-aus-dem-papierkorb-wiederherstellen.html)

Benmik 26. Aug 2014 23:50

Datei aus dem Papierkorb wiederherstellen
 
Über dieses Thema gibt es offenbar wenig, und noch weniger in Delphi. Nach vieler Mühe habe ich eine funktionsfähige Lösung zusammengebastelt.
Natürlich ist sie fast vollständig aus dem Internet zusammengeklaubt, im Wesentlichen von hier.
Eine fertige, funktionsfähige Lösung von hier konnte ich nicht benutzen, da sie eine höhere Delphi-Version als 2009 voraussetzt.
Der folgende Code funktioniert unter Windows Vista und Windows 7, sehr wahrscheinlich auch unter Windows 8.1.
Für die Lösung mit TList habe ich mich mit dem hier auseinandergesetzt und dann die schlichteste Lösung gewählt. Vermutlich gibt es noch einiges Verbesserungspotenzial, aber für mich reicht es. Die Funktion zum Auflisten aller Dateien im Papierkorb kann leicht herausgelöst werden.

Der Parameter "Dateiname" muss den Namen und den vollständigen Pfad der gelöschten Datei an ihrem Ursprungsort enthalten.

Delphi-Quellcode:

uses COMObj,shlobj,ActiveX;

type
  PPIDLItem = ^TPIDLItem;
  TPIDLItem = record
    Dateiname : string;
    IDL      : PItemIDList;
  end;

function PapierkorbDateiWiederherstellen(Dateiname:string):Boolean;
var
  DeskDirI, RecycleI: IShellFolder;
  pReIDL, pItemIDL: PItemIDList;
  CmInfo: CMINVOKECOMMANDINFO;
  ContextI: IContextMenu;
  PIDLListe:TList;
  PPIDL:PPIDLItem;
  i:integer;
//------------------------------------------------------------------------------------------------------------------------------------------
  procedure PapierkorbDateienAuflisten;
  var
    DeskDirI, RecycleI: IShellFolder;
    pReIDL, pNextIDL: PItemIDList;
    EnumList: IENUMIDLIST;
    IsThere: Cardinal;
    StrRet: TStrRet;
    parName: String;
    PPIDL:PPIDLItem;
  begin
    OleCheck(SHGetDesktopFolder(DeskDirI));
    OleCheck(SHGetSpecialFolderLocation(Application.Handle, CSIDL_BITBUCKET, pReIDL));
    OleCheck(DeskDirI.BindToObject(pReIDL, nil, IShellFolder, RecycleI));
    CoTaskMemFree(pReIDL);
    OleCheck(RecycleI.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumList));
    while EnumList.Next(1, pNextIDL, IsThere) = S_OK do begin
      If IsThere > 0 then begin
        try
          OleCheck(RecycleI.GetDisplayNameOf(pNextIDL, SHGDN_NORMAL, StrRet));
        except
          CoTaskMemFree(pNextIDL);
          // Be sure to Free the memory
        end;
        case StrRet.uType of
          STRRET_CSTR: parName := StrRet.cStr;
          STRRET_OFFSET: parName := PChar(Cardinal(pNextIDL)+StrRet.uOffset);
          STRRET_WSTR: parName := StrRet.pOleStr;
        end;
      end;
      If pNextIDL <> nil then begin
        New(PPIDL);
        PPIDL^.Dateiname := parName;
        PPIDL^.IDL := pNextIDL;
        PIDLListe.Add(PPIDL);
      end;
    end;
  end;
//------------------------------------------------------------------------------------------------------------------------------------------
  procedure LeerePIDLListe;
  begin
    While PIDLListe.Count > 0 do begin
      PPIDL := PPIDLItem(PIDLListe[0]);
      PPIDL^.Dateiname := '';
      PIDLListe.Delete(0);
      Dispose(PPIDL);
    end;
    FreeAndNil(PIDLListe);
  end;
//------------------------------------------------------------------------------------------------------------------------------------------
begin
  Result := False;
  PIDLListe := TList.Create;
  Try
    OleCheck(SHGetDesktopFolder(DeskDirI));
    OleCheck(SHGetSpecialFolderLocation(Application.Handle, CSIDL_BITBUCKET, pReIDL));
    OleCheck(DeskDirI.BindToObject(pReIDL, nil, IShellFolder, RecycleI));// get Recycle shell folder
    CoTaskMemFree(pReIDL);
    // code above gets the Recycle Bin IShellFoldr Interface in RecycleI
    PapierkorbDateienAuflisten;
    For i := 0 to PIDLListe.Count - 1 do begin
      If SameText(PPIDLItem(PIDLListe[i])^.Dateiname,Dateiname) then begin
        pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
        break;
      end;
      If i = PIDLListe.Count - 1 then begin
        LeerePIDLListe;
        exit;
      end;
    end;
  Except
    LeerePIDLListe;
    exit;
  End;
  If pItemIDL <> nil then begin
    try
      ZeroMemory(@CmInfo, SizeOf(CmInfo));
      with CmInfo do begin
        cbSize:= SizeOf(CmInfo);
        fMask:= CMIC_MASK_FLAG_NO_UI;
        // this fmask of NO_UI is suppose to NOT show the "Do You want to?" dialog box
        hwnd:= Application.Handle;
        lpVerb:= 'undelete'; // restore the recycle bin item
        nShow:= SW_SHOWDEFAULT;
      end;
      OleCheck(RecycleI.GetUIObjectOf(Application.Handle, 1, pItemIDL, IID_IContextMenu, nil, ContextI));
      OleCheck(ContextI.InvokeCommand(CmInfo));
    Except
      CoTaskMemFree(pItemIDL);
      LeerePIDLListe;
      exit;
    end;
  end;
  LeerePIDLListe;
  // Result := True;
  Result := FileExists(Dateiname);
end;

Dejan Vu 27. Aug 2014 07:52

AW: Datei aus dem Papierkorb wiederherstellen
 
Vorneweg: Top!

Konvertiere das doch in eine Klasse. Einfach die lokalen Prozeduren in private Methoden überführen und die Hauptprozedur als public deklarieren.
Dann würde ich für das IDL-Zeugs kein Record nehmen, sondern eine Klasse und das in eine TObjectList packen. Damit ist das aufräumen erledigt (OwnsObject = true).
Deine Prozedur muss aufgeräumt werden. Ein 'try..finally LeerePIDLListe end' um alles herum erspaart dir die einzelnen Aufruf von 'LeerePIDLListe', denn bei einem 'exit' wird vorher der finally-Abschnitt aufgerufen.
Und dann würde ich jeden einzelnen Schritt in der Prozedur in eine eigene Methode packen, z.B. aus :
Delphi-Quellcode:
// code above gets the Recycle Bin IShellFoldr Interface in RecycleI
PapierkorbDateienAuflisten;
For i := 0 to PIDLListe.Count - 1 do begin
  If SameText(PPIDLItem(PIDLListe[i])^.Dateiname,Dateiname) then begin
    pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
    break;
  end;
If i = PIDLListe.Count - 1 then begin
// das ist eh falsch, denn i ist = PIDLListe.Count, wenn nichts gefunden wurde
  // LeerePIDLListe;
  exit;
end;
wird (was passiert denn den da?)
Delphi-Quellcode:
Const
  NotFound = -1;
...
  i := FindeNameInListe(Dateiname);
  if i = NotFound then exit; // 
  pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
  ...
und
Delphi-Quellcode:
function TPapierkorb.FindeNameInListe (const Dateiname : String) : Integer;
Begin
  For result := 0 to PIDLListe.Count - 1 do
    If SameText(PPIDLItem(PIDLListe[result])^.Dateiname,Dateiname) then
      exit;

  Result := -1 // nicht gefunden
End;
Extrahiere die Einzelschritte so, das jeder Schritt genau einen kleinen Beitrag zur Gesamtlösung liefert. Hier: "Sucht einen Dateinamen in der Liste und liefert den Index oder -1, wenn der Name nicht gefunden wurde". Mehr macht das Teil nicht und mehr muss es auch nicht machen.

Deine Routine sähe dann in etwa so aus:
Delphi-Quellcode:
Procedure TPapierkorb.StelleDateiWiederher(const Dateiname : String);
...
begin
  Result := False;
  Try
    PIDLListe := TObjectList.Create(true);
    RecycleI := GetRecycleBinInterace();
    PapierkorbDateienAuflisten (PIDLListe);
    i := FindeNameInListe(Dateiname);
    if i=-1 then exit; // 
    pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
   
    If pItemIDL <> nil then
      RecycleFile(RecycleI, pItemIDL);
    Result := FileExists(Dateiname);
  finally
    PIDLListe.Free;
  end
end;
Das ist immer noch komplex (aus Sicht eines pingeligen Softwarearchitekten), aber wenn Du soweit bist, kann man noch weiter am Code rumschrauben, damit er verständlicher wird. Ziel sollte es sein, den Code ohne Kommentare intuitiv zu verstehen.
Eins zum Schluss: Ich habe deutsche und englische Bezeichnernamen vermischt: Ganz großer Käse! Entscheide dich für eine Sprache und dann zieh das durch. Vermeide Abkürzungen, außer, sie entsprechen dem Fachjargon ('PIDL')

Benmik 27. Aug 2014 12:41

AW: Datei aus dem Papierkorb wiederherstellen
 
Hallo Dejan Vu, vielen Dank für deinen wirklich guten Kommentar. Auch der ist top! :)

Fast alle deine Anmerkungen hatte ich mir auch vorher durch den Kopf gehen lassen und ich finde sie richtig. Ich muss aber erklärend anmerken, dass nach dem vielen Herumsuchen und -probieren ich nachts um eins wenig Lust hatte, den Code einzustellen. Da ich aber schon so viel von der DP profitiert habe und wusste, du machst es gleich oder gar nicht, habe ich den Code einfach rasch reingehauen. Er löst das eigentliche Problem und es ist für jedermann kinderleicht, ihn den eigenen Wünschen und Bedürfnissen anzupassen.

Zu deinen Anmerkungen:
  1. Klasse: Das war sonnenklar, dass der Profi (bin ich ja nicht) alles mit Klassen macht (machen muss, sonst fühlt er sich nicht gut!). Ich bleibe (mit schlechtem Gewissen) gern bei meinen schlichten Prozedurchen und Funktiönchen, weil sie einfach und praktisch sind (vor allem beim Reinkopieren in den eigenen Code).
  2. Records 1: Das Gleiche! Records sind out und der Profi nimmt Klassen. Nach mehreren Diskussionen hierüber in der DP (siehe vor allem hier) liebe ich immer noch meine kleinen bescheidenen Recordchen und bin da anscheinend auch nicht der einzige.
  3. Records 2: Ich hatte stark mit einer TObjectList geliebäugelt, insbesondere wegen OwnsObject. Dann habe ich aber einen (englischen) Beitrag gelesen, wo jemand behauptete, er habe den Quelltext von TObjectList durchgesehen und dort werde trotz OwnsObject gar nichts freigegeben. Da habe ich mir gedacht, wenn du sowieso das altmodische Zeugs nimmst, dann baust du dir auch eine idiotensichere Lösung (daher auch
    Delphi-Quellcode:
    PPIDL^.Dateiname := '';
    ).
  4. Einzelschritte: Unbedingt! Mache ich eigentlich sonst immer. Insbesondere, weil ich Code Folding für die segensreichste Neuerung der IDE halte und Einzelschritte das Debuggen so erleichtern. Was mich nur irritiert, ist, dass der Code der Profis hier diesen Grundsatz eigentlich so gut wie nie beherzigt. Und der Sourcecode von großen kommerziellen Programmen tut das auch nicht, da sieht man ellenlangen Spaghetticode, allenfalls unterbrochen von hinweisenden Kommentaren.
  5. "...das ist eh falsch, denn i ist = PIDLListe.Count, wenn nichts gefunden wurde" stimmt meiner Meinung nach nicht, der Code ist richtig. Erster Kandidat dennoch für eine Zerlegung in Einzelschritte.
  6. "...denn bei einem 'exit' wird vorher der finally-Abschnitt aufgerufen." Echt? Tatsächlich! Da erhebt sich nebenbei die Frage, wie man den langgehegten Wunsch vieler Delphi-Anwender nach einer try..except..finally-Konstruktion am besten realisiert. Doppeltes "try"?
  7. Deutsch/Englisch: Stimmt auch. Ich habe das englische Original (hier!) zum Teil gelassen, weil ich mich genierte, den fremden Code so total zu vereinnahmen. Ist vielleich Quatsch.
Ausblick: Vielleicht setze ich mich dran und bastle ein paar Klassen, und sei es nur zum Üben. Ein Vorteil wäre (sogar für mich), dass man dann noch ein paar Funktionalitäten einbauen könnte (beispielsweise glaube ich, dass die Auflistung der Dateien im Papierkorb für sich allein für viele interessant ist). Ansonsten tut es vielleicht der Nächste, der den Code benutzt? :)

Dejan Vu 27. Aug 2014 13:11

AW: Datei aus dem Papierkorb wiederherstellen
 
Ich glaube, das das mit dem kleinen Fehler stimmt(e). Ich mach seit einiger Zeit nix mit Delphi, aber soweit ich mich erinnere gilt folgendes:

Delphi-Quellcode:
for i:=0 to Grenze do begin ... end;
   
// hier ist i>Grenze
// Es wäre denkbar, das i auch <0 ist. wenn die Reihenfolge keine Rolle spielt.
// Aber i sollte nicht =Grenze sein. Probiere es mal aus
Aber ist es nicht so, das der Compiler eine Warnung ausspuckt, i sei nach dem Ende der Schleife undefiniert??? ;-)

Benmik 27. Aug 2014 13:52

AW: Datei aus dem Papierkorb wiederherstellen
 
Bei einer Schleife
Delphi-Quellcode:
For i := 0 to PIDLListe.Count - 1
kann i maximal den Wert PIDLListe.Count - 1 erreichen. i bleibt definiert, da innerhalb der For-Schleife; dafür muss das Erreichen von PIDLListe.Count - 1 unschöner Weise bei jedem Durchlauf abgeprüft werden.

Dejan Vu 27. Aug 2014 13:59

AW: Datei aus dem Papierkorb wiederherstellen
 
Jaha, aber wie sieht denn i *hinter* der Schleife aus? Ist verboten, ich weiß, aber trotzdem :-)
Delphi-Quellcode:
for i:=1 to Grenze do begin
  foo(i)
  end;
// Welchen Wert hat 'i' hier?
...
// ist äquivalent zu
...
i := 1;
while i<=Grenze do begin
  foo(i);
  inc(i);
end;
// Welchen Wert hat 'i' hier?
Zitat:

Zitat von Benmik (Beitrag 1269991)
dafür muss das Erreichen von PIDLListe.Count - 1 unschöner Weise bei jedem Durchlauf abgeprüft werden.

Es bleibt ja auch nichts anderes übrig. Nur das das Schleifenende einmalig ausgerechnet wird. Also wird nicht jedesmal geschaut, wie lang die Liste denn nun ist und dann 1 abgezogen...

Benmik 27. Aug 2014 19:28

AW: Datei aus dem Papierkorb wiederherstellen
 
1. Hinter For..end ist die Schleifenvariable definitionsgemäß undefiniert.
2. Bei einer While-Konstruktion ist i immer definiert, da es sich um eine initialisierte Variable handelt. Hier dürfte man übrigens auch eine globale Variable verwenden, was bei For nicht erlaubt ist.

Benmik 27. Aug 2014 19:45

AW: Datei aus dem Papierkorb wiederherstellen
 
So, jetzt hat es mich natürlich doch gejuckt und ich habe das Ganze OOP-mäßig in Klassen verpackt.
Wie erwähnt, hat mich die Erweiterbarkeit gereizt.
Das Ganze hat jetzt 5 Funktionalitäten:
  1. Anzahl der Dateien im Papierkorb ermitteln
  2. Liste aller Dateien im Papierkorb erstellen (mit Filterfunktion!)
  3. Datei in den Papierkorb verschieben
  4. Datei aus dem Papierkorb wiederherstellen
  5. Papierkorb leeren

Delphi-Quellcode:
unit Papierkorb;

interface

uses Windows,Contnrs,Forms,Classes,SysUtils,ShellAPI,Masks,COMObj,shlobj,ActiveX;

type
  TPIDLItem = class
  private
    FDateiname: String;
    FIDL     : PItemIDList;
  protected
  public
end;

type
  TPapierkorb = class
  private
    FPIDLListe: TObjectList;
    FDeskDirI : IShellFolder;
    FRecycleI : IShellFolder;
    FpReIDL  : PItemIDList;
    FpNextIDL : PItemIDList;
    FpItemIDL : PItemIDList;
    FEnumList : IENUMIDLIST;
    FCmInfo  : CMINVOKECOMMANDINFO;
    FContextI : IContextMenu;
    FIsThere : Cardinal;
    FStrRet  : TStrRet;
    FparName : String;
    FPIDLItem : TPIDLItem;
    procedure  SetzePapierkorbInterface;
    procedure  NeueDatei(var PPIDLItem:TPIDLItem);
    function   ListePapierkorbDateienAuf(Maske:string = ''):Boolean;
    function   PKDateiWiederhergestellt(ListNr:integer;Dateiname:string):Boolean;
    function   DateiInPKGefunden(Dateiname:string;var ListNr:integer):Boolean;
    function   VerschiebeDateiInPK(var Dateiname: string;PlusNull:Boolean):Boolean;
  protected
  public
    constructor Create();
    destructor Destroy(); override;
    function   ErstellePKDateiListe(const DateiListe:TStringList;Maske:string = ''):Boolean;
    function   StellePKDateiWiederHer(Dateiname:string):Boolean;
    function   ErmittleAnzPKDateien(Maske:string = ''):integer;
    function   LeerePapierkorb:Boolean;
    function   DateiInPapierkorb(Dateiname: string): Boolean;
end;
function SHEmptyRecycleBin(Wnd:HWnd; LPCTSTR:PChar; DWORD:Word):Integer; stdcall;
function SHEmptyRecycleBin; external 'SHELL32.DLL' name 'SHEmptyRecycleBinA';

implementation

constructor TPapierkorb.Create;
begin
  inherited Create;
  FPIDLListe := TObjectList.Create;
end;

destructor TPapierkorb.Destroy;
begin
  FPIDLListe.Free;
  FPIDLListe := nil;
  inherited;
end;

function TPapierkorb.ErstellePKDateiListe(const DateiListe:TStringList;Maske:string = ''):Boolean;
var i:integer;
begin
  SetzePapierkorbInterface;
  Result := ListePapierkorbDateienAuf(Maske);
  If Result then begin
    For i := 0 to FPIDLListe.Count - 1 do
      DateiListe.Add(TPIDLItem(FPIDLListe[i]).FDateiname);
  end;
end;

function TPapierkorb.StellePKDateiWiederHer(Dateiname:string):Boolean;
var ListNr:integer;
begin
  SetzePapierkorbInterface;
  ListePapierkorbDateienAuf;
  Result := DateiInPKGefunden(Dateiname,ListNr) and PKDateiWiederhergestellt(ListNr,Dateiname);
end;

function TPapierkorb.ErmittleAnzPKDateien(Maske:string = ''):integer;
begin
  SetzePapierkorbInterface;
  If ListePapierkorbDateienAuf(Maske)
    then Result := FPIDLListe.Count
    else Result := -1;
end;

function TPapierkorb.DateiInPKGefunden(Dateiname:string;var ListNr:integer):Boolean;
var i:integer;
begin
  ListNr := -1;
  Try
    For i := 0 to FPIDLListe.Count - 1 do begin
      If SameFileName(TPIDLItem(FPIDLListe[i]).FDateiname,Dateiname) then begin
        ListNr := i;
        break;
      end;
    end;
  Finally
    Result := (ListNr > -1);
  End;
end;

function TPapierkorb.PKDateiWiederhergestellt(ListNr:integer;Dateiname:string):Boolean;
begin
  Try
    FpItemIDL := TPIDLItem(FPIDLListe[ListNr]).FIDL;
    If FpItemIDL <> nil then begin
      ZeroMemory(@FCmInfo, SizeOf(FCmInfo));
      FCmInfo.cbSize:= SizeOf(FCmInfo);
      FCmInfo.fMask:= CMIC_MASK_FLAG_NO_UI;
      FCmInfo.hwnd:= Application.Handle;
      FCmInfo.lpVerb:= 'undelete';
      FCmInfo.nShow:= SW_SHOWDEFAULT;
      OleCheck(FRecycleI.GetUIObjectOf(Application.Handle, 1, FpItemIDL, IID_IContextMenu, nil, FContextI));
      OleCheck(FContextI.InvokeCommand(FCmInfo));
    end;
  Except
    CoTaskMemFree(FpItemIDL);
  end;
  // Result := True;
  Result := FileExists(Dateiname);
end;

function TPapierkorb.ListePapierkorbDateienAuf(Maske:string = ''):Boolean;
begin
  Result := True;
  Try
    OleCheck(FRecycleI.EnumObjects(Application.Handle, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, FEnumList));
    While FEnumList.Next(1, FpNextIDL, FIsThere) = S_OK do begin
      If FIsThere > 0 then begin
        OleCheck(FRecycleI.GetDisplayNameOf(FpNextIDL, SHGDN_NORMAL, FStrRet));
        case FStrRet.uType of
          STRRET_CSTR:  FparName := FStrRet.cStr;
          STRRET_OFFSET: FparName := PChar(Cardinal(FpNextIDL) + FStrRet.uOffset);
          STRRET_WSTR:  FparName := FStrRet.pOleStr;
        end;
      end;
      If FpNextIDL <> nil then begin
        If (Maske = '') or MatchesMask(FparName,Maske) then begin
          FPIDLItem := TPIDLItem.Create;
          FPIDLItem.FDateiname := FparName;
          FPIDLItem.FIDL := FpNextIDL;
          NeueDatei(FPIDLItem);
        end;
      end;
    end;
  except
    Result := False;
  end;
  CoTaskMemFree(FpNextIDL);
end;

procedure TPapierkorb.NeueDatei(var PPIDLItem:TPIDLItem);
begin
  FPIDLListe.Add(PPIDLItem);
end;

function TPapierkorb.LeerePapierkorb:Boolean;
const
  SHERB_NOCONFIRMATION = $00000001;
  SHERB_NOPROGRESSUI = $00000002;
  SHERB_NOSOUND = $00000004;
begin
  Result := (SHEmptyRecycleBin(0, nil, SHERB_NOCONFIRMATION or SHERB_NOPROGRESSUI or SHERB_NOSOUND) = 0);
end;

function TPapierkorb.DateiInPapierkorb(Dateiname: string): Boolean;
begin
  Result := FileExists(Dateiname);
  If Result then begin
    // Erst kein, dann ein, und dann zwei Nullzeichen hinter den Dateinamen setzen -> drei Mal ist Bremer Recht!
    Result := VerschiebeDateiInPK(Dateiname,False);
    If not Result then begin
      Result := VerschiebeDateiInPK(Dateiname,True);
      If not Result
        then Result := VerschiebeDateiInPK(Dateiname,True);
    end;
  end;
end;

function TPapierkorb.VerschiebeDateiInPK(var Dateiname: string;PlusNull:Boolean):Boolean;
var DatStrukt: TSHFileOpStruct; Ergebnis:integer;
begin
  // Es müssen ZWEI Nullzeichen am Dateiende sein, das klappt nicht immer
  If PlusNull
    then Dateiname := Dateiname + #0;
  FillChar(DatStrukt, SizeOf(DatStrukt), 0);
  DatStrukt.wFunc := FO_DELETE;
  DatStrukt.pFrom := PChar(Dateiname);
  DatStrukt.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_SILENT;
  Ergebnis := ShFileOperation(DatStrukt);
  Result := (Ergebnis = 0);
end;

procedure TPapierkorb.SetzePapierkorbInterface;
begin
  OleCheck(SHGetDesktopFolder(FDeskDirI));
  OleCheck(SHGetSpecialFolderLocation(Application.Handle, CSIDL_BITBUCKET, FpReIDL));
  OleCheck(FDeskDirI.BindToObject(FpReIDL, nil, IShellFolder, FRecycleI));
  CoTaskMemFree(FpReIDL);
end;

end.
Ausprobieren kann man das mit einem neuen Projekt, dazu eine Listbox, drei Buttons und ein Edit auf die Form bringen, TPapierkorb einbinden und dann:
Delphi-Quellcode:
uses Papierkorb;

procedure TForm1.Button1Click(Sender: TObject);
var PK:TPapierkorb; Liste:TStringList;
begin
  ListBox1.Clear;
  Liste := TStringList.Create;
  Liste.Sorted := True;
  Form1.Position := poDesktopCenter;
  PK := TPapierkorb.Create;
  PK.ErstellePKDateiListe(Liste,Edit1.Text);
  ListBox1.Items.Assign(Liste);
  PK.LeerePapierkorb;
  PK.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var PK:TPapierkorb;
begin
  ListBox1.Clear;
  Form1.Position := poDesktopCenter;
  PK := TPapierkorb.Create;
  ListBox1.Items.Add('Es sind ' + IntToStr(PK.ErmittleAnzPKDateien(Edit1.Text)) + ' Dateien gemäß Ihren Kriterien im Papierkorb vorhanden.');
  PK.Free;
end;

procedure TForm1.Button3Click(Sender: TObject);
var PK:TPapierkorb;
begin
  If ListBox1.ItemIndex = -1 then begin
    ShowMessage('Scherzkeks! Kein Eintrag ausgewählt!    ');
  end else begin
    PK := TPapierkorb.Create;
    If PK.StellePKDateiWiederHer(ListBox1.Items[ListBox1.ItemIndex])
      then Showmessage('Die Datei' + Chr(13) + Chr(13) + ListBox1.Items[ListBox1.ItemIndex] + Chr(13) + Chr(13) + 'wurde wiederhergestellt.  ')
      else Showmessage('Die Datei' + Chr(13) + Chr(13) + ListBox1.Items[ListBox1.ItemIndex] + Chr(13) + Chr(13) + 'konnte nicht wiederhergestellt werden.  ');
    PK.Free;
  end;
end;
Eine Sache ist mir unklar: Muss der Anwender
Delphi-Quellcode:
Free
aufrufen?

hoika 27. Aug 2014 21:04

AW: Datei aus dem Papierkorb wiederherstellen
 
Hallo,

ja, solange nicht mit Interfaces gearbeitet wird.

Die Sache mit dem i hinter der For-Schleife ist leicht erklärt.
Deine Code-Formatierung sah so aus, als ob du auf die Schleifenvariable nach der For-Schleife zugreifst,
hast du aber nicht.

Delphi-Quellcode:
PapierkorbDateienAuflisten;
For i := 0 to PIDLListe.Count - 1 do
begin
  If SameText(PPIDLItem(PIDLListe[i])^.Dateiname,Dateiname) then
  begin
    pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
    break;
  end;
  If i = PIDLListe.Count - 1 then
  begin
    // das ist eh falsch, denn i ist = PIDLListe.Count, wenn nichts gefunden wurde
    // LeerePIDLListe;
    exit;
  end;
Heiko

himitsu 27. Aug 2014 21:23

AW: Datei aus dem Papierkorb wiederherstellen
 
Wir wäre es, wenn man einfach das prüft, was man prüfen wollte?
"Wurde nichts gefunden?" statt "Bin ich am Ende der Liste?"

Delphi-Quellcode:
pItemIDL := nil;
For i := 0 to PIDLListe.Count - 1 do
  If SameFileName(PPIDLItem(PIDLListe[i])^.Dateiname, Dateiname) then begin
    pItemIDL := PItemIDList(PPIDLItem(PIDLListe[i])^.IDL);
    break;
  end;
If not Assigned(pItemIDL) then begin
  // LeerePIDLListe;
end;
Delphi-Referenz durchsuchenSameFileName :angel:


Und die Fehlerbehandlung im ersten Post ist echt grausam.
  • Resourcenschutzblöcke fehlen komplett
    Delphi-Quellcode:
    OleCheck(SHGetSpecialFolderLocation(Application.Handle, CSIDL_BITBUCKET, pReIDL));
    OleCheck(DeskDirI.BindToObject(pReIDL, nil, IShellFolder, RecycleI));
    CoTaskMemFree(pReIDL);
    Wer gibt pReIDL frei, wenn es in BindToObject knallt?
  • Und die Try-Except sind das Schlimmste, was ich je gesehn hab.
    Exceptions werden zwar abgefangen, aber dann ohne Behandlung und vorallem ohne Auswertung/Anzeige der Fehlerursache einfach weggeworfen.
    Da wäre es besser gewesen, wenn man einfach ganz darauf verzichtet hätte.
  • OK, wenigstens wurden via OleCheck die Rückgabewerte geprüft, was schonmal ein Anfang ist,
    aber da dann der ausgelöste Fehler praktisch iignoriert wird, ist es praktisch nutzlos, aber wenigstens sorgt es dafür, daß der Nachfolgende Code (bis zum nächsten Except) nicht fehlerhaft ausgeführt wird. :angel:

Dalai 27. Aug 2014 22:14

AW: Datei aus dem Papierkorb wiederherstellen
 
Warum ist
Delphi-Quellcode:
DateiListe
der Methode
Delphi-Quellcode:
TPapierkorb.ErstellePKDateiListe
ein
Delphi-Quellcode:
var
-Parameter? Stattdessen gehört da ein
Delphi-Quellcode:
const
hin, weil der Zeiger auf die Liste konstant zu bleiben hat; Strings hinzufügen kann man trotzdem. Ich weiß, meckern ist immer einfach ;).

MfG Dalai

Benmik 27. Aug 2014 23:28

AW: Datei aus dem Papierkorb wiederherstellen
 
Bei himitsu kann man sich darauf verlassen, dass bei Schlampereien in puncto Speicherlecks und Fehlerbehandlung nicht das Florett, sondern der Morgenstern oder gleich die Pumpgun rausgeholt wird! :thumb:

Zitat:

Und die Try-Except sind das Schlimmste, was ich je gesehn hab.
Besser so ein Rekord als gar keiner...
Zitat:

...sorgt es dafür, daß der Nachfolgende Code (bis zum nächsten Except) nicht fehlerhaft ausgeführt wird.
Und genau das war mein Ziel, das Programm soll nicht knallen. Behandlung und Fehlerergründung und gar noch ausführliche Interaktion hierüber mit dem armen Anwender waren nicht mein Ziel, was soll es hier bringen? Durch den Rückgabewert weiß der Programmierer, dass es nicht geklappt hat, und was er dann tut und was er dem Anwender sagt, ist seine Sache.
Zitat:

SameFileName
Hm. Wenns die Funktion gibt, dann soll man sie wohl auch verwenden.

Hallo Dalai, du hast Recht.

Dejan Vu 28. Aug 2014 06:34

AW: Datei aus dem Papierkorb wiederherstellen
 
Bezüglich Fehlerbehandlung geht man eigentlich davon weg, den Anwender einer Methode durch Rückgabewerte über den Erfolg oder Misserfolg zu informieren. Stattdessen werden Exceptions eingesetzt. Der Grund ist einfach: Der Code ist lesbarer.
Delphi-Quellcode:
// Statt:
var
  r : TMethodResult;

begin
  r := ThisMethod();
  if r = Success then begin
    r := ThatMethod();
    if r = Success then
      DoSomething
    else
      ErrorHandling(r);
  end else
    ErrorHandling(r);
...
// Lieber
  Try
    ThisMethod();
    ThatMethod();
    DoSomething();
  Except
    On e:EMyMethodException do
      ErrorHandling(e);
  End
Wenn Du also noch eine EPapierkorb-Exception Klasse deklarierst und dann in dieser Exception den genauen Grund des Scheiterns lieferst, kann der Anwender die sehr elegante und -finde ich- einfacher lesbarere zweite Variante verwenden.

Und das mit der For-Schleife... Decke bitte den Mantel der Nächstenliebe über meinen Einwand. Danke hoika. :oops:

himitsu 28. Aug 2014 09:50

AW: Datei aus dem Papierkorb wiederherstellen
 
Zitat:

Zitat von Benmik (Beitrag 1270060)
Besser so ein Rekord als gar keiner...

Oder besser nichts/weniger, als etwas Schlimmes.

* Auto mit Airbag
* Auto ohne Airbag
* Auto mit nicht funktionierendem Airbag, wo alle denken "ich brauch mich nicht anschnallen ... bin ja geschützt"

Ob ein bissl, ein bissl mehr oder der Superschutz, ist erstmal egal,
aber grob fahrlässigen Pfusch sollte man doch besser lassen.

Sir Rufo 28. Aug 2014 10:06

AW: Datei aus dem Papierkorb wiederherstellen
 
Und ich dachte immer, dass ein Airbag nur dann schützt, wenn man angeschnallt ist. Ohne Anschnallen ist das Verletzungsrisiko mit Airbag sogar höher.

http://www.unfallzeitung.de/zeitung/...e-alleskoenner

himitsu 28. Aug 2014 10:25

AW: Datei aus dem Papierkorb wiederherstellen
 
Das ist ein Superairbag, der kann das. :stupid:

Sir Rufo 28. Aug 2014 10:31

AW: Datei aus dem Papierkorb wiederherstellen
 
Zitat:

Zitat von himitsu (Beitrag 1270111)
Das ist ein Superairbag, der kann das. :stupid:

Den kenn ich http://www.youtube.com/watch?v=RnyhkBU1yaw

himitsu 28. Aug 2014 10:33

AW: Datei aus dem Papierkorb wiederherstellen
 
Genau der :lol:

DeddyH 28. Aug 2014 10:35

AW: Datei aus dem Papierkorb wiederherstellen
 
Tut mir einen Gefallen und friert mich bitte wieder ein :mrgreen:

Nu aber genug OT, oder?

Benmik 28. Aug 2014 14:14

AW: Datei aus dem Papierkorb wiederherstellen
 
Wie ich bereits schrieb, ist der entscheidende Code im ersten Post nicht von mir. Er ist von einem Delphi-Experten mit "Genius"-Status, 1.594.234 Punkten und 1.327 akzeptierten Lösungen. Er hat seinen Code vorgestellt als etwas, das ein Problem löst, damit die Hauptarbeit leistet, und die Basis für die eigene Ausarbeitung liefert. Reaktionen auf seine freundliche Hilfe a la "sind das Schlimmste, was ich je gesehn hab" und "grob fahrlässigen Pfusch sollte man doch besser lassen" hat er im Gegensatz zu mir nicht bekommen. Ich bin sicher, dass jeder, der sich genauso mit dem Problem herumschlägt wie ich es getan habe, so dankbar für meine Arbeit sein wird, wie ich es immer bin, wenn ich etwas finde; auch wenn die Vorlage nicht perfekt ist.

Mein lieber himitsu, in punkto Delphi werden dir nicht viele etwas vormachen, aber in punkto freundliche Umgangsformen ist noch extrem viel Luft nach oben. Du darfst dir sehr gern ein Beispiel an Dejan Vu nehmen, der erst Anerkennung gezollt und dann Kritik angebracht hat, und zwar konstruktive. Völlig inakzeptabel finde ich, dass du in deinem ersten Post auch noch Codeteile aus meiner ersten, bereits obsoleten Version, einer vernichtenden Kritik unterzogen hast. Das nennt man Nachtreten. Ich vermute mal, dich nerven Amateure. Soweit ich sehen kann, ist die DP aber alles andere ein exklusives Profiforum. Als jemand, der zu 99% mitliest und nur in Ausnahmefällen selbst etwas vorstellt, bin ich sicher, dass viele stille Mitleser sich jetzt noch sehr viel mehr als vorher überlegen werden, ob sie für die Allgemeinheit interessante Codestücke nicht lieber still für sich behalten. Und zum Schluss, mein lieber himitsu, ist dir mal aufgefallen, dass mein Pfusch-Code sehr nützlich ist und einfach gut funktioniert?

Dejan Vu 28. Aug 2014 15:23

AW: Datei aus dem Papierkorb wiederherstellen
 
Ich finde auch, das es zuallererst (wie schreibt man das eigentlich? zu aller erst? Erst? Egal) darum gehen sollte, so eine Leistung zu *honorieren*. Denn ich zumindest hab die Lösung so noch nicht gesehen und für mich bedeutet er einen Mehrwert. Und wenn jemand noch dazu schreibt, das er nicht so der Extremeprogrammerguru ist, dann sollte man mit Kritik vorsichtig und vor allen Dingen konstruktiv und höflich sein.

Mich z.B. könnt ihr komplett in den Boden rammen, denn ich bin ein Großmaul und wenn ich "Mist" veröffentliche, erzähle oder ausdiffundiere, kann man ruhig darüber herziehen. Das macht mir nix, im Gegenteil.

So. Benmik hat aber eigentlich alles gesagt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:32 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz