PDA

Vollständige Version anzeigen : Wie erhalte ich einen Verzeichnisauswahldialog?


Stefan Kulpa
11.01.2003, 17:33
Der Dateiauswahldialog ist ein Windows eigener Systemdialog. Aus diesem Grund kann er von Windows Version zu Windows Version unterschiedlich aussehen – die Handhabung ist aber identisch.

Der Aufruf ist jedoch nur mittels des Win32-API möglich, ein entsprechendes ActiveX-Control wird (von Microsoft) nicht angeboten.

Leider(?) gibt es auch hier wieder unterschiedliche Möglichkeiten, diesen Dialog zu beeinflussen. Dies geschieht über folgende Konstanten:

<TABLE border="0" cellpadding="3" cellspacing="1" class="tabletext"><tr><td width="35%" class="tablehead1"><span class="tabletext">Const BIF_BROWSEFORCOMPUTER = &H1000</span></td><td class="tablesmileyhead2"> Version 4.0. Nur Computer als Auswahl erlaubt. Wenn der Anwender andere Ordner markiert, kann der OK-Schalter nicht ausgewählt werden.</td></tr><tr><td class="tabletext1">Const BIF_BROWSEFORPRINTER = &H2000</td><td class="tablesmiley2"> Version 4.0. Nur Drucker als Auswahl erlaubt. Wenn der Anwender andere Ordner markiert, kann der OK-Schalter nicht ausgewählt werden.</td></tr><tr><td class="tabletext1">Const BIF_BROWSEINCLUDEFILES = &H4000</td><td class="tablesmiley2"> Version 4.71. Der Dialog zeigt neben den Ordnern auch Dateien.</td></tr><tr><td class="tabletext1">Const BIF_BROWSEINCLUDEURLS = &H80</td><td class="tablesmiley2"> Version 5.0. Der Dialog kann auch URLs anzeigen.</td></tr><tr><td class="tabletext1">Const BIF_DONTGOBELOWDOMAIN = &H2</td><td class="tablesmiley2"> Version 4.0. Der Dialog zeigt keine Netzwerkordner unterhalb der aktuellen Domain.</td></tr><tr><td class="tabletext1">Const BIF_EDITBOX = &H10</td><td class="tablesmiley2"> Version 4.71. Dem Dialog wird eine Textbox hinzugefügt, 'um einen Eintrag einzugeben</td></tr><tr><td class="tabletext1">Const BIF_NEWDIALOGSTYLE = &H40</td><td class="tablesmiley2"> Version 5.0. Das neue Benutzer-Design wird verwendet.</td></tr><tr><td class="tabletext1">Const BIF_NONEWFOLDERBUTTON = &H200</td><td class="tablesmiley2">Version 4.0. Der Dialog enthält keine Schaltfläche "Neuen Ordner erstellen</td></tr><tr><td class="tabletext1">Const BIF_RETURNFSANCESTORS = &H8</td><td class="tablesmiley2"> Version 4.0. Nur Dateisystemobjekte als Auswahl erlaubt. Wenn der Anwender andere Ordner markiert, kann der OK-Schalter nicht ausgewählt werden.</td></tr><tr><td class="tabletext1">Const BIF_RETURNONLYFSDIRS = &H1</td><td class="tablesmiley2"> Version 4.0. Nur Dateisystemordner als Auswahl erlaubt. Wenn der Anwender andere Ordner markiert, kann der OK-Schalter nicht ausgewählt werden.</td></tr><tr><td class="tabletext1">Const BIF_SHAREABLE = &H8000</td><td class="tablesmiley2"> Version 5.0. Der Dialog zeigt 'shareable' Ressourcen auf Netzwerksystem an.</td></tr><tr><td class="tabletext1">Const BIF_STATUSTEXT = &H4</td><td class="tablesmiley2"> Version 4.0. Der Dialog enthält eine Statuszeile. Die Callback-Funktion kann die Statuszeile ausfüllen.</td></tr><tr><td class="tabletext1">Const BIF_UAHINT = &H100</td><td class="tablesmiley2"> Version 4.0. Zusammen mit BIF_NEWDIALOGSTYLE wird anstelle der Eingabemöglichkeit ein Benutzerhinweis angezeigt</td></tr><tr><td class="tabletext1">Const BIF_USENEWUI = &H40</td><td class="tablesmiley2"> Version 5.0. Zeigt ein neuen Dialog an mit mehr benutzerfreundlichen Änderungen</td></tr><tr><td class="tabletext1">Const BIF_VALIDATE = &H20</td><td class="tablesmiley2"> Version 4.71. Sendet an die Callback Funktion eine BFFM_VALIDATEFAILED Message, wenn in der Textbox eine falsche Eingabe gemacht wurde</td></tr></TABLE>

Diese Konstanten stehen in Abhängigkeit von der Shell32.dll-Version zur Verfügung. Dies sind:

<TABLE border="0" cellpadding="3" cellspacing="1" class="tabletext"><tr><td class="tablehead1"><span class="tabletext">Version</span></td><td class="tablehead2"><span class="tabletext">DLL</span></td><td class="tablehead3"><span class="tabletext">Betriebssystem</span></td></tr><tr><td class="tabletext1">4.00</td><td class="tabletext2"> alle</td><td class="tabletext3"> Microsoft® Windows® 95/Windows NT® 4.0</td></tr><tr><td class="tabletext1">4.71</td><td class="tabletext2"> alle</td><td class="tabletext3"> Microsoft® Internet Explorer 4.0</td></tr><tr><td class="tabletext1">5.00</td><td class="tabletext2"> Shlwapi.dll</td><td class="tabletext3"> Microsoft® Internet Explorer 5</td></tr><tr><td class="tabletext1">5.00</td><td class="tabletext2"> Shell32.dll</td><td class="tabletext3"> Microsoft® Windows® 2000 und Windows Me</td></tr></TABLE>

Um diese Konstanten nun einsetzen zu können, wird eine Struktur benötigt:

Type BROWSEINFO
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hOwner&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Handle zum Elternfenster
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pidlRoot&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;für VB/A nicht relevant
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pszDisplayName&nbsp;As String&nbsp;&nbsp;&nbsp;für VB/A nicht relevant
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszTitle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String&nbsp;&nbsp;&nbsp;Dialogtitel
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ulFlags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flag für die Dialogeinstellung
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Funktionsadresse (Callback)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lParam&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Wert für die Callback-Nutzung
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;für VB/A nicht relevant
End Type

In diesem Beispiel wird jedoch von der einfachsten Art der Nutzung des Auswahldialogs ausgegangen:

<div><link href="http://www.ms-office-forum.de/ubb/codeconv.css" rel="stylesheet"><pre><span class="TOKEN">Type</span> BROWSEINFO
hOwner <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
pidlRoot <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
pszDisplayName <span class="TOKEN">As</span> <span class="TOKEN">String</span>
lpszTitle <span class="TOKEN">As</span> <span class="TOKEN">String</span>
ulFlags <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
lpfn <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
lParam <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
iImage <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
<span class="TOKEN">End</span> <span class="TOKEN">Type</span>
&nbsp;
<span class="TOKEN">Const</span> BIF_BROWSEFORCOMPUTER = &amp;H1000
<span class="TOKEN">Const</span> BIF_BROWSEFORPRINTER = &amp;H2000
<span class="TOKEN">Const</span> BIF_BROWSEINCLUDEFILES = &amp;H4000
<span class="TOKEN">Const</span> BIF_BROWSEINCLUDEURLS = &amp;H80
<span class="TOKEN">Const</span> BIF_DONTGOBELOWDOMAIN = &amp;H2
<span class="TOKEN">Const</span> BIF_EDITBOX = &amp;H10
<span class="TOKEN">Const</span> BIF_NEWDIALOGSTYLE = &amp;H40
<span class="TOKEN">Const</span> BIF_NONEWFOLDERBUTTON = &amp;H200
<span class="TOKEN">Const</span> BIF_RETURNFSANCESTORS = &amp;H8
<span class="TOKEN">Const</span> BIF_RETURNONLYFSDIRS = &amp;H1
<span class="TOKEN">Const</span> BIF_SHAREABLE = &amp;H8000
<span class="TOKEN">Const</span> BIF_STATUSTEXT = &amp;H4
<span class="TOKEN">Const</span> BIF_UAHINT = &amp;H100
<span class="TOKEN">Const</span> BIF_USENEWUI = &amp;H40
<span class="TOKEN">Const</span> BIF_VALIDATE = &amp;H20
&nbsp;
<span class="TOKEN">Declare</span> <span class="TOKEN">Function</span> GetActiveWindow <span class="TOKEN">Lib</span> &quot;user32&quot; () <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
&nbsp;
<span class="TOKEN">Declare</span> <span class="TOKEN">Function</span> SHBrowseForFolder <span class="TOKEN">Lib</span> &quot;shell32.dll&quot; <span class="TOKEN">Alias</span> _
&quot;SHBrowseForFolderA&quot; _
(lpBrowseInfo <span class="TOKEN">As</span> BROWSEINFO) <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
&nbsp;
<span class="TOKEN">Declare</span> <span class="TOKEN">Function</span> SHGetPathFromIDList <span class="TOKEN">Lib</span> &quot;shell32.dll&quot; <span class="TOKEN">Alias</span> _
&quot;SHGetPathFromIDListA&quot; _
(<span class="TOKEN">ByVal</span> pidl <span class="TOKEN">As</span> Long, _
<span class="TOKEN">ByVal</span> pszPath <span class="TOKEN">As</span> <span class="TOKEN">String</span>) <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
&nbsp;
<span class="TOKEN">Declare</span> <span class="TOKEN">Sub</span> CoTaskMemFree <span class="TOKEN">Lib</span> &quot;OLE32.dll&quot; (<span class="TOKEN">ByVal</span> pv <span class="TOKEN">As</span> <span class="TOKEN">Long</span>)
&nbsp;
<span class="TOKEN">Function</span> Ordnerauswahl() <span class="TOKEN">As</span> <span class="TOKEN">String</span>
&nbsp;
<span class="TOKEN">Const</span> MAXPATH <span class="TOKEN">As</span> <span class="TOKEN">Long</span> = 260
<span class="TOKEN">Dim</span> uBrowseInfo <span class="TOKEN">As</span> BROWSEINFO
<span class="TOKEN">Dim</span> sPath <span class="TOKEN">As</span> <span class="TOKEN">String</span>
<span class="TOKEN">Dim</span> lPidl <span class="TOKEN">As</span> <span class="TOKEN">Long</span>
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Das Elternfenster bestimmen</span>
<span class="REM">'// -------------------------------------------------------------</span>
uBrowseInfo.hOwner = GetActiveWindow()
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// pidlRoot ist zwar irrelevant, muss aber auf 0 gesetzt werden</span>
<span class="REM">'// -------------------------------------------------------------</span>
uBrowseInfo.pidlRoot = 0&amp;
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Flag auf &quot;nur Ordner&quot; setzen</span>
<span class="REM">'// -------------------------------------------------------------</span>
uBrowseInfo.ulFlags = BIF_RETURNONLYFSDIRS
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Dialogtitel setzen</span>
<span class="REM">'// -------------------------------------------------------------</span>
uBrowseInfo.lpszTitle = &quot;Bitte w&auml;hlen Sie ein Verzeichnis:&quot;
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Funktion aufrufen</span>
<span class="REM">'// -------------------------------------------------------------</span>
lPidl = SHBrowseForFolder(uBrowseInfo)
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// String-Buffer f&uuml;r API-Aufruf dimensionieren !!!</span>
<span class="REM">'// -------------------------------------------------------------</span>
sPath = VBA.Space$(MAXPATH)
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Ergebnis &quot;abholen&quot;</span>
<span class="REM">'// -------------------------------------------------------------</span>
<span class="TOKEN">If</span> SHGetPathFromIDList(<span class="TOKEN">ByVal</span> lPidl, <span class="TOKEN">ByVal</span> sPath) <span class="TOKEN">Then</span>
<span class="REM"> '// ---------------------------------------------------------</span>
<span class="REM"> '// Bei Erfolg R&uuml;ckgabewert ermitteln</span>
<span class="REM"> '// ---------------------------------------------------------</span>
Ordnerauswahl = Left(sPath, InStr(sPath, vbNullChar) - 1)
<span class="TOKEN">End</span> <span class="TOKEN">If</span>
<span class="REM">'// -------------------------------------------------------------</span>
<span class="REM">'// Wichtig: Speicher freigeben !!!</span>
<span class="REM">'// -------------------------------------------------------------</span>
<span class="TOKEN">Call</span> CoTaskMemFree(lPidl)
&nbsp;
<span class="TOKEN">End</span> <span class="TOKEN">Function</span>
&nbsp;
<span class="TOKEN">Sub</span> Beispiel()
&nbsp;
<span class="TOKEN">Dim</span> sFolder <span class="TOKEN">As</span> <span class="TOKEN">String</span>
sFolder = Ordnerauswahl()
<span class="TOKEN">If</span> Len(sFolder) &gt; 0 <span class="TOKEN">Then</span>
MsgBox &quot;Der Ordner &quot; &amp; sFolder &amp; &quot; wurde gew&auml;hlt!&quot;, vbInformation
<span class="TOKEN">End</span> <span class="TOKEN">If</span>
&nbsp;
<span class="TOKEN">End</span> <span class="TOKEN">Sub</span></pre></div>
Code eingefügt mit dem MOF Code Converter (http://www.ms-office-forum.net/forum/codeconverter.php)

Sascha Trowitzsch
17.03.2003, 14:03
Die einfachste Variante, um den Verzeichnisauswahl-Dialog zu erhalten, ist der entsprechende Aufruf aus der Shell32.dll.
Da diese eine ActiveX-DLL und in jedem Windows enthalten ist, können viele Systemfunktionen auf einfache Weise ohne API und Sorge um Kompatibilität aufgerufen werden.
Eine gute Übersicht kann man unter
http://www.shadoware.de/vb/tutorials/shell32.html
finden.
Voraussetzung ist ein Verweis auf diese DLL im VB-Editor, der sich 'Microsoft Shell Controls And Automation' nennt.
<hr>
Microsoft macht außerdem in der MSDN folgende Aussagen zum Object Shell.Application:

Minimum DLL version:
shell32.dll version 4.71 or later

Minimum operating systems:
Windows 2000, Windows NT 4.0 with Internet Explorer 4.0, Windows 98, Windows 95 with Internet Explorer 4.0
<hr>
Einen Order mit dem entspr. Shell-Dialog erhält man mit folgender Funktion:

<div><link href="http://www.ms-office-forum.net/forum/externals/codeconv.css" rel="stylesheet"><pre>&nbsp;
<span class="REM">'Shell Funktion: Function BrowseForFolder(Hwnd As Long, Title As String, Options As Long, [RootFolder]) As Folder</span>
&nbsp;
<span class="TOKEN">Function</span> GetFolder(<span class="TOKEN">Optional</span> Caption, <span class="TOKEN">Optional</span> StartFolder, <span class="TOKEN">Optional</span> lOptions) <span class="TOKEN">As</span> <span class="TOKEN">String</span>
<span class="TOKEN">Dim</span> SH <span class="TOKEN">As</span> <span class="TOKEN">New</span> Shell
<span class="TOKEN">On</span> <span class="TOKEN">Error</span> <span class="TOKEN">Resume</span> <span class="TOKEN">Next</span> <span class="REM">'Notwendig, falls der Abbrechen-Button bet&auml;tigt wird; Ergebnis ist dann &quot;&quot;</span>
<span class="TOKEN">If</span> IsMissing(Caption) <span class="TOKEN">Then</span> Caption = &quot;&quot;
GetFolder = <span class="TOKEN">CStr</span>(SH.BrowseForFolder(0, Caption, lOptions, StartFolder))
<span class="TOKEN">End</span> <span class="TOKEN">Function</span></pre></div>

Mit Caption kann ein Titel-String angegeben werden.
Mit StartFolder kann ein Verzeichnis-String als Startverzeichnis angegeben werden.
lOptions ist eine Kombination von Konstanten. Es sind die gleichen, die Stefan oben aufgelistet hat (BIF_-Konstanten).

Alternativ funktioniert das Ganze auch ohne Verweis :
<div><link href="http://www.ms-office-forum.net/forum/externals/codeconv.css" rel="stylesheet"><pre><span class="TOKEN">Function</span> GetFolder(<span class="TOKEN">Optional</span> Caption, <span class="TOKEN">Optional</span> StartFolder, <span class="TOKEN">Optional</span> lOptions) <span class="TOKEN">As</span> <span class="TOKEN">String</span>
<span class="TOKEN">Dim</span> SH <span class="TOKEN">As</span> Object
<span class="TOKEN">On</span> <span class="TOKEN">Error</span> <span class="TOKEN">Resume</span> <span class="TOKEN">Next</span>
<span class="TOKEN">Set</span> SH = CreateObject(&quot;Shell.Application&quot;)
<span class="TOKEN">If</span> IsMissing(Caption) <span class="TOKEN">Then</span> Caption = &quot;&quot;
GetFolder = <span class="TOKEN">CStr</span>(SH.BrowseForFolder(0, Caption, lOptions, StartFolder))
<span class="TOKEN">Set</span> SH = <span class="TOKEN">Nothing</span>
<span class="TOKEN">End</span> <span class="TOKEN">Function</span>
&nbsp;</pre></div>

Beispiel für einen Aufruf:

strFolder = GetFolder( , "C:\", &H40)

Ciao, Sascha

Update:

Nach Update von W2000 auf SP4 funktioniert die Funktion nicht mehr wie gewünscht. Sie gibt nur noch den Verzeichnisnamen zurück, nicht jedoch den gesamten Pfad.
Es notwendig, die Funktion folgendermaßen umzuschreiben:

<div><link href="http://www.ms-office-forum.net/forum/externals/codeconv.css" rel="stylesheet"><pre><span class="TOKEN">Function</span> GetFolder(<span class="TOKEN">Optional</span> Caption, <span class="TOKEN">Optional</span> StartFolder, <span class="TOKEN">Optional</span> lOptions) <span class="TOKEN">As</span> <span class="TOKEN">String</span>
<span class="TOKEN">Dim</span> SH <span class="TOKEN">As</span> Object, SF <span class="TOKEN">As</span> <span class="TOKEN">Object</span>
<span class="TOKEN">Set</span> SH = <span class="TOKEN">CreateObject</span>(&quot;Shell.Application&quot;)
<span class="TOKEN">If</span> <span class="TOKEN">IsMissing</span>(Caption) <span class="TOKEN">Then</span> Caption = &quot;&quot;
<span class="TOKEN">If</span> <span class="TOKEN">IsMissing</span>(StartFolder) <span class="TOKEN">Then</span> StartFolder = &quot;c:\&quot;
<span class="TOKEN">If</span> <span class="TOKEN">IsMissing</span>(lOptions) <span class="TOKEN">Then</span> lOptions = &amp;H40
<span class="TOKEN">Set</span> SF = SH.BrowseForFolder(0, Caption, lOptions, StartFolder)
<span class="TOKEN">If</span> SF <span class="TOKEN">Is</span> <span class="TOKEN">Nothing</span> <span class="TOKEN">Then</span> <span class="TOKEN">Exit Function</span>
GetFolder = SF.Self.Path
<span class="TOKEN">Set</span> SH = <span class="TOKEN">Nothing</span>
<span class="TOKEN">Set</span> SF = <span class="TOKEN">Nothing</span>
<span class="TOKEN">End</span> <span class="TOKEN">Function</span><hr></pre></div>
Code eingefügt mit dem MOF Code Converter (http://www.ms-office-forum.net/forum/codeconverter.php)

DarthPatrick
15.07.2004, 08:26
@Sascha: Vielen Dank für diesen super Tipp!! Leider habe ich ein Problem und bekomme es selber nicht in den Griff: NT40, SP6, IE5.0 gibt mir mit der ersten Funktion nur den Verzeichnisnamen und nicht den Pfad zurück. Die zweite Funktion scheitert mit dem Fehler "Objekt unterstützt diese Eigenschaft oder Methode nicht" in der Zeile GetFolder=SF.Self.Path :confused:

Ich vermute jetzt mal, dass SF kein Object sondern irgendwas anderes sein muss - habe bnis jetzt aber noch nicht so recht herausbekommen was - oder liegt der Fehler ganz woanders ?!

Toast78
16.10.2007, 20:23
Ich hätt da auch nochmal einen kleinen Tipp: Und zwar wollte ich auf möglichst einfache Art und Weise mittels shell32.dll den gesamten Pfad und nicht nur den Namen des Ordners selbst ermitteln.
Dazu habe ich folgendes kleines Beispiel:
Public Sub oeffneOrdner()
Dim schale As New Shell
Dim ordner As Folder2
Set ordner = schale.BrowseForFolder(0, "Verzeichnisdialog", &H40, "G:\")
Debug.Print ordner.Self.Path
End Sub