Einzelnen Beitrag anzeigen

Benmik

Registriert seit: 11. Apr 2009
486 Beiträge
 
Delphi 10.4 Sydney
 
#1

Datei aus dem Papierkorb wiederherstellen

  Alt 26. Aug 2014, 23:50
Ü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;

Geändert von Benmik (26. Aug 2014 um 23:57 Uhr) Grund: Parameter klargestellt
  Mit Zitat antworten Zitat