Zu löschende Dateien mit VB6 in den Windows-Papierkorb verschieben

Veröffentlicht: 30. Mai 2005

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht? Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Wenn ich in Visual Basic 6.0 Dateien lösche, benutze ich die dafür vorgesehene Anweisung „Kill“. Damit sind die Dateien dann aber unwiederbringlich gelöscht, der Windows-Papierkorb wird schlicht ignoriert. Wie also kann ich Dateien in den Windows-Papierkorb verschieben (sofern er aktiviert ist)?

Visual Basic 6.0 kann mit reinen Bordmitteln keine Dateien in den Windows-Papierkorb verschieben. Dabei gab es den Papierkorb auch für Microsoft Windows schon mit der Vorstellung von Visual Basic 4.0, das parallel als 16-bit und erste 32-bit VB-Version zur Verfügung stand. Doch keine der beiden Versionen berücksichtigte dieses zentrale Detail, und dabei blieb es über viele Jahre hinweg auch bis zur letzten Version von Visual Basic (ohne „.NET“).

Da Visual Basic jedoch mit der offenen Möglichkeit ausgestattet ist, Funktionen des Win32-API in allen erdenklichen Lagen und Varianten zu nutzen, stellt diese Einschränkung kein wirkliches Problem dar. Denn natürlich können Sie Dateien unter Verwendung der Funktionen des Win32-API in den Papierkorb verschieben, statt sie unwiederbringlich löschen zu müssen.

Den Schlüssel zu allen möglichen Datei- und Verzeichnisoperationen stellt die Funktion SHFileOperation dar. Mit ihr können Sie Dateien und Verzeichnisse samt Windows-eigener Dialoganzeige verschieben, kopieren sowie löschen und damit in den Papierkorb verschieben (sofern dieser aktiviert ist – was nur sehr selten nicht der Fall ist, meist in entsprechend geheimhaltungsbedürftigen Umgebungen).

Wie immer beim Einsatz des Win32-API benötigen wir zunächst einige deklaratorische Zeilen, in denen Funktionen, Konstante und Typen vorab definiert werden. Der folgende Codeblock enthält viel mehr Konstantendefinitionen als die hier notwendigen – fühlen Sie sich eingeladen, den definitorisch eingeschränkten Umfang dieses Artikels mit dieser kleinen Hilfe auf eigene Initiative zu durchbrechen.

' Benötigte Typen
  
Private Type SHFILEOPSTRUCT
  hWnd      As Long
  wFunc     As Long
  pFrom     As String
  pTo       As String
  fFlags    As Integer
  fAborted  As Boolean
  hNameMaps As Long
  sProgress As String
End Type
  
  
' Benötigte und weitere, für den Leser ggf. nützliche Konstante
  
Private Const FO_MOVE As Long = &H1&     ' Dateien verschieben
Private Const FO_COPY As Long = &H2&     ' Dateien kopieren
Private Const FO_DELETE As Long = &H3&   ' Dateien in den Papierkorb verschieben
Private Const FO_RENAME As Long = &H4&   ' Dateien umbenennen
  
Private Const FOF_MULTIDESTFILES As Long = &H1&      ' Mehrere Zieldateien (für kopieren, verschieben, umbenennen)
Private Const FOF_CONFIRMMOUSE As Long = &H2&        ' Bestätigung
Private Const FOF_SILENT As Long = &H4&              ' Keine Darstellung des Löschvorgangs
Private Const FOF_RENAMEONCOLLISION As Long = &H8&   ' Falls Zielname vergeben, automatscih umbenennen
Private Const FOF_NOCONFIRMATION As Long = &H10&     ' Keine Bestätigungen anfordern
  
Private Const FOF_ALLOWUNDO As Long = &H40&              ' UNDO erlauben
Private Const FOF_FILESONLY As Long = &H80&              ' WildCards nur auf Dateien beziehen
Private Const FOF_SIMPLEPROGRESS As Long = &H100&        ' Einfache Fortschrittsanzeige
Private Const FOF_NOCONFIRMMKDIR As Long = &H200&        ' Anlegen von Verzeichnissen ohne Anfrage
Private Const FOF_NOERRORUI As Long = &H400&             ' Kein UserInterface bei Fehlern
Private Const FOF_NOCOPYSECURITYATTRIBS As Long = &H800& ' Sicherheitsattribute nicht mit kopieren
  
  
' API-Funktionsprototypisierungen
  
Private Declare Function SHFileOperation _
  Lib "shell32.dll" ( _
  ByRef FileOpStruct As SHFILEOPSTRUCT _
  ) As Long

Für unsere Zwecke wichtig sind vorrangig drei Aspekte: Einerseits ist da die Funktion SHFileOperation, die am Ende den Job für uns erledigen soll. Geschenkt: Sie hat einen Parameter vom Typ SHFILEOPSTRUCT. Der jedoch hat weitere Betrachtung verdient. Und dabei spielt auch schon der dritte Aspekt mit: die definierten Konstanten, denen die Funktionalität steuernde Wirkung zukommt.

Betrachten wir einige der Parameter der Struktur SHFILEOPSTRUCT:

Trivial ist der Parameter hWnd – hier kann ein Fensterhandle eines Fensters angegeben werden, das als Elternfenster für Interaktionselemente dienen soll (i.A. schlicht „Form1.hWnd“). Weiter geht es mit wFunc: Hier wird angegeben, welche Art der Dateibehandlung (Kopieren, Verschieben, Löschen oder Umbenennen) gewünscht wird. Wir entscheiden uns für das Löschen (in den Papierkorb, versteht sich) und verwenden dafür die benannte Konstante FO_DELETE.

Der interessanteste Parameter für unsere Zwecke ist der Parameter pFrom: Hier wird definiert, woher („From“) die Dateien kommen, die in den Papierkorb verschoben werden sollen. Auf gut Deutsch: Hier sind die Pfade zu den zu löschenden Dateien anzugeben. Da es sich um nur einen einzigen Stringparameter handelt, muss es ein Trennzeichen geben, um mehrere Angaben voneinander trennen zu können (Sie könnten auch nur einen Dateipfad angeben und jeweils die Löschoperation durchführen – das würde in etwa dem Vorgehen entsprechen, 20 Dateien in einem Verzeichnis Stück für Stück zu löschen, statt zunächst die 20 Dateien zu markieren und erst dann den Löschbefehl zu erteilen). Gibt es auch: Das Trennzeichen ist das „Nullzeichen“ (Chr$(0)), das in Visual Basic statt über die jeweils auszuführende Chr-Funktion auch einfacher über die Stringkonstante vbNullChar abgerufen werden kann. So reihen Sie also einfach mehrere Dateipfade, die durch vbNullChar-Zeichen verbunden sind, in die Reihe der Löschkandidaten ein. Die Liste muss für die Funktion SHFileOperation beim Aufruf durch ein doppeltes vbNullChar als abgeschlossen erkennbar sein. Tief unter der Haube terminiert Visual Basic dem Win32-API gegenüber allerdings ohnehin jeden String mit einem zusätzlichen vbNullChar, so dass Sie auch einfach nach jedem Pfad ein vbNullChar anhängen könnten und damit „aus dem Schneider“ wären – letztlich eine Stilfrage. Ich selber hänge solche eigentlich nicht notwendigen Terminierungen gerne ausdrücklich mit an Strings an, um die Anforderungen der eingesetzten API-Funktion von mir aus zu erfüllen und damit transparenten Code zu schreiben, dessen Funktionsfähigkeit nicht von Interna abhängt, die nicht unter meiner Kontrolle stehen. Ich nenne das „Explizites Programmieren“.

Letztlich noch interessant ist der Parameter fFlags der Struktur: Hier kommen die oben aufgeführten und dort erklärten FOF_-Konstanten zur Anwendung. Um etwa das Rückgängigmachen einer Aktion zu erlauben, verwenden Sie die Konstante FOF_ALLOWUNDO. Mehrere Flags für den Parameter verknüpfen Sie mithilfe des Or-Operators.

So befüllt fehlt der SHFILEOPSTRUCT-Struktur eigentlich nur noch eines: der Aufruf der Funktion SHFileOperation, für die sie alle relevanten Ausführungsinformationen enthält.

Der folgende beispielhafte Sourcecode dient dem Löschen von Dateien in den Papierkorb. Übergeben werden können als ParamArray einzelne Dateipfade, aber auch String-Arrays, die Pfade für zu löschende Dateien enthalten. Selbst ein Mix daraus ist möglich:

Public Sub BinAddFiles(ParamArray Filename() As Variant)
' Dateien in den Papierkorb verschieben. Übergeben werden die Dateipfade zu den
' zu löschenden Dateien als Strings, z.B.:
' BinAddFiles "d:\text.txt", "d:\bild.bmp", "d:\musik.wav"
' Es können auch Arrays mit Dateipfaden übergeben werden.
' Ein Mix der beiden Möglichkeiten ist ebenfalls erlaubt.
Dim SHOP As SHFILEOPSTRUCT  ' API-Struktur
Dim Files As String         ' vbNullChar-separierte Dateipfade
Dim i As Long
Dim k As Long
  
  ' ParamArray in einen vbNullChar-separierten String wandeln
  For i = LBound(Filename) To UBound(Filename)
  
    ' Stellt der aktuelle Parameter ein Array dar?
    If IsArray(Filename(i)) Then
      ' Arraymitglieder jeweils einzeln hinzufügen
      For k = LBound(Filename(i)) To UBound(Filename(i))
        Files = Files & Filename(i)(k) & vbNullChar
      Next k
    Else
      ' Kein Array, sondern ein einzelner Pfad
      Files = Files & Filename(i) & vbNullChar
    End If
  
  Next i
  
  Files = Files & vbNullChar  ' abschließendes vbNullChar anfügen
  
  With SHOP                   ' Parameter festlegen
    .wFunc = FO_DELETE        ' in den Papierkorb löschen
    .pFrom = Files            ' Quelldateien übergeben
    .fFlags = FOF_ALLOWUNDO   ' Rückgängigmachung erlauben
  End With
  
  ' Die Löschoperation ausführen
  SHFileOperation SHOP
  
End Sub

Mathias Schiffer widmet sich als freier Softwareentwickler und Technologievermittler größeren Projekten ebenso wie arbeitserleichternden Alltagslösungen. Seit Jahren gibt er sein Wissen in unzähligen Publikationen auch an andere Entwickler und Entscheider weiter. Sie erreichen ihn per E-Mail an die Adresse Schiffer@mvps.org.