ERCC (http://eriedel.info)

Dialoge zur Ordner- und Dateiauswahl anzeigen


In diesem Artikel stelle ich Möglichkeiten vor, mit Windows-Scripten einen Dialog zur Auswahl von Ordnern oder Dateien anzuzeigen. Neben der Anwendung in VBScript werden Codierungen in HTML/HTA und PowerShell demonstriert. Die vorgestellten Scripte sind in einer Zip-Datei zu diesem Artikel enthalten.

Vorbemerkung

Bevor ich die Anzeige eines Auswahldialogs behandle, möchte ich kurz auf die Möglichkeit hinweisen, diese Auswahl sozusagen auszulagern. Wenn Sie ein Script so anlegen, dass es vom Windows Explorer ausgehend gestartet wird und dabei dessen Datei- oder Ordnerauswahl übernimmt, können Sie eine eigene Dialoganzeige vermeiden.
Das setzt freilich voraus, dass die Aufgabe des Scripts von vornherein dateibezogen ist und sich als Option des Explorers definieren lässt. (Die FolderCopy-Scripte sind dafür ein Beispiel.) Das Script hat dann allerdings vorab keine Kontrolle über die Auswahl, kann also zum Beispiel keinen Ordner oder Dateityp vorgeben.

Ein Nachteil dieser Methode ist, dass auch die Übergabe der ausgewählten Namen an das zu startende Script dem Benutzer überlassen ist und vielleicht als unpraktisch oder wenig intuitiv empfunden wird. 1   Der Weg über das Explorer-Kontextmenü bietet hier in der Regel keine einfache Möglichkeit, will man nicht Vorarbeit in die Einrichtung einer »Senden an«-Option investieren (s. den Artikel Explorer-Kontextmenü erweitern).
Daher ist es im Normalfall das beste (bzw. unumgänglich), die Auswahl durch das Script selbst zu veranlasen.

Dialog zur Ordnerauswahl

Mit der Ordnerauswahl soll in aller Regel ein einzelner Ordner bestimmt werden, der dann als Arbeitsverzeichnis dient, bspw. um dort Daten zu speichern. Für diese Aufgabe gibt es einen Shell-Dialog, den Scripts auch auf einfache Weise verwenden können: BrowseForFolder.

Die API-Funktion weist eine Reihe von Parametern auf und ermöglicht auch die Auswahl verschiedener Objekte wie bspw. Drucker oder Verknüpfungen. Wenn man die Anwendung auf Verzeichnisse des Dateisystems beschränkt, sind die Optionen aber überschaubar. Die wichtigsten sind:

Als Startordner kann ein String oder eine spezieller Zahlenwert angegeben werden. In der Regel wird man entweder ein bestimmtes Verzeichnis vorgeben wollen (z.B. "C:\Workdir"), oder die Auswahl auf die Ebene der Laufwerke legen (ssfDRIVES), wobei je nach Windows-Version auch noch einige spezielle Ordner enthalten sein können.
Der Wert für die Optionsflags (iOptions) kann sich im einfachsten Fall auf die Kombination BIF_RETURNONLYFSDIRS (1) + BIF_NONEWFOLDERBUTTON (512) belaufen.

vRootFolder = 17    ' ssfDRIVES
sTitle = ""
iOptions = 513
Set obj = CreateObject("Shell.Application")
Set obj = obj.BrowseForFolder(0, sTitle, iOptions, vRootFolder)

Nach erfolgter Auswahl gibt die Funktion einen Ordner zurück, allerdings nicht als String sondern als Folder-Objekt. Dieser Shell-Folder ist nicht identisch mit dem gleichnamigen Objekt der Scripting-Komponente FileSystemObject (FSO). Bei Abbruch des Dialogs erhalten wir kein Objekt, ansonsten kann der Pfad dann über einen kleinen Umweg ermittelt werden.

If obj Is Nothing Then WScript.Quit     ' bzw. Fehlerbehandlung
Set obj = obj.Self
folder = obj.Path
WScript.Echo folder

Der gezeigte Code ist im Script browseforfolder.vbs enthalten. (Ein ähnliches Script mit einigen erklärenden Kommentaren – folderselection.vbs – finden Sie auch in den Beispielen zu VTool, die Sie als separate Zip-Datei herunterladen können.)

Dialog zur Dateiauswahl

Anscheinend war mit dem BrowseForFolder-Dialog früher auch eine Dateiauswahl möglich. Spätere und aktuelle Windows-Versionen unterstützen diese Option jedoch nicht mehr. Leider enthält Windows auch keinen anderen Dialog für diesen Zweck, der für WSH-Scripts geeignet wäre. Die Standarddialoge zur Dateiauswahl sind für WSH-Scripts nur mit zusätzlicher COM-Unterstützung erreichbar. (Ich komme darauf später zurück, möchte aber erst die anderen Möglichkeiten behandeln.)

HTA

Eine gängige Lösung für eine Dateiauswahl mittels Script besteht darin, MSHTA auszuführen, das Teil der Windows-Systemprogramme ist.

sMSHTA = "mshta.exe ""about:<input type=file id=FILE>" & _
         "<script>FILE.click();new ActiveXObject('Scripting.FileSystemObject')" & _
         ".GetStandardStream(1).WriteLine(FILE.value);close();</script>"""
Set obj = CreateObject("WScript.Shell")
Set obj = obj.Exec(sMSHTA)
sFile = obj.StdOut.ReadLine()
Set obj = Nothing
WScript.Echo sFile

Der Parameter repräsentiert eine minimale HTA (HTML-Applikation), die einen Dateiauswahldialog öffnet und den gewählten Dateinamen über das FSO an die Konsole ausgibt. Das WSH-Objekt WshShellExec ermöglicht das Einlesen dieser Ausgabe (mshta-filesel.vbs).

Der Einsatz von MSHTA hatte und hat den Vorteil, auf praktisch allen Windows-Versionen zu funktionieren. Ein Nachteil der gezeigten Lösung liegt in der eingeschränkten Dateiauswahl und dem vorgegebenen Fenstertitel. Leider lässt sich auch kein Verzeichnis bestimmen. Der zugrundeliegende Shell-Dialog verwendet daher regelmäßig den Ordner einer vorherigen Auswahl.

Die HTA-Technik bietet ansonsten auch die Möglichkeit, komplexe Fenster mit diversen GUI-Elementen anzulegen und unterstützt die Kombination mit Scriptcode. (Ich habe die Anzeige eines solchen Fensters zur Auswahl mehrerer Optionen im Artikel über Mehrfachauswahlen demonstriert.) Neben der Dateiauswahl könnte also auch die gesamte Anwendung durch eine HTA erfolgen. Falls der ausgewählte Dateiname jedoch an ein Script übergeben werden soll, so ist zu berücksichtigen, dass der HTA-Datei die Standard-E/A-Ströme der Konsole nicht verfügbar sind. Hier wäre also ein anderer Weg zu wählen, etwa die Übergabe mittels Aufrufparameter. Dies wird an den Dateien hta-dlg-1.hta und hta-dlg-2.vbs demonstriert: Die HTA kann direkt gestartet werden und bringt den Auswahldialog zur Anzeige. Der Dateiname wird dann an die Scriptdatei übergeben.

PowerShell (PS)

Mit PowerShell ist ab 2006 ein sehr leistungsfähiger Befehlsinterpreter vorhanden, der seitdem standardmäßiger Bestandteil von Windows ist. Inzwischen existieren mehrere Versionen, die sich im Funktionsumfang unterscheiden. Die konkrete Version ist von der Windows-Version, aber auch von optionalen Updates abhängig. Dies hat den Nachteil, dass die Verfügbarkeit bestimmter Funktionen nicht auf allen Systemen gewährleistet ist. Die hier gezeigte Lösung sollte davon nicht betroffen sein.

PowerShell kann Objekte des .NET-Frameworks verwenden. Die Anzeige eines Dateiauswahldialogs ist in System.Windows.Forms.OpenFileDialog implementiert. Die entsprechenden Anweisungen lassen sich in einem kleinen PowerShell-Script (filedlg.ps1) zusammenstellen.

Zur leichteren Unterscheidung von WSH/VBS wird PS-Code im Folgenden farblich hervorgehoben.

Im Allgemeinen verhindern Windows-Sicherheitseinstellungen die Ausführung von PS-Scripten. Die Einstellung lässt sich jedoch so abändern, dass lokale PS-Scripte gestartet werden können. Hierzu wird PowerShell in einer Administrator-Konsole aufgerufen und der Befehl

set-executionpolicy remotesigned

eingegeben.
Die aktuell geltende Einstellung kann mit dem Befehl

get-executionpolicy

überprüft werden.

Alternativ lässt sich die Sicherheitsbeschränkung für eine einzelne Scriptdatei durch einen Aufrufparameter reduzieren oder außer Kraft setzen, z.B. (s. ps-filedlg.cmd):

powershell -executionpolicy bypass .\filedlg.ps1

Der Objektbezug zum .NET-Dialogfenster muss im Script explizit hergestellt werden. Dies geschieht im nachfolgenden Code durch die Anweisung der ersten Zeile. Anschließend wird das Objekt erzeugt, und es werden zwei seiner Eigenschaften definiert:

Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
$FileBrowser.InitialDirectory = [Environment]::CurrentDirectory
$FileBrowser.Title = 'Select a File'
$val = $FileBrowser.ShowDialog()

Das PowerShell-Script kann auch von einem WSH-Script aufgerufen werden (s. ps-filedlg.vbs). Und falls die eigentliche Anwendung, die eine Dateiauswahl verarbeitet, durch das WSH-Script erfolgen soll, lässt sich dies über die Konsolen-E/A bewerkstelligen. Hierzu wird der Name der ausgewählten Datei in der Konsole ausgegeben. Bei Abbruch des Dialogs ist das eine Leerzeile. Die Ausgabe kann im WSH-Script eingelesen und überprüft werden.

write-host $FileBrowser.FileName

Die ShowDialog-Methode gibt »OK« oder »Cancel« als Text zurück. Man kann das Script entsprechend mit einem Exitcode beenden:

if ($val -eq 'OK') {exit 0}
else {exit 1}

Dies erlaubt einer Befehlsdatei die Auswertung mittels %errorlevel% (siehe das Beispiel ps-filedlg.cmd). In einem WSH-Script kann der Wert durch die ExitCode-Eigenschaft ermittelt werden.

Der Aufruf des PowerShell-Scripts erfolgt im WSH-Script (ps-filedlg.vbs) mittels WshScriptExec. Falls PowerShell in der älteren Version 2.0 vorliegt (standardmäßig enthalten in Windows 7 und Windows Server 2008 R2), muss das Programm explizit als STA-Anwendung gestartet werden, was durch den Parameter »-Sta« geschieht. Spätere Versionen tun dies von sich aus und stören sich am Parameter nicht.

sCmd = "powershell -Sta -WindowStyle Hidden .\filedlg.ps1"
Set oExec = CreateObject("wscript.shell")
Set oExec = oExec.Exec(sCmd)

Mit dem Start von PowerShell wird ein PS-Konsolenfenster geöffnet, das hier unerwünscht ist. Seine Sichtbarkeit lässt sich aber durch den verwendeten Parameter »-WindowStyle Hidden« verhindern. (Achtung: Auf diese Weise verschwindet auch ein zuvor geöffnetes Konsolenfenster. Erfolgt also die Ausführung über eine Befehlsdatei oder ein Konsolenscript, so sollte der Parameter nicht oder allenfalls in der Form »-WindowStyle Minimized« eingesetzt werden.)
Der im Fenster ausgegebene Dateiname kann mit einer WshScriptExec-Methode eingelesen werden:

sLine = oExec.StdOut.ReadLine
Set oExec = Nothing
WScript.Echo "Output:" & vbNewLine & sLine

Der PowerShell-Prozess läuft über das Schließen des Dialogfensters und das Ende des PS-Scriptes hinaus weiter, solange das WshScriptExec-Objekt besteht. Daher ist es sinnvoll, diese Referenz alsbald aufzulösen.

Der Dialog erlaubt auch die Auswahl mehrerer Dateien. Das wird an den Beispielen filedlg2.ps1 und ps-filedlg2.vbs demonstriert.

COM-Add-Ins

WSH/VBS kann (wie auch PS) auf Objekte vorhandener COM-Module zugreifen und deren Funktionalität benutzen. Microsoft hatte in der Vergangenheit ein solches Modul entwickelt, das die Verwendung der Standarddialoge, darunter auch die Dateiauswahl unterstützt (»MSComDlg.CommonDialog«, comdlg32.ocx). Diese Komponente wurde früher mit Visual Basic 6.0 und diversen Programmen, möglicherweise auch mit manchen MS-Office-Produkten installiert. Auf aktuellen Systemen ist sie sehr wahrscheinlich nicht vorhanden, wird aber von Microsoft weiterhin zum Download bereitgestellt, wobei Nutzungs- und Systembedingungen zu beachten sind. 2  

Wenn die Installation eines COM-Add-Ins kein Hindernis darstellt, kann ich auch zwei ergänzende Lösungen vorschlagen, die auf von mir entwickelten Komponenten basieren.

Eine davon ist das sehr einfach verwendbare VTool, das eine Reihe von GUI-Dialogen bietet, einschließlich einer Dateiauswahl. VTool.FileSelection setzt den Standarddialog des Windows-API zum Öffnen oder Speichern von Dateien ein. Im einfachsten Fall der Auswahl einer Datei genügen folgende Anweisungen:

Set obj = CreateObject("VTool.FileSelection")
If obj.Dialog(0) Then
    MsgBox obj.Directory & obj.FileName, , "Datei:"
End If
Set obj = Nothing

Das Objekt ist in der VTool-Doku mit Beispielen beschrieben.

Ein anderer Weg steht mit DynaLib (DynaLib.Caller) offen. DynaLib ermöglicht es Scripten, DLL-Funktionen aufzurufen. Auf diese Weise können Sie das Windows-API nutzen. Um einen Dateiauswahldialog zu öffnen, bieten sich die API-Funktionen GetFileNameFromBrowse (Shell32.dll) und GetOpenFileName (Comdlg32.dll) an.

Die Funktion GetFileNameFromBrowse ist recht einfach zu verwenden, allerdings kann damit nur eine einzelne Datei ausgewählt werden. Das folgende Beispiel (browseforfile.vbs) zeigt eine mögliche Anwendung.

Set obj = WScript.CreateObject("WScript.Shell")
pdir = obj.CurrentDirectory
cc = 512
pfile = String(cc, 0)
Set obj = CreateObject("DynaLib.Caller")
args = Array(Null, pfile, Array(cc), pdir, Null, Null, "File Selection")
n = obj.CallFunc("Shell32.dll", "GetFileNameFromBrowse", args)
If n Then
    msg = args(1)
Else
    msg = "Function cancelled or an error occurred."
End If
MsgBox msg
Set obj = Nothing

Die Funktion GetOpenFileName bietet etwas weiter gehende Optionen, setzt als Parameter aber auch eine umfangreiche Struktur ein. (Leider unterstützt VBScript den Datentyp Struktur nicht. Er muss daher über einen String abgebildet werden. DynaLib enthält Funktionen, die dabei helfen.) Eine Beispielanwendung ist mit den Scripten getopenfile.vbs und getopenfile2.vbs enthalten.

Download, Benutzung

Die in diesem Artikel erwähnten Script-Dateien sind in  fselection.zip enthalten. Sie können sie in einen beliebigen Ordner entpacken und nach Ihren Vorstellungen verwenden.
Beachten Sie bitte, dass die Überlassung dieser Dateien ohne jede Gewährleistung oder Haftung erfolgt. Die Benutzung geschieht auf eigenes Risiko!

Links

Die folgende Liste verweist auf Webseiten von Microsoft mit weitergehenden Information zu den behandelten Script-Techniken und Funktionen.

WSH & VBS
Windows Script Host overview
Windows Script Host
VBScript
Script Runtime

HTA
Introduction to HTML Applications (HTAs)

PowerShell, .NET-Dateidialog
OpenFileDialog Class
PowerShell Documentation
PowerShell Intro
PowerShell - Getting Started
PowerShell command-line parameters

API-Funktionen
Shell.BrowseForFolder method
GetFileNameFromBrowse (Shell)
GetOpenFileName (Comdlg)
OPENFILENAME-Struktur


Anmerkungen:

1 Der Start mit Argumentübergabe ist mittels Copy & Paste möglich. Dazu werden die Dateien markiert, kopiert und beim markierten Script »eingefügt«. Das Ziehen der Auswahl mit der Maus auf die Scriptdatei (Drag & Drop) bewirkt dasselbe, ist im Grunde aber nur praktikabel, wenn sich beides im selben Verzeichnis befindet.

2 Microsoft weist auf der Download-Seite darauf hin, dass die Nutzung der beiden angebotenen Steuerelemente von einer bestehenden Lizenz abhängig und die Installation nur bei vorhandener Vorversion möglich ist.
Ein Beitrag der »Microsoft Community« beschreibt ein mögliches Verfahren zur Installation der einzelnen Komponente (comdlg32.ocx).



http://eriedel.info/info/fseldlg/fselection.html


ERCC (http://eriedel.info)  2023   © Erhard Riedel Computer Consulting (ERCC)

 

Link zur ERCC-Hauptseite   Link zur Info-Übersicht