{"id":55001096,"date":"2017-08-01T00:00:00","date_gmt":"2020-05-13T21:26:24","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1096"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Explorer_Control","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/","title":{"rendered":"Explorer Control"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>F&uuml;r manche Aufgaben ben&ouml;tigen auch Datenbanken die Anzeige oder Auswahl von Dateien oder Ordnern des Betriebssystems. Manche davon lassen sich mit dem Dateiauswahldialog von Office erledigen. Hin und wieder ist aber eine unmittelbare Einsicht in das Dateisystem n&uuml;tzlich. Der Windows Explorer l&auml;sst sich mit Einschr&auml;nkungen fernsteuern, doch schicker w&auml;re ein Explorer direkt in einem Formular. Und das geht!<\/b><\/p>\n<h2>Explorer Browser Control aus Windows<\/h2>\n<p>Den Explorer komplett nachzubilden, ist in der Regel mit gewaltigem Aufwand verbunden. Hier sind unz&auml;hlige <b>Shell<\/b>-Objekte zu ber&uuml;cksichtigen. Wer etwa das <b>Access 2007 Praxisbuch<\/b> kennt, findet in der zentralen Beispielanwendung <b>dmsBase<\/b> ein <b>ActiveX-Steuerelement<\/b> <b>ShellExplorer.ocx<\/b>, das zur Laufzeit weitgehend dem Windows Explorer gleicht. Die Programmierung dieses Controls ben&ouml;tigte &uuml;ber 20.000 Zeilen Code.<\/p>\n<p>Diese Zeiten sind seit <b>Windows Vista<\/b> vorbei! Microsoft hat hier ein neues Control in den <b>Shell<\/b>-Komponenten verbaut, welches sich <b>ExplorerBrowser<\/b> nennt. Dabei handelt es sich um einen kompletten Explorer mit allem Zubeh&ouml;r als einbettbares Fenster. In gewisser Weise &auml;hnelt diese Komponente dem<b> Webbrowser Control<\/b>, welches den<b> Internet Explorer <\/b>als ActiveX-Steuerelement zur Verf&uuml;gung stellt. Nur gibt es die <b>ExplorerBrowser<\/b>-Komponente eben leider nicht als ActiveX-Control. Sie muss stattdessen &uuml;ber <b>COM-Schnittstellen<\/b> erzeugt und gesteuert werden. Das w&auml;re weiter nicht tragisch, enthielte denn irgendeine Windows-Bibliothek, die sich in die <b>Verweise<\/b> von VBA eintragen lie&szlig;e, die entsprechenden Schnittstellendefinitionen. Das ist jedoch nicht der Fall.<\/p>\n<h2><b>OLEEXP<\/b> als Nachfolger von <b>OLELIB<\/b><\/h2>\n<p>Zum Gl&uuml;ck gibt es Typbibliotheken, die diesem Umstand abhelfen. Der Microsoft <b>MVP<\/b> f&uuml;r <b>Visual Basic 6<\/b>, <b>Eduardo Morcillo<\/b>, stellte einst die geniale Bibliothek <b>olelib.tlb<\/b> bereit, die in gro&szlig;em Umfang <b>COM<\/b>-Schnittstellen von Windows-Komponenten definiert. Mit dieser k&ouml;nnen Dinge erreicht werden, die sich auch mit Unmengen von <b>API<\/b>-Funktionen nicht realisieren lassen. Das Problem mit dieser Bibliothek aus dem Jahre 2003 ist, dass sie ziemlich ins Alter gekommen ist. Sie kann nur abbilden, was bis zu diesem Zeitpunkt bekannt war &#8211; und das sind  maximal die Schnittstellen von <b>Windows XP<\/b>.<\/p>\n<p>Das fiel auch anderen Programmierern auf. Es gibt immer noch rastlose Geister, die das altehrw&uuml;rdige <b>VB6<\/b>, auf dessen Stand das Pendant <b>VBA<\/b> nun mal leider stehenblieb, weiterentwickeln. Viele kompetente Mitstreiter finden sich im Forums <b>vbforums.com<\/b>. Der User <b>fafalone<\/b> hat sich an die Arbeit gemacht, die <b>olelib<\/b> mit neuem Leben zu f&uuml;llen, und in die abgeleitete neue Bibliothek <b>oleexp.tlb<\/b> Schnittstellendefinitionen eingebracht, die bis <b>Windows 7<\/b> reichen. Und einer der Neuen ist das Interface zum <b>ExplorerBrowser<\/b>.<\/p>\n<p>Es handelt sich, wohlgemerkt, nicht um eine aktive Komponente! Eine <b>tlb<\/b> ist lediglich eine Typbibliothek, die sich auf aktive Komponenten bezieht. Es ist deshalb in Ihrem Unternehmen nicht zu bef&uuml;rchten, dass sie bei der Rasterfahndung nach gef&auml;hrdenden Komponenten durchf&auml;llt, wie manche andere ActiveX-Dateien. Sie k&ouml;nnen sie getrost in die Verweise Ihrer Datenbank laden, wozu sie noch nicht einmal zwingend registriert werden muss. Die Methode <b>References.LoadFromFile<\/b> erlaubt auch die Integration zur Laufzeit.<\/p>\n<h2>Registrieren der OLEEXP<\/h2>\n<p>Freilich ist es dennoch sinnvoll, die Bibliothek im System zu registrieren, damit sie in Zukunft auch f&uuml;r andere VBA-Projekte zur Verf&uuml;gung steht. Im Verzeichnis zur Beispieldatenbank <b>explorerctl.accdb <\/b>finden Sie neben der <b>oleexp.tlb<\/b> noch die ausf&uuml;hrbare Datei <b>regtlibv12.exe<\/b>, die solche Typbibliotheken registrieren kann. Das ist ein Kommandozeilen-Tool von Microsoft, das Sie wahrscheinlich auch auf Ihrem System als Bestandteil des <b>NET-Frameworks 4<\/b> vorfinden. Der Einfachheit halber haben wir die Datei in das Verzeichnis der Datenbank kopiert.<\/p>\n<p>Damit Sie nicht umst&auml;ndlich in der Windows-Kommandozeile herumhantieren m&uuml;ssen, ruft eine weitere Datei <b>register_tlb.bat<\/b> die <b>regtlibv12<\/b> auf und &uuml;bergibt ihr als Parameter die <b>oleexp.tlb<\/b>. Die Registrierung verlangt &uuml;ber die <b>UAC<\/b> automatisch nach erh&ouml;hten Rechten. Die Registrierung der Bibliothek erfolgt danach ganz im Stillen. Nach diesem Vorgang k&ouml;nnen Sie die Bibliothek &uuml;ber die Verweise von VBA und den Eintrag <b>oleexp &#8211; olelib with modern interfaces by fafalone <\/b>in Ihr Projekt laden.<\/p>\n<h2>Die Klasse ExplorerBrowser<\/h2>\n<p>Im VBA-Objektkatalog stellen Sie links oben die Bibliothek <b>oleexp<\/b> ein und navigieren danach zur Klasse <b>ExplorerBrowser<\/b>. Der Objektkatalog gibt leider keine Auskunft dar&uuml;ber, ob eine Klasse instanzierbar ist oder lediglich eine Interface-Definition darstellt. Sie behelfen sich damit, dass Sie das Schl&uuml;sselwort <b>New<\/b> ins VBA-Direktfenster schreiben und die gew&uuml;nschte Bibliothek anf&uuml;gen. Etwa so:<\/p>\n<pre><span style=\"color:blue;\">New<\/span> oleexp.<\/pre>\n<p>Sobald Sie den Punkt anf&uuml;gen, zeigt <b>Intellisense<\/b> alle Klassen an, die in der <b>Library<\/b> instanzierbar sind. Beim <b>ExplorerBrowser<\/b> ist das tats&auml;chlich der Fall. Eine Instanz kann also per <b>New<\/b>-Operator erzeugt werden, und die sonst h&auml;ufig ben&ouml;tigten API-Aufrufe mit <b>CoCreateInstance<\/b> et cetera entfallen. Bild 1 zeigt die recht &uuml;berschaubaren und dennoch m&auml;chtigen Methoden der Klasse, auf die wir im Einzelnen noch zu sprechen kommen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/OBK_ExplBrowser.png\" alt=\"Die Klasse ExplorerBrowser und ihre Methoden im VBA-Objektkatalog\" width=\"500\" height=\"418,0328\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Die Klasse ExplorerBrowser und ihre Methoden im VBA-Objektkatalog<\/span><\/b><\/p>\n<p>Sie erzeugen den Explorer im Formular also, indem Sie eine modulweit g&uuml;ltige Objektvariable deklarieren und ihr eine neue Instanz der Klasse zuweisen:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>oExplBrowser<span style=\"color:blue;\"> As <\/span>oleexp.ExplorerBrowser\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n<span style=\"color:blue;\">Set<\/span> oExplBrowser = <span style=\"color:blue;\">New<\/span> oleexp.ExplorerBrowser\r\n...<\/pre>\n<p>Damit tut sich indessen noch nichts. Erst m&uuml;ssen noch einige Methoden des Objekts aufgerufen werden, die grundlegende Einstellungen anweisen. Die wichtigste davon ist die <b>Initialize<\/b>-Methode, welche dem Objekt unter anderem sagt, wo der Explorer zu platzieren ist. Dazu gleich mehr. Davor zeigt Ihnen aber Bild 2, wie das Resultat aussieht. Auf der linken Seite findet sich der Verzeichnisbaum mit allen Elementen. Nicht nur das Dateisystem ist vorhanden, sondern etwa auch Netzlaufwerke, Bibliotheken und die Systemsteuerung! Rechts zeigen sich die Elemente des Verzeichnisses. Die Spaltenk&ouml;pfe k&ouml;nnen auf gleiche Weise manipuliert werden, wie sonst auch. Der Toolbar oben enth&auml;lt dieselben Elemente, wie der <b>Windows Explorer<\/b>. Die Ansicht und das Layout k&ouml;nnen also dar&uuml;ber gesteuert werden. Selbstverst&auml;ndlich funktionieren auch <b>Drag And Drop<\/b> und alle Kontextmen&uuml;s samt gegebenenfalls installierten <b>Shell Extensions<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmExplorerSimple_RT.png\" alt=\"Im Formular fmExplorerSimple ist nur ein Windows Control im Detailbereich untergebracht, welches den Explorer abbildet\" width=\"700\" height=\"436,8964\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Im Formular fmExplorerSimple ist nur ein Windows Control im Detailbereich untergebracht, welches den Explorer abbildet<\/span><\/b><\/p>\n<p>Ein Blick in die Entwurfsansicht des Formulars (s. Bild 3) verbl&uuml;fft m&ouml;glicherweise etwas. Hier finden Sie tats&auml;chlich kein einziges Steuerelement, sondern nur den Detailbereich vor. Es ist Aufgabe der <b>Initialize<\/b>-Methode, auf dem Detailbereich das <b>ExplorerBrowser Control<\/b> zu rendern.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmExplorerSimple_DS.png\" alt=\"Die Entwurfsansicht des Formulars frmExplorerSimple stellt sich in der Tat &auml;u&szlig;erst simpel dar\" width=\"650\" height=\"443,9024\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Entwurfsansicht des Formulars frmExplorerSimple stellt sich in der Tat &auml;u&szlig;erst simpel dar<\/span><\/b><\/p>\n<h2>Initialisieren des ExplorerBrowsers<\/h2>\n<p>Die <b>Initialize<\/b>-Funktion hat folgende Syntax:<\/p>\n<pre>Initialize (hwnd<span style=\"color:blue;\"> As Long<\/span>, rct<span style=\"color:blue;\"> As <\/span>RECT,  pfs<span style=\"color:blue;\"> As <\/span>FOLDERSETTINGS)<span style=\"color:blue;\"> As Long<\/span><\/pre>\n<p>Der Aufruf dieser einen Funktion f&uuml;hrt schon zur Anzeige des Explorers im Formular &#8211; wenn denn die Parameter korrekt &uuml;bergeben werden.<\/p>\n<p>Das w&auml;re zun&auml;chst das <b>Fenster-Handle<\/b> <b>hwnd<\/b>, das angibt, auf welchem Fenster das Control angebracht werden soll. Der Typ <b>RECT<\/b> f&uuml;r die Variable <b>rct<\/b> ist ebenfalls in der <b>oleexp<\/b>-Bibliothek definiert und steuert die Positionierung des Controls:<\/p>\n<pre>Type RECT\r\n     Bottom<span style=\"color:blue;\"> As Long<\/span>\r\n     Left<span style=\"color:blue;\"> As Long<\/span>\r\n     Right<span style=\"color:blue;\"> As Long<\/span>\r\n     Top<span style=\"color:blue;\"> As Long<\/span>\r\nEnd Type<\/pre>\n<p><b>Left<\/b> ist der horizontale Abstand zum linken Rand des Host-Fensters, <b>Top<\/b> der vertikale zum oberen Rand. Die Breite und H&ouml;he des Controls ergeben sich aus <b>Right<\/b> und <b>Bottom<\/b>. Ist <b>Left<\/b> etwa <b>20<\/b> und <b>Right<\/b> <b>300<\/b>, so wird die Breite des Controls <b>280<\/b> sein. Mit <b>30<\/b> f&uuml;r <b>Top<\/b> und <b>200<\/b> f&uuml;r <b>Bottom<\/b> entsteht eine H&ouml;he von 170. Alle Angaben in Pixel.<\/p>\n<p>Der letzte Parameter <b>pfs<\/b> muss eine Variable vom Typ <b>oleexp.FOLDERSETTINGS <\/b>sein. Der Typ setzt zwei Enumerationskonstanten zusammen:<\/p>\n<pre>Type FOLDERSETTINGS\r\n     fFlags<span style=\"color:blue;\"> As <\/span>FOLDERFLAGS\r\n     ViewMode<span style=\"color:blue;\"> As <\/span>FOLDERVIEWMODE\r\nEnd Type<\/pre>\n<p><b>FOLDERFLAGS<\/b> und <b>FOLDERVIEWMODE<\/b> sind Konstanten, die &uuml;ber den <b>Or<\/b>-Operator zusammengesetzt werden k&ouml;nnen. Beispiel:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>pfs<span style=\"color:blue;\"> As <\/span>oleexp.FOLDERSETTINGS\r\npfs.fFlags = FWF_ALIGNLEFT Or FWF_NOWEBVIEW\r\npfs.ViewMode = FVM_DETAILS<\/pre>\n<p>Damit stellt das Control die Dateien dann einerseits auf <b>Links angeordnet<\/b> ein und verbietet die Web-Ansicht (<b>fFlags<\/b>), andererseits wird die Detail- beziehungsweise Report-Ansicht angeordnet (<b>ViewMode<\/b>). <b>FVM_SMALLICON<\/b> etwa w&uuml;rde zur Ansicht <b>Kleine Symbole<\/b> f&uuml;hren, <b>FVM_THUMBNAIL<\/b> zu <b>Gro&szlig;e Symbole<\/b>.<\/p>\n<p>Schon beim Initialisieren k&ouml;nnen also grundlegende Eigenschaften des Controls gesetzt werden.<\/p>\n<p>Kopfzerbrechen bereitet indessen das ben&ouml;tigte Fenster-<b>Handle<\/b> <b>hwnd<\/b>. Zwar weist auch das <b>Access<\/b>.<b>Form<\/b>-Objekt eine Eigenschaft <b>hwnd<\/b> auf, doch dieses <b>Handle<\/b> bezieht sich auf das gesamte Fenster, nicht aber auf einen Formularbereich, wie den Detailbereich. Dieser, wie auch Formularkopf oder Formularfu&szlig;, sind tats&auml;chlich eigene Fenster, die als Kindfenster des Hauptfensters fungieren. Zwar kann einer dieser Bereiche &uuml;ber die <b>Section<\/b>-Funktion des Formulars ermittelt werden (<b>Form.Section (acDetail)<\/b> etwa), doch dieses zur&uuml;ckgegebene <b>Section<\/b>-Objekt kennt kein Fenster-Handle. Wir kommen hier nicht umhin, <b>API<\/b>-Funktionen zu bem&uuml;hen. Zum Gl&uuml;ck ist der Code hierf&uuml;r nicht sonderlich kompliziert. Listing 1 zeigt eine Hilfsroutine, die bei uns zum Einsatz kommt.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Const GW_CHILD<span style=\"color:blue;\"> As Long<\/span> = 5\r\n<span style=\"color:blue;\">Private <\/span>Const GW_HWNDNEXT<span style=\"color:blue;\"> As Long<\/span> = 2 \r\n<span style=\"color:blue;\">Private <\/span>Declare Function GetClassName Lib \"user32.dll\" Alias \"GetClassNameA\" (ByVal hwnd<span style=\"color:blue;\"> As Long<\/span>, _\r\n                                                ByVal lpClassName<span style=\"color:blue;\"> As String<\/span>, ByVal nMaxCount<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>Declare Function GetWindow Lib \"user32.dll\" (ByVal hwnd<span style=\"color:blue;\"> As Long<\/span>, ByVal wCmd<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span> \r\n<span style=\"color:blue;\">Private Function <\/span>GetDetailHwnd()<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hwnd<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>ret<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>rct<span style=\"color:blue;\"> As <\/span>RECT\r\n     <span style=\"color:blue;\">Dim <\/span>sClass<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     hwnd = GetWindow(Me.hwnd, GW_CHILD)\r\n     Do\r\n         sClass = String(255, 0)\r\n         ret = GetClassName(hwnd, sClass, 255)\r\n         sClass = <span style=\"color:blue;\">Left<\/span>(sClass, ret)\r\n        hwnd = GetWindow(hwnd, GW_HWNDNEXT)\r\n     <span style=\"color:blue;\">Loop<\/span> Until sClass = \"OFormSub\"\r\n     GetDetailHwnd = hwnd\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Hilfsfunktion mit API zum Ermitteln des Fenster-Handles des Detailbereichs eines Formulars<\/span><\/b><\/p>\n<p>Sie geht vom Handle des Hauptfensters (<b>Me.hwnd<\/b>) aus und befragt dann dessen Kindfenster mit der API-Funktion <b>GetWindow<\/b>. Dazu geh&ouml;ren allerdings nicht nur die Bereiche des Formulars, sondern etwa auch andere Fensterelemente, wie die Navigationsleiste. Die Bereiche lassen sich aber dadurch identifizieren, dass sie alle den Fensterklassennamen <b>OFormSub<\/b> tragen, den die Funktion <b>GetClassName<\/b> zur&uuml;ckgibt. Grunds&auml;tzlich sind sowohl Formularkopf wie -fu&szlig; vorhanden. Sind diese ausgeblendet, so existieren die Fenster zwar, haben jedoch die H&ouml;he <b>0<\/b>. Das zweite Kindfenster ist also immer der Detailbereich. Die Schleife identifiziert den Klassennamen und bricht ab, wenn der korrekte Name gefunden wurde. Da dann bereits das n&auml;chste Kindfenster &uuml;ber <b>GetWindow<\/b> mit <b>GW_HWNDNEXT<\/b> enumeriert wurde, steht in <b>hwnd<\/b> das richtige Handle, welches als R&uuml;ckgabewert der Funktion dient.<\/p>\n<p>Damit haben wir bereits alle n&ouml;tigen Bestandteile beisammen, um das Formular mit eingebettetem Explorer zum Laufen zu bringen. Den Code des Beispielformulars mit dem kleinsten Aufwand (<b>frmExplorerMinimal<\/b>) demonstriert Listing 2. Die ganze Instanzierung des Explorer Controls findet im Ereignis <b>Form_Load<\/b> statt.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>oExplBrowser<span style=\"color:blue;\"> As <\/span>oleexp.ExplorerBrowser\r\n<span style=\"color:blue;\">Private <\/span>lPIDL<span style=\"color:blue;\"> As Long<\/span>, hwndDetail<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>rct<span style=\"color:blue;\"> As <\/span>oleexp.RECT\r\n     <span style=\"color:blue;\">Dim <\/span>pfs<span style=\"color:blue;\"> As <\/span>oleexp.FOLDERSETTINGS\r\n     \r\n     pfs.fFlags = FWF_ALIGNLEFT Or FWF_NOWEBVIEW\r\n     pfs.ViewMode = FVM_DETAILS\r\n     rct.Bottom = Me.Section(acDetail).Height \\ 15\r\n     rct.<span style=\"color:blue;\">Right<\/span> = Me.InsideWidth \\ 15\r\n     <span style=\"color:blue;\">Set<\/span> oExplBrowser = <span style=\"color:blue;\">New<\/span> oleexp.ExplorerBrowser\r\n     oExplBrowser.Initialize GetDetailHwnd, rct, pfs\r\n     oExplBrowser.SetOptions EBO_SHOWFRAMES\r\n     lPIDL = SHGetSpecialFolderLocation(ByVal 0&, _\r\n         CSIDL_DESKTOP)\r\n     oExplBrowser.BrowseToIDList lPIDL, SBSP_ABSOLUTE\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     oExplBrowser.Destroy\r\n     oleexp.CoTaskMemFree lPIDL\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n(Zur &lt;b&gt;Hilfsfunktion GetDetailHwnd siehe Listing 1)<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Der komplette Inhalt des Formulars frmExplorerMinimal<\/span><\/b><\/p>\n<p>Erst werden die zwei Teile der <b>FOLDERSETTINGS<\/b>-Variablen <b>pfs<\/b> mit Vorgabewerten best&uuml;ckt. Selbst das k&ouml;nnte im Prinzip entfallen, da beide dann eben den Wert <b>0<\/b> enthielten. Zwar gibt es eigentlich keine von Microsoft deklarierte <b>ViewMode<\/b>-Konstante, die diesem Wert entspricht, ein Fehler ereignet sich dabei aber nicht. Die Ansicht stellt sich bei Auskommentieren der beiden Zeilen einfach auf <b>Gro&szlig;e Symbole<\/b> ein. Die <b>Flags<\/b>-Konstanten sind ohnehin alle optional.<\/p>\n<p>Das Setzen der Abmessungen des Controls &uuml;ber die <b>RECT<\/b>-Variable <b>rct<\/b> allerdings ist zwingend erforderlich. F&uuml;r <b>Left<\/b> und <b>Right<\/b> bleibt es bei <b>0<\/b>, was das Control in der linken oberen Ecke des Detailbereichs anordnet. Die H&ouml;he in Bottom ergibt sich aus der H&ouml;he des Detailbereichs (<b>Section acDetail<\/b>), wobei der Wert durch Division mit <b>15<\/b> von <b>Twips<\/b> nach <b>Pixel<\/b> umgewandelt wird. Die Breite des Controls ergibt sich aus der des Formulars selbst (<b>InsideWidth<\/b>). Schlie&szlig;lich wird f&uuml;r die per <b>New<\/b> erzeugte Instanz <b>oExplBrowser<\/b> die <b>Initialize<\/b>-Methode aufgerufen und das Fenster-Handle des Detailbereichs &uuml;ber die Hilfsfunktion <b>GetDetailHwnd<\/b> (Listing 1) &uuml;bergeben.<\/p>\n<p>Nicht erw&auml;hnt haben wir bisher die Methode <b>SetOptions<\/b> des <b>ExplorerBrowser<\/b>-Objekts. Die hier anzugebenden Konstanten steuern das Gesamtlayout des Controls. Wichtig etwa ist das Setzen von <b>EBO_SHOWFRAMES<\/b>. Erst diese Zuweisung sagt dem Control, dass es den Explorer komplett nachbilden soll, und Treeview sowie Toolbar anzeigen soll. Unterbleibt das, so zeigt es lediglich die Dateiansicht an, wie in Bild 4. F&uuml;r diese gibt es sicher ebenfalls Anwendungsf&auml;lle.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmMinimal_NoFrames.png\" alt=\"Ist EBO_SHOWFRAMES nicht gesetzt, so zeigt das Control nur den rechten Teil des Explorers\" width=\"650\" height=\"389,1231\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Ist EBO_SHOWFRAMES nicht gesetzt, so zeigt das Control nur den rechten Teil des Explorers<\/span><\/b><\/p>\n<p>Unterschlagen haben wir auch, dass das Control erst wissen muss, welches Verzeichnis des Systems es &uuml;berhaupt anzeigen soll. Dies &uuml;bernimmt seine Methode <b>BrowseToIDList<\/b>. L&auml;sst man sie weg, so zeigt das Control nur eine wei&szlig;e Fl&auml;che.<\/p>\n<p>Die Methode erwartet eine sogenannte <b>ID-List<\/b>. Das ist in der <b>Shell<\/b>-Welt im Grunde eine eindeutige <b>ID<\/b> eines Verzeichnisses oder einer Datei. Einen String f&uuml;r einen Verzeichnispfad kann man hier nicht angeben, sondern m&uuml;sste diesen erst &uuml;ber eine Hilfsfunktion in eine <b>ID<\/b> umwandeln. Das erl&auml;utern wir sp&auml;ter. Die andere hier verwendete Option ist das Ermitteln einer <b>ID<\/b> f&uuml;r einen der Standardordner von Windows &uuml;ber die API-Funktion <b>SHGetSpecialFolderLocation<\/b>. Ihr &uuml;bergibt man die Konstante eines der Standardordner, wobei <b>CLSID_DESKTOP<\/b> den Desktop symbolisiert. M&ouml;chten Sie zu den Laufwerken navigieren, wie in Bild 4, so geben Sie stattdessen die Konstante <b>CLSID_DRIVES<\/b> an. Die m&ouml;glichen Konstanten sehen Sie im Objektkatalog zur Bibliothek <b>oleexp<\/b> unter der Liste <b>CSIDLs<\/b> ein.<\/p>\n<p>Die ermittelte <b>ID<\/b> speichert die formularglobale Variable <b>lPIDL<\/b>. Sie wird <b>BrowseToIDList<\/b> &uuml;bergeben. Der zweite Parameter <b>SBSP_ABSOLUTE<\/b> sagt ihr zus&auml;tzlich, dass ein absoluter Sprung zum Ordner erfolgen soll. M&ouml;glich w&auml;re auch ein relativer Sprung, den wir hier aber nicht erkl&auml;ren, weil dies zu deutlich h&ouml;herem Aufwand f&uuml;hren w&uuml;rde.<\/p>\n<p>Mehr gibt es nicht zu tun. Die gerade 40 Zeilen des Formularcodes zeigen, wie einfach ein Explorer anzulegen ist. Beim Schlie&szlig;en des Formulars (<b>Form_Unload<\/b>) muss allerdings der Explorer wieder abgebaut werden, damit es nicht zu Speicherlecks oder Abst&uuml;rzen kommt. Die <b>Destroy<\/b>-Methode veranlasst dies. Au&szlig;erdem sollte die erhaltene Ordner-ID in l<b>PIDL<\/b> noch freigegeben werden, was &uuml;ber die API-Funktion <b>CoTaskMemFree<\/b> geschieht. Wir haben damit nun einen funktionsf&auml;higen Explorer im Formular. W&uuml;nschenswert w&auml;re allerdings noch eine erweiterte Einflussnahme auf seine Gestalt und sein Verhalten, wie auch zus&auml;tzlich Interaktion mit dem Control und den angezeigten Ordnern und Dateien. Die aufgebohrte Version mit allerlei Zusatz-Features nennt sich in der Beispieldatenbank <b>frmExplorerCtl<\/b>.<\/p>\n<h2>Das Ultra-Komplettbeispiel<\/h2>\n<p>Bild 5 zeigt dieses Formular zur Laufzeit. Beschreiben wir kurz seine Funktionalit&auml;t. Alle Bezeichnungen sind in Englisch gehalten, damit der Bezug zu den Methoden im VBA-Code etwas deutlicher wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmExplorerCtl_RT.png\" alt=\"Im Formular frmExplorerCtl k&ouml;nnen unten verschiedene Einstellungen des Explorer Controls zur Laufzeit vorgenommen werden\" width=\"700\" height=\"503,9176\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Im Formular frmExplorerCtl k&ouml;nnen unten verschiedene Einstellungen des Explorer Controls zur Laufzeit vorgenommen werden<\/span><\/b><\/p>\n<p>Zun&auml;chst sind im Formular auch Kopf und Fu&szlig; angezeigt. Das Explorer Control befindet sich ausf&uuml;llend im Detailbereich. Im Formularkopf bewirkt ein Klick auf die Schaltfl&auml;che <b>Reset to &#8220;&#8220;Computer&#8220;&#8220;<\/b> den Sprung zu eben diesem Spezialordner, also der Laufwerks&uuml;bersicht. Haben Sie sich im Explorer durch diverse Verzeichnisse gehangelt, so gelangen Sie &uuml;ber den Button <b>Back<\/b> zum vorigen Verzeichnis, mit <b>Forward<\/b> zum n&auml;chsten, so wie bei der Navigation im richtigen Explorer auch. <b>Dir Up<\/b> schaltet eine Verzeichnisebene aufw&auml;rts, falls m&ouml;glich. Beim Desktop klappt das nat&uuml;rlich nicht. Die Textbox oben rechts zeigt das aktuelle Verzeichnis an. Dies entspricht der Adresszeile des Explorers. Eine Eingabe ist hier allerdings nicht m&ouml;glich. Bei speziellen Elementen, wie denen der Systemsteuerung etwa, bleibt die Textbox leer.<\/p>\n<p>Rechts unten gibt es eine mehrzeilige Textbox, die der Ausgabe von durch das Control ausgel&ouml;sten Ereignissen dient wie auch der weiterer Informationen. In der Abbildung ist zu erkennen, dass etwa die Navigation zu Verzeichnissen abgefangen werden kann. Auch die Markierung von Dateien bleibt dem Formularcode nicht verborgen.<\/p>\n<p>Im linken Bereich des Formularfu&szlig;es k&ouml;nnen &uuml;ber zahlreiche Checkboxen und Optionsfelder Einstellungen f&uuml;r das Control vorgenommen werden. Diese beziehen sich allerdings alle auf die Dateiansicht im rechten Rahmen, der sogenannten <b>Folder View<\/b>. Dabei k&ouml;nnen Sie mit einem Klick auf die Schaltfl&auml;che <b>Get<\/b> die momentane Konfiguration der <b>Folder View<\/b> ermitteln. Die Checkboxen werden dann gem&auml;&szlig; der Ansicht markiert. &auml;ndern Sie einzelne Markierungen, so wirken sich die neuen Einstellungen erst nach Klick auf den roten Button <b>Apply view settings<\/b> aus. <\/p>\n<p>In der Mitte des Formularfu&szlig;es schlie&szlig;lich k&ouml;nnen Sie &uuml;ber die vier blauen Schaltfl&auml;chen verschiedene Aktionen ausl&ouml;sen, die lediglich als Beispiele die Steuerungsm&ouml;glichkeiten des Controls demonstrieren sollen. <b>Edit 5th item<\/b> etwa markiert das f&uuml;nfte Element von oben in der Dateiansicht und bringt es in editierbaren Zustand, sodass Sie dessen Namen &auml;ndern k&ouml;nnen. Es spielt dabei keine Rolle, ob es sich um eine Datei oder ein Verzeichnis handelt.<\/p>\n<p><b>Select items with &#8220;&#8220;P*&#8220;&#8220;<\/b> markiert alle Elemente in der Ansicht, die mit dem Buchstaben <b>P<\/b> beginnen. <b>Search for &#8220;&#8220;*.pdf&#8220;&#8220;<\/b> st&ouml;&szlig;t eine Suche nach allen Elementen Im Verzeichnis und seinen Unterverzeichnissen an, die PDF-Dokumente darstellen. Dabei bildet sich eine neue <b>View<\/b> mit den Suchergebnissen. <b>Circle Items <\/b>markiert visuell alle Elemente in der Ansicht der Reihe nach von oben nach unten mit einem Intervall von 80 Millisekunden. <b>Sort By File Size DESC <\/b>sortiert die Ansicht der Dateien nach deren Dateigr&ouml;&szlig;e absteigend, also nach der Spalte <b>Gr&ouml;&szlig;e<\/b>.<\/p>\n<p>Die Optionsfelder dienen der Einstellung des Ansichtsmodus. <b>Report view <\/b>etwa zeigt die Detailansicht, <b>Small icons<\/b> zeigt <b>Kleine Symbole<\/b>, <b>Thumbnail view<\/b> Miniaturabbilder. Diese Einstellung k&ouml;nnen Sie ja auch manuell &uuml;ber den Toolbar des Controls vornehmen. Bei allen Optionen f&uuml;r eine Symboldarstellung aktiviert sich zus&auml;tzlich rechts das Kombinationsfeld <b>Icon Size<\/b>. &uuml;ber dieses k&ouml;nnen Sie dann au&szlig;erdem die quadratische Gr&ouml;&szlig;e der Symbol-Icons bestimmen. Erlaubt sind hier Angaben von <b>16&#215;16<\/b> bis <b>256&#215;256<\/b>. <\/p>\n<p>Ganz in der Mitte befindet sich eine kleine Textbox mit der &uuml;berschrift <b>Sort String<\/b>. Hier zeigt sich nach Klick auf den <b>Get<\/b>-Button die aktuelle Sortierung der <b>View<\/b>, wie das Control sie intern ausgibt. Sie beginnt immer mit dem Pr&auml;fix <b>prop:<\/b>. Sind die Elemente nach Namen sortiert, so nennt sich die Sortierspalte <b>System.ItemsNameDisplay<\/b>. Sie k&ouml;nnen diesen String auch modifizieren! Geben Sie etwa <b>System.ModifiedDate<\/b> an, so sortiert sich die Ansicht nach dem &auml;nderungsdatum der Elemente, nachdem Sie auf den <b>Apply<\/b>-Button klicken. Eine absteigende Sortierung erreichen Sie &uuml;brigens, indem Sie nach <b>prop:<\/b> ein Minuszeichen einsetzen.<\/p>\n<p>Zu erl&auml;utern w&auml;re schlie&szlig;lich noch die Checkbox <b>Allow file drop<\/b> unten. Ist sie aktiviert, so k&ouml;nnen Sie von au&szlig;erhalb des Formulars Dateien oder Verzeichnisse in die View ziehen und l&ouml;sen damit den normalen Kopier-, Verschiebe- oder Verkn&uuml;pfungsvorgang aus. Ist sie deaktiviert, so werden diese Aktionen unterbunden. Allerdings taucht dann trotzdem zur Information eine Messagebox auf, die den oder die Namen der <b>gedragten <\/b>Elemente ausgibt.<\/p>\n<p>Trotz der zahlreichen Features des Formulars beschr&auml;nkt sich sein Code auf circa 360 &uuml;berschaubare Zeilen, von denen etliche Kommentare enthalten.<\/p>\n<p>Was noch auf unserer ToDo-Liste steht gleich vorneweg: Es ist uns nicht gelungen, einzelne Bereiche des Controls ein- und auszuschalten. &uuml;ber <b>SetOptions<\/b> (s. Listing 2) und <b>EBO_SHOWFRAMES<\/b> kann bisher nur die Sichtbarkeit des Treeviews des Controls gesteuert werden. Den Toolbar ausschalten klappt indessen nicht. Zwar sieht Microsoft diese M&ouml;glichkeit im Prinzip vor, der dazu ben&ouml;tigte Umgang mit speziellen Interfaces und einer Callback-Funktion &uuml;berfordert VBA &#8211; oder uns &#8211; jedoch etwas. Zusammengefasst kann mit dem Control in vielerlei Hinsicht &uuml;ber VBA interagiert werden. Schauen wir uns im Folgenden an, wie die Programmierung der einzelnen Features gelingt.<\/p>\n<h2>Verweise des VBA-Projekts<\/h2>\n<p>F&uuml;r einige Aufgaben ben&ouml;tigen wir einen Bezug auf Klassenobjekte, die in der Bibliothek <b>OLEEXP<\/b> nicht vorhanden sind. Das sind vornehmlich Objekte der <b>Windows Shell <\/b>und deren <b>Interfaces<\/b>. Man findet sie aber alle in Komponenten von Windows. Alle hier aufgef&uuml;hrten Bibliotheken sind Bestandteil von Windows und brauchen deshalb nicht registriert zu werden. Bild 6 zeigt diese <b>Libraries<\/b> im Verweise-Dialog des Projekts.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/References.png\" alt=\"Alle Verweise des Datenbank-VBA-Projekts stammen mit Ausnahme der Bibliothek OLEEXP aus g&auml;ngigen Windows- und Office-Komponenten\" width=\"500\" height=\"383,2977\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Alle Verweise des Datenbank-VBA-Projekts stammen mit Ausnahme der Bibliothek OLEEXP aus g&auml;ngigen Windows- und Office-Komponenten<\/span><\/b><\/p>\n<p>Elementar ist die Bibliothek <b>Microsoft Shell Controls And Automation<\/b>, welche sich in der Systemdatei <b>shell32.dll<\/b> befindet. Sie enth&auml;lt einige Klassen, die auch vom Browser Control verwendet werden. Der Verweis auf die <b>Microsoft Forms 2.0 Object Library<\/b> w&auml;re an sich nicht erforderlich. Er l&auml;sst sich jedoch &uuml;ber den normalen <b>Verweise-Dialog<\/b> eigenartigerweise nicht mehr entfernen, nachdem er einmal gesetzt wurde. Den Verweis auf die <b>OLEEXP<\/b>-Bibliothek erl&auml;uterten wir ja bereits.<\/p>\n<h2>Browser Control resizen<\/h2>\n<p><!--30percent--><\/p>\n<p>Der <b>Initialize<\/b>-Methode des <b>ExplorerBrowser<\/b>-Objekts gibt man &uuml;ber den <b>RECT<\/b>-Parameter mit, wie gro&szlig; die Ausdehnung des Controls im Formularfenster ausfallen soll. Man ist auf diese jedoch nicht festgelegt. Auch zur Laufzeit k&ouml;nnen Sie &uuml;ber die Methode <b>SetRect<\/b> eine andere Gr&ouml;&szlig;e anweisen. Das ist praktisch, um das Control immer auf die Gr&ouml;&szlig;e des Detailbereichs zu bringen, wenn das Formular ver&auml;ndert wird. Also setzen Sie in das Ereignis <b>Bei Gr&ouml;&szlig;en&auml;nderung<\/b> des Formulars etwa den Code aus Listing 3.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Resize()\r\n     <span style=\"color:blue;\">Dim <\/span>x<span style=\"color:blue;\"> As Long<\/span>, y<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>rct<span style=\"color:blue;\"> As <\/span>RECT\r\n     \r\n     <span style=\"color:blue;\">If <\/span>oExplBrowser Is Nothing<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n     \r\n     GetWindowRect GetDetailHwnd, rct\r\n     y = rct.Bottom - rct.Top\r\n     x = Me.InsideWidth \\ 15\r\n     oExplBrowser.SetRect 0, 0, 0, x, y\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Das Control macht hiermit Gr&ouml;&szlig;en&auml;nderungen mit<\/span><\/b><\/p>\n<p>Zur Sicherheit wird hier abgefragt, ob das Browser Control &uuml;berhaupt erzeugt wurde. Dann ist der Inhalt der zust&auml;ndigen Objektvariablen <b>oExplBrowser<\/b> nicht <b>Nothing<\/b>. Anschlie&szlig;end ermittelt die API-Funktion <b>GetWindowRect<\/b> abermals die Ausdehnung des Detailbereichs &uuml;ber dessen Fenster-Handle, welches Sie &uuml;ber die schon erw&auml;hnte Hilfsfunktion <b>GetDetailHwnd<\/b> bekommen. Die H&ouml;he wird in der Variablen <b>y<\/b> gespeichert. Die Breite k&ouml;nnte eigentlich ebenfalls aus dem <b>RECT<\/b>-Typ <b>rct<\/b> ausgelesen werden; wir nehmen hier jedoch die Breite des Formulars selbst in <b>InsideWidth<\/b>. <b>SetRect<\/b> erwartet dann als ersten Parameter ein <b>Pseudo-Handle<\/b>, das wir unbeachtet lassen, und deshalb <b>0<\/b> zuweisen. Die n&auml;chsten beiden Parameter geben die linke obere Ecke des Controls im Detailbereich an, also dessen x- und y-Koordinaten. Auch hier verwenden wir <b>0<\/b>. Dann folgen Breite und H&ouml;he des Controls, die in den Variablen x und y gespeichert sind. Damit macht das Control alle Gr&ouml;&szlig;en&auml;nderungen des Formulars mit, so als w&auml;re es mit dem <b>Verankern<\/b>-Feature von Access ausgestattet.<\/p>\n<h2>Ereignisse abfangen<\/h2>\n<p>Wie Sie aus dem Objektkatalog (Bild 1) ablesen k&ouml;nnen, l&ouml;st das <b>ExplorerBrowser<\/b>-Objekt selbst keine Ereignisse aus. Daf&uuml;r ist n&auml;mlich ein separates <b>Interface<\/b> namens <b>IExplorerBrowserEvents<\/b> zust&auml;ndig (Bild 7). Und Sie m&uuml;ssen dem Objekt erst mitteilen, wo sich dieses <b>Interface<\/b> befindet. Wie aber kann eine Instanz dieser <b>Interface<\/b>-Klasse angelegt werden<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/OBK_BrowserEvents.png\" alt=\"Die Klasse IExplorerBrowserEvents im VBA-Objektkatalog\" width=\"500\" height=\"297,1312\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Die Klasse IExplorerBrowserEvents im VBA-Objektkatalog<\/span><\/b><\/p>\n<p>Hier kommt das selten genutzte Schl&uuml;sselwort <b>Implements<\/b> von VBA ins Spiel. In den Kopf des Moduls schreiben Sie das:<\/p>\n<pre>Implements IExplorerBrowserEvents<\/pre>\n<p>Beim Kompilieren weist VBA Sie nun per Fehler darauf hin, dass die Methoden dieser Schnittstelle im Modul eingebaut sein m&uuml;ssen. Sie suchen also in der linken oberen Combo des Modulfensters den Eintrag <b>IExplorer-BrowserEvents<\/b> heraus, worauf Sie in der rechten die einzelnen Methoden der Schnittstellen ausw&auml;hlen k&ouml;nnen. VBA legt dabei automatisch die zugeh&ouml;rigen Prozeduren an, &auml;hnlich wie bei den Ereignissen einer Objektvariablen. Damit ist in der Formularklasse zus&auml;tzlich das Interface <b>IExplorerBrowserEvents<\/b> integriert. Es muss nur noch eine Verbindung zwischen Control und der Formularklasse hergestellt werden. Das &uuml;bernimmt die Methode <b>Advise<\/b> des <b>ExplorerBrowsers<\/b>:<\/p>\n<pre>Implements IExplorerBrowserEvents\r\n<span style=\"color:blue;\">Private <\/span>lEventCookie<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     ...\r\n     oExplBrowser.Advise Me, lEventCookie\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnNavigationPending _\r\n     (ByVal pidlFolder<span style=\"color:blue;\"> As Long<\/span>)\r\n''''...\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnNavigationComplete _\r\n     (ByVal pidlFolder<span style=\"color:blue;\"> As Long<\/span>)\r\n<span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnNavigationFailed _\r\n     (ByVal pidlFolder<span style=\"color:blue;\"> As Long<\/span>)\r\n<span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnViewCreated _\r\n     (ByVal psv<span style=\"color:blue;\"> As <\/span>oleexp.IShellView)<\/pre>\n<p>Der Methode <b>Advise<\/b> wird das Objekt &uuml;bergeben, welches die Schnittstelle <b>IExplorerBrowserEvents<\/b> implementiert &#8211; hier das Formularobjekt durch <b>Me<\/b> -, sowie eine Variable, welche eine <b>ID<\/b> f&uuml;r die Verbindung entgegennimmt.<\/p>\n<p>Sie wird noch ben&ouml;tigt und ist deshalb im Modulkopf als Variable <b>lEventCookie<\/b> vom Typ <b>Long<\/b> deklariert. Beim Entladen des Formulars sollte diese Verbindung wieder getrennt werden. Das wiederum geschieht &uuml;ber die Methode <b>UnAdvise<\/b> des <b>Exlorer-Browsers<\/b>:<\/p>\n<pre>olExplBrowser. UnAdvise lEventCookie<\/pre>\n<p>Es gibt also vier Ereignisse, die das Control selbst ausl&ouml;sen kann. <b>OnNavigationPending<\/b> passiert bei Anwahl eines Verzeichnisses im Treeview des Controls. Es besagt, dass die Navigation zum ihm noch aussteht. Der gew&auml;hlte Ordner wird dabei durch den Parameter <b>pidlFolder<\/b> &uuml;bergeben.<\/p>\n<p>Er kann dann mithilfe einer API-Funktion in einen Verzeichnis-String umgewandelt werden:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>GetPathFromPidl(pidl<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>pszPath<span style=\"color:blue;\"> As String<\/span>\r\n     pszPath = String(MAX_PATH, 0)\r\n     <span style=\"color:blue;\">If <\/span>SHGetPathFromIDListW(pidl, StrPtr(pszPath))<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(pszPath, vbNullChar)<span style=\"color:blue;\"> Then<\/span>\r\n             GetPathFromPidl = Left$(pszPath, <span style=\"color:blue;\">InStr<\/span>(pszPath, vbNullChar) - 1)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b>SHGetPathFromIDListW<\/b> ist hier f&uuml;r die Umwandlung zust&auml;ndig. Die API-Funktion ist im Kopf des Formularmoduls definiert. Im Beispiel s&auml;he die Verwendung der Hilfsfunktion etwa so aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnNavigationPending _\r\n     (ByVal pidlFolder<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> GetPathFromPidl( pidlFolder)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sobald Sie ein Verzeichnis im Control ausw&auml;hlen, wird dessen Pfad nun im VBA-Direktfenster ausgegeben. Im Beispielformular allerdings protokolliert die Prozedur <b>AddToLog<\/b> das Ereignis in der entsprechenden Textbox.<\/p>\n<p>Das Control muss nun die <b>Folder View<\/b>, also die rechte Ansicht des Explorers, erzeugen. Ist das von Erfolg gekr&ouml;nt, so tritt das Ereignis <b>OnViewCreated <\/b>auf den Plan. Als Parameter &uuml;bergibt es eine Interface-Variable <b>psv<\/b> des Typs <b>IShellView<\/b>.<\/p>\n<p>Diese Schnittstelle ist ebenfalls in der Bibliothek <b>OLEEXP <\/b>definiert. Man ben&ouml;tigt einen Verweis auf diese Schnittstelle, um sp&auml;ter an die Elemente der Datei-und Ordnerliste heranzukommen. Deshalb wird in der Demo ein Verweis auf sie in der Formularvariablen <b>IShView <\/b>abgelegt:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>IShView<span style=\"color:blue;\"> As <\/span>oleexp.IShellView \r\n<span style=\"color:blue;\">Private Sub <\/span>IExplorerBrowserEvents_OnViewCreated _\r\n                                                                            (ByVal psv<span style=\"color:blue;\"> As <\/span>oleexp.IShellView)\r\n     AddToLog \"View created\"\r\n     <span style=\"color:blue;\">Set<\/span> IShView = psv\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Es kann sein, dass die Navigation zu einem Verzeichnis im Control fehlschl&auml;gt. Dies w&auml;re etwa der Fall, wenn Sie eine ung&uuml;ltige <b>ID-List<\/b> als Parameter an die Methode <b>BrowserToIDList <\/b>&uuml;bergeben. In diesem Fall ereignet sich <b>OnNavigationFailed<\/b>.<\/p>\n<p>Ist der ganze Vorgang abgeschlossen, also das Verzeichnis im Treeview markiert und die <b>Folder View<\/b> dazu aufgebaut, so kommt es zum Ereignis <b>NavigationComplete<\/b>, auch hier wieder unter Angabe des angezeigten Ordners in <b>pidlFolder<\/b>.<\/p>\n<p>&uuml;ber diese Ereignisse haben Sie also im Formularcode volle Kontrolle &uuml;ber die Verzeichnisse, zu denen im Control navigiert wird. Zugriff auf die Dateien und andere Elemente der <b>Folder View<\/b> besteht indessen noch nicht. Der <b>ExplorerBrowser<\/b> selbst enth&auml;lt hierf&uuml;r keinerlei Methoden. Die liefert erst die <b>ShellView<\/b>, welche &uuml;ber das Ereignis <b>OnViewCreated<\/b> zur&uuml;ckgeliefert und in der Variablen <b>ShView<\/b> zwischengespeichert wurde. Und hier wird es leider kompliziert, denn das Interface <b>IShellView<\/b> l&ouml;st selbst wiederum keine Ereignisse aus. Es sind einige Tricks vonn&ouml;ten, um aus der Schnittstelle ein neues Objekt abzuleiten, welches Ereignisse unterst&uuml;tzt.<\/p>\n<p>Und das ist die Klasse <b>ShellFolderView<\/b> der Bibliothek <b>Shell32<\/b>, die wir in die Verweise des VBA-Projekts aufnahmen.  Nehmen Sie sie im Objektkatalog unter die Lupe (Bild 8). Neben verschiedenen Properties oben, die vor allem das Layout der Elemente der <b>View<\/b> bestimmen, gibt es f&uuml;nf Methoden zu ihrer Steuerung und f&uuml;nf Ereignisse, die ausgel&ouml;st werden, wenn Sie Aktionen auf die Elemente ausf&uuml;hren. Das kann das Markieren von Dateien oder Verzeichnissen sein (<b>SelectionChanged<\/b>), das Ziehen von Elementen (<b>BeginDrag<\/b>) oder eine Aktion durch Doppelklicken beziehungsweise &uuml;ber das Kontextmen&uuml; eines Elements (<b>VerbInvoked<\/b>, <b>DefaultVerbInvoked<\/b>). <b>EnumDone<\/b> passiert dann, wenn alle Elemente eines Verzeichnisses vom Control ermittelt wurden, und hat damit lediglich informativen Charakter.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/OB_ShellFolderView.png\" alt=\"Die Klasse ShellFolderView der Shell32-Bibliothek zeigt ihre Methoden und Ereignisse im VBA-Objektkatalog\" width=\"425\" height=\"555,85\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Die Klasse ShellFolderView der Shell32-Bibliothek zeigt ihre Methoden und Ereignisse im VBA-Objektkatalog<\/span><\/b><\/p>\n<p>Am Interessantesten ist sicher das Ereignis <b>SelectionChanged<\/b>. &auml;ndern Sie etwa die Markierung oder Auswahl von Dateien im Control, so kommt es immer zu diesem Ereignis. Es &uuml;bergibt allerdings keinen Parameter, aus dem sich etwas &uuml;ber die Art der Auswahl ableiten lie&szlig;e. Daf&uuml;r w&auml;re dann die Methode <b>SelectedItems<\/b> zu bem&uuml;hen, die eine Liste von <b>FolderItems<\/b> zur&uuml;ckgibt. Dazu sp&auml;ter mehr.<\/p>\n<p>Die Frage ist nun, wie man &uuml;ber die vom Control im Ereignis <b>OnViewCreated<\/b> erhaltene <b>ShellView<\/b> zu diesem Objekt <b>ShellFolderView<\/b> gelangt. Im Formularklassenmodul geschieht dies &uuml;ber die ausgelagerte Hilfsroutine <b>ConnectToView<\/b>. Ihr Aufruf wird direkt im entsprechenden Ereignis <b>OnViewCreated <\/b>vollzogen:<\/p>\n<pre>ConnectToView<\/pre>\n<p>Den Code der Routine finden Sie etwas gek&uuml;rzt in Listing 4. Die Funktion <b>GetItemObject<\/b> der <b>IShellView<\/b> wird aufgerufen und dabei als Ergebnis durch das Flag <b>SVGIO_BACKGROUND<\/b> deren sogenanntes <b>Dispatch<\/b>-Interface abgefragt. Eben das ist die <b>ShellFolderView<\/b>, welche die Objektvariable <b>oViewObj <\/b>entgegennimmt. Sie ist im Modul oben deklariert:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ConnectToView()\r\n     DisconnectFromView\r\n     \r\n     IShView.GettemObject SVGIO_Flags.SVGIO_BACKGROUND, _\r\n                                                     IIDDispatch, oViewObj\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> oViewObj Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         If 0 = ConnectToConnectionPoint(Me, _\r\n                               IID_DShellFolderViewEvents, 1&, _\r\n                               oViewObj, lCookie, Nothing) Then\r\n             <span style=\"color:blue;\">Set<\/span> oViewDispatch = oViewObj\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>DisconnectFromView()\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> oViewObj Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         ConnectToConnectionPoint Nothing, _\r\n                                     IID_DShellFolderViewEvents, _\r\n                                     0&, oViewObj, lCookie, Nothing\r\n         <span style=\"color:blue;\">Set<\/span> oViewDispatch = Nothing\r\n         <span style=\"color:blue;\">Set<\/span> oViewObj = Nothing\r\n         lCookie = 0&\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Erhalten des ShellFolderView-Objekts oViewObj<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private <\/span>oViewObj<span style=\"color:blue;\"> As <\/span>Shell32.ShellFolderView<\/pre>\n<p>Dieses Objekt l&ouml;st leider noch keine Ereignisse aus, weil es ohne die Anweisung <b>WithEvents<\/b> deklariert ist. F&uuml;gten Sie diese ein, so passierte trotzdem nichts und die Ereignisse unterblieben. Grund daf&uuml;r ist, dass die Verbindung zur Ereignisschnittstelle f&uuml;r die <b>ShellView<\/b> noch nicht hergestellt ist. Wir fanden aber eine geniale API-Funktion unter Windows, die diese Verbindung herstellen kann: <b>ConnectToConnectionPoint<\/b>. Ihr &uuml;bergeben Sie die Formularklasse (<b>Me<\/b>) und die gew&uuml;nschte Event-Schnittstelle <b>DShellFolderViewEvents<\/b> in Form einer <b>GUID<\/b>, welche in der <b>Shell32<\/b>-Bibliothek definiert ist. Auch hier ist, wie bei der <b>Advise<\/b>-Methode des <b>Explorer-Browsers<\/b>, ein <b>Event-Cookie<\/b> (<b>lCookie<\/b>) zu benutzen, welches sp&auml;ter zum Kappen der Ereignisbindung ben&ouml;tigt wird. &uuml;ber diese API-Funktion ist nun die Verbindung zwischen <b>ShellView<\/b> und Formular erzwungen, weshalb auch Ereignisse an in ihm deklarierten Objektvariablen weitergeleitet werden. Das eigentliche Objekt, welches die Ereignisse ausl&ouml;st, ist <b>oViewDispatch<\/b>, definiert im Modulkopf:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Withevents oViewDispatch<span style=\"color:blue;\"> As <\/span>Shell32.ShellFolderView<\/pre>\n<p>F&uuml;r dieses Objekt k&ouml;nnen Sie nun auf gewohnte Weise die f&uuml;nf Ereignisprozeduren anlegen. <\/p>\n<p>Es reicht allerdings nicht, die Verbindung zu dieser Schnittstelle nur einmal zuzuweisen, denn bei jeder neuen Verzeichniswahl im Control wird auch eine neue <b>ShellView<\/b> erzeugt. Deshalb auch der Aufruf der Routine aus dem Ereignis <b>OnViewCreated<\/b>. Bevor eine Neuzuweisung passiert, muss die gegebenenfalls bestehende alte Verbindung aber gel&ouml;st werden. Das &uuml;bernimmt die zweite Prozedur <b>DisconnectFromView<\/b>, welche sich ebenfalls der API-Funktion <b>ConnectToConnectionPoint<\/b> bedient, nur dass hier als Zielobjekt nicht <b>Me<\/b>, sondern <b>Nothing<\/b> angegeben wird. Auch das zuvor erhaltene <b>Event-Handle lCookie<\/b> muss dabei angegeben werden.<\/p>\n<p>&uuml;ber das nunmehr instanzierte <b>ShellFolderView<\/b>-Objekt haben Sie Zugriff auf alle Methoden in Bild 8. Zun&auml;chst interessiert Sie hier wohl das Ereignis <b>SelectionChanged<\/b>. Setzen Sie eine Ereignisroutine ein, wie in Listing 5. Die Funktion <b>SelectedItems<\/b> gibt eine Auflistung des Typs <b>Shell32.FolderItems<\/b> zur&uuml;ck, welche &uuml;ber eine <b>For-Each<\/b>-Schleife enumeriert werden kann. Die Elemente der Auflistung wiederum sind <b>FolderItem<\/b>-Objekte. Die Eigenschaft <b>Path<\/b> gibt Auskunft &uuml;ber den Pfad des Objekts. Dabei kann es sich wohlgemerkt sowohl um eine Datei wie auch um ein Verzeichnis handeln. Um was es geht, ermitteln Sie &uuml;ber die booleschen Eigenschaften <b>IsFolder <\/b>(Verzeichnis) oder <b>IsLink<\/b> (Verkn&uuml;pfung) eines <b>FolderItem<\/b>-Objekts. Trifft beides nicht zu, so handelt es sich um eine Datei. F&uuml;r Objekte wie die der Systemsteuerung gilt dies allerdings nicht. Hier w&auml;re die Eigenschaft <b>IsFileSystem<\/b> zus&auml;tzlich abzufragen, welche bei virtuellen Elementen <b>False<\/b> zur&uuml;ckgibt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oViewDispatch_SelectionChanged()\r\n     <span style=\"color:blue;\">Dim <\/span>oItm<span style=\"color:blue;\"> As <\/span>Shell32.FolderItem\r\n     <span style=\"color:blue;\">Dim <\/span>sObjs<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     For Each oItm In oViewDispatch.SelectedItems\r\n         sObjs = sObjs & <span style=\"color:blue;\">vbCrLf<\/span> & String(4, 32) & oItm.Path\r\n     <span style=\"color:blue;\">Next<\/span> oItm\r\n     AddToLog \"Selected object(s): \" & sObjs\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Enumerieren der in der ShellView markierten Elemente<\/span><\/b><\/p>\n<p>Im Beispiel werden in der String-Variablen <b>sObjs<\/b> die Pfade der selektierten Elemente aneinandergeh&auml;ngt, um sie &uuml;ber die Hilfsroutine <b>AddToLog<\/b> in der Textbox des Formulars auszugeben.<\/p>\n<h2>Gestalt des Controls steuern<\/h2>\n<p>Der <b>Initialize<\/b>-Methode des <b>ExplorerBrowsers<\/b> gaben wir schon Voreinstellungen &uuml;ber die <b>FOLDERSETTINGS<\/b>-Variable <b>pfs<\/b> mit. Eine solche Variable mit anderen Einstellungen k&ouml;nnen Sie jedoch jederzeit &uuml;ber die Methode <b>SetOptions<\/b> neu zuweisen. Davon macht die Ereignisroutine des <b>Apply<\/b>-Buttons <b>cmdSetOpts<\/b> im Formular Gebrauch (Listing 6).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdSetOpts_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>sTag<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lSettings<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>pfs<span style=\"color:blue;\"> As <\/span>oleexp.FOLDERSETTINGS\r\n     \r\n     For i = 1 To 21\r\n         <span style=\"color:blue;\">If <\/span>Me.Controls(\"chk\" & CStr(i)).Value = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             sTag = Me.Controls(\"chk\" & CStr(i)).Tag\r\n             <span style=\"color:blue;\">Debug.Print<\/span> sTag\r\n             lSettings = lSettings Or Val(\"&H\" & sTag & \"&\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     pfs.fFlags = lSettings\r\n     pfs.ViewMode = Me!optgrp.Value\r\n     oExplBrowser.SetFolderSettings pfs\r\n     oViewObj.IconSize = Me!cbIcons.Value\r\n     bAllowDrop = <span style=\"color:blue;\">Not<\/span> Me!chkDrop.Value\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Prozedur beim Klick auf den Button cmdSetOpts (Apply)<\/span><\/b><\/p>\n<p>Die Art der Ansicht der <b>View<\/b> steuert die Komponente <b>ViewMode<\/b> von <b>pfs<\/b>. Sie wird direkt auf einen Wert gesetzt, der aus der Optionsgruppe <b>optgrp<\/b> des Formulars stammt. Jede Optionsschaltfl&auml;che hat dort einen Wert bekommen, der einer der Konstanten der <b>FOLDERVIEWMODE<\/b>-Enumeration entspricht. Etwa <b>4<\/b> f&uuml;r <b>FVM_DETAILS<\/b> (Detailansicht), <b>3<\/b> f&uuml;r <b>FVM_LIST<\/b> (Listenansicht) oder <b>-1<\/b> f&uuml;r <b>FVM_AUTO<\/b> (Ansicht automatisch von Windows gesetzt). <\/p>\n<p>Die Komponente <b>fFlags<\/b> hingegen kann mehrere Konstanten der <b>FOLDERFLAGS<\/b>-Enumeration kombinieren. Deshalb die Checkboxen im Formular. Jede dieser Checkboxen weist in der Eigenschaft <b>Tag<\/b> einen Hexadezimal-String auf, der einer der Konstanten entspricht. Alle diese Steuerelemente haben den Namen <b>chk<\/b> plus Nummern von <b>1<\/b> bis <b>21<\/b>. Damit lassen sie sich in einer Schleife leicht durchlaufen. Ist ein H&auml;kchen gesetzt, so ist die <b>Value<\/b>-Eigenschaft der Checkbox <b>True<\/b> und deren Tag wird in <b>sTag<\/b> eingelesen. Aus diesem Hexadezimal-String wird mithilfe der <b>Val<\/b>-Funktion ein <b>Long<\/b>-Wert produziert, der in der Variablen <b>lSettings<\/b> bin&auml;r per <b>Or<\/b> kombiniert wird. Schlie&szlig;lich verabreicht die Methode <b>SetFolderSettings<\/b> des <b>ExplorerBrowsers<\/b> die Einstellungen der Variablen <b>pfs<\/b>. Nicht alle wirken sich unmittelbar aus. Manchmal ist erst die Navigation zu einem anderen Verzeichnis n&ouml;tig, damit sie greifen.<\/p>\n<p>Die Gr&ouml;&szlig;e der Symbole bei Symbolansicht in der <b>View<\/b> kann mit <b>IconSize<\/b> bestimmt werden. Im Prinzip kann hier jeder <b>Long<\/b>-Wert angegeben werden, aber die <b>Shell<\/b> kann nat&uuml;rlich keine 19&#215;19-Icons rendern, weshalb nur die g&auml;ngigen Werte wie 16, 24, 32, 48, 64 et cetera zu Anwendung kommen. Die Werte holt die Routine aus dem Kombinationsfeld <b>cbIcons<\/b>.<\/p>\n<p>Eine Boole-Variable <b>bAllowDrop<\/b> im Formularmodul wird zus&auml;tzlich auf den Wert der entsprechenden Checkbox gesetzt. Wir erl&auml;utern noch, wof&uuml;r wir sie brauchen.<\/p>\n<p>Experimentieren Sie einfach mit einigen Einstellungen im Formular. Da die <b>Tag<\/b>-Werte f&uuml;r die Checkboxen unmittelbar aus der Enumeration <b>FOLDERFLAGS<\/b> stammen, gibt es keine Gew&auml;hr, dass alle auch die Gestalt oder das Verhalten des Controls &auml;ndern. Manche Kombinationen funktionieren eben nicht. Einige wichtige Flags:<\/p>\n<ul>\n<li><b>FWF_FULLROWSELECT<\/b> &#8211; Beim Markieren von Dateien wird die komplette Zeile selektiert, ansonsten nur der Name.<\/li>\n<li><b>FWF_CHECKSELECT<\/b> &#8211; Dateien und Verzeichnisse werden zur Markierung zus&auml;tzlich mit Checkboxen versehen.<\/li>\n<li><b>FWF_NOCOLUMNHEADER<\/b> &#8211; Die View zeigt keine Spaltenk&ouml;pfe an.<\/li>\n<li><b>FWF_NOHEADERINALLVIEWS<\/b> zeigt nur bei Detailansicht Spaltenk&ouml;pfe an.<\/li>\n<li><b>FWF_NOSUBFOLDERS<\/b> &#8211; Die View zeigt ausschlie&szlig;lich Dateien an, aber keine Unterverzeichnisse.<\/li>\n<li><b>FWF_SINGLECLICKACTIVATE<\/b> &#8211; Die Standardaktion f&uuml;r das Element (Navigieren bei Unterverzeichnissen, &ouml;ffnen bei Dateien) wird bereits bei einfachem Klick darauf ausgel&ouml;st.<\/li>\n<li><b>FWF_SINGLESEL<\/b> &#8211; Es kann nur ein einziges Element der View selektiert werden.<\/li>\n<li><b>FWF_NOGROUPING<\/b> &#8211; Die Elemente der View lassen sich nicht gruppieren.<\/li>\n<li><b>FWF_NOWEBVIEW<\/b> &#8211; Eine Web-Ansicht der <b>View<\/b> wird unterbunden, falls etwa zu einer <b>URL<\/b> navigiert w&uuml;rde.<\/li>\n<\/ul>\n<p>Der Klick auf die <b>Get<\/b>-Schaltfl&auml;che im Formular kehrt die Routine aus Listing 6 &uuml;brigens einfach um. &uuml;ber die ausgelesenen <b>FOLDERSETTINGS<\/b> steuert sie den Status der Checkboxen und den Wert der Optionsgruppe. Allerdings sieht die <b>ExplorerBrowser<\/b>-Klasse keine Methode zum Auslesen dieser Einstellungen vor. Man muss stattdessen das <b>ShellFolderView<\/b>-Objekt <b>oViewObj<\/b> und seine Methoden <b>CurrentViewMode<\/b> oder <b>FolderFlags<\/b> bem&uuml;hen:<\/p>\n<pre>Me!optgrp.Value = _\r\n                       CLng(CallByName(oViewObj, \"CurrentViewMode\", VbGet))\r\nlSettings = CallByName(oViewObj, \"FolderFlags\", VbGet)<\/pre>\n<p>Die <b>CallByName<\/b>-Funktion muss hier zum Einsatz kommen, weil die Deklaration dieser Schnittstellenmethoden in <b>Shell32<\/b> Datentypen f&uuml;r die Parameter enth&auml;lt, die VBA nicht kennt. <b>CallByName<\/b> ist dabei ein g&auml;ngiger Workaround.<\/p>\n<p>Eine Sache blieb noch unerw&auml;hnt. Sie k&ouml;nnen das Control anweisen, die Einstellungen f&uuml;r alle Ordner, zu denen Sie mit ihm navigieren, unter einem Namen abzuspeichern. Diese Zeile legt es fest:<\/p>\n<pre>oExplBrowser.SetPropertyBag \"aiubrowser\"<\/pre>\n<p>Nun wird f&uuml;r jeden Ordner ein spezielles Shell-<b>PropertyBag<\/b> unter dem Namen <b>aiubrowser<\/b> angelegt, welches die vorgenommenen Einstellungen verewigt. Das sind Teile der Registry. Der normale Explorer tut das &uuml;brigens auch, nur haben seine <b>PropertyBags<\/b> keinen Namen. Es existieren Abertausende solcher <b>PropertyBags<\/b> in der Registry. Die Methode <b>SetPropertyBag<\/b> bewirkt aber nicht nur das Abspeichern der Einstellungen, sondern auch automatisch deren Einlesen. Das bedeutet, dass das Control beim Navigieren zu einem Verzeichnis die Registry befragt und dann das passende <b>PropertyBag<\/b> einliest, um die Einstellungen des Ordners vorzunehmen. Ist keines da, so verwendet es die f&uuml;r den normalen Explorer abgespeicherten oder Standard-Werte. Die f&uuml;r <b>aiubrowser<\/b> gespeicherten Werte wirken sich ausschlie&szlig;lich in unserer Anwendung aus, nicht aber im normalen Explorer! Wen es interessiert: Diese <b>PropertyBags<\/b> befinden sich in der Registry im Zweig<\/p>\n<pre>HKCR\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\\<\/pre>\n<h2>Navigieren per VBA<\/h2>\n<p>Nat&uuml;rlich k&ouml;nnen Sie auch &uuml;ber Code-Anweisungen zu anderen Verzeichnissen im Control navigieren. Die erw&auml;hnte Methode <b>BrowseToIDList<\/b> des <b>Explorer-Browser<\/b>-Objekts &uuml;bernimmt das. Leider nimmt sie als Parameter nur Shell-IDs entgegen. Eine API-Funktion kann einen Pfad-String aber in eine solche ID umwandeln:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>lPIDL<span style=\"color:blue;\"> As Long<\/span>\r\nlPIDL = oleexp.ILCreateFromPathW(StrPtr(sPath))\r\noExplBrowser.BrowseToIDList lPIDL, SBSP_ABSOLUTE<\/pre>\n<p>Alternativ geht eben auch der Sprung zu einem Spezialordner von Windows. Zu den <b>Eigenen Dokumenten<\/b> etwa kommen Sie &uuml;ber diese Zeile:<\/p>\n<pre>  lPIDL = SHGetSpecialFolderLocation(0&, CSIDL_MYDOCUMENTS)<\/pre>\n<p>Der Sprung zum letzten Verzeichnis in der History des Controls gelingt &uuml;ber <\/p>\n<pre>oExplBrowser.BrowseToIDList 0&, SBSP_NAVIGATEBACK<\/pre>\n<p>Eine <b>ID<\/b> muss hier nicht angegeben werden. Stattdessen sagt der zweite Parameter dem Control, dass es diese selbst aus seiner History heraussuchen soll. Analog beim Sprung vorw&auml;rts:<\/p>\n<pre>oExplBrowser.BrowseToIDList 0&, SBSP_NAVIGATEFORWARD<\/pre>\n<p>Die Sache funktioniert also fast genauso einfach wie im <b>Webbrowser Control<\/b> und dessen Methoden <b>GoBack<\/b> und <b>GoForward<\/b>.<\/p>\n<p>Zum dar&uuml;ber liegenden Verzeichnis gelangt man &uuml;ber <\/p>\n<pre>oExplBrowser.BrowseToIDList 0&, SBSP_PARENT<\/pre>\n<p>Diese drei Aufrufe liegen hinter den entsprechenden Schaltfl&auml;chen des Formularkopfs.<\/p>\n<h2>Steuerbeispiele<\/h2>\n<p>Die blauen Buttons im Formular unten demonstrieren einige M&ouml;glichkeiten zur Steuerung der <b>View<\/b>. Nehmen wir etwa die Schaltfl&auml;che zum Editieren des f&uuml;nften angezeigten Elements. Sie ruft nur eine einzige Code-Zeile auf:<\/p>\n<pre>oViewObj.SelectItem oViewObj.Folder.Items.Item(4), 3 Or 4<\/pre>\n<p>Bei allen Vorg&auml;ngen rund um die View-Elemente ist das zwischengespeicherte <b>ShellFolderView<\/b>-Objekt (<b>oViewObj<\/b>) zu verwenden, nicht das <b>ExplorerBrowser<\/b>-Objekt. Seine Methode <b>SelectItem<\/b> markiert ein Element auf unterschiedliche Weise.<\/p>\n<p>Wie, das gibt der zweite Parameter an, eine Kombination mehrerer m&ouml;glicher Konstanten. Die <b>4<\/b> sagt der <b>View<\/b>, dass sie alle bisher markierten Elemente deselektieren, die <b>3<\/b> gleichzeitig, dass das betreffende Element in den Editierzustand versetzt werden soll.<\/p>\n<p>Das Objekt im ersten Parameter muss vom Typ <b>Shell32.FolderItem<\/b> sein. Um zu erkl&auml;ren, wie wir &uuml;ber den Objektausdruck zum f&uuml;nften Element gelangen, hier die Abfolge:<\/p>\n<ul>\n<li><b>oViewObj <\/b>ist das <b>ShellFolderView<\/b>-Objekt<\/li>\n<li><b>.Folder <\/b>ist der aktuell dargestellte Ordner<\/li>\n<li><b>.Items <\/b>ist die Auflistung seiner <b>View<\/b>-Elemente<\/li>\n<li><b>.Item(4)<\/b> ist das f&uuml;nfte Element (<b>FolderItem<\/b>) der Auflistung, weil diese nullbasiert ist<\/li>\n<\/ul>\n<p>Machen Sie sich am besten mit den Schnittstellen der <b>Shell32<\/b>-Bibliothek vertraut. Wichtig sind die Klassen <b>Folder<\/b> bis <b>Folder3<\/b>, <b>FolderItems<\/b> und <b>FolderItem<\/b> bis <b>FolderItem3<\/b>. Alle Definitionen sind ziemlich VBA-kompatibel. Die numerierten <b>Interfaces<\/b> leiten sich &uuml;brigens jeweils von den Vorg&auml;ngern ab. Ben&ouml;tigen Sie etwa Methoden der <b>Folder3<\/b>-Klasse, so <b>casten<\/b> Sie einfach ein <b>Folder<\/b>-Objekt auf ein anderes:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>fld<span style=\"color:blue;\"> As <\/span>Shell32.Folder\r\n<span style=\"color:blue;\">Dim <\/span>fld3<span style=\"color:blue;\"> As <\/span>Shell32.Folder3\r\n<span style=\"color:blue;\">Set<\/span> fld3 = fld\r\nfld3.TueDiesUndJenes...<\/pre>\n<p>Analog klappt das auch f&uuml;r ein <b>FolderItem<\/b>. <b>COM<\/b> implementiert immer die neuen Interfaces im Haupt-Interface.<\/p>\n<p>N&auml;chstes Beispiel. Um nun alle im Namen mit <b>P<\/b> beginnenden Elemente in der <b>View<\/b> zu markieren, kommt dies zum Einsatz:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdSelectP_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>fld<span style=\"color:blue;\"> As <\/span>Shell32.Folder\r\n     <span style=\"color:blue;\">Dim <\/span>itm<span style=\"color:blue;\"> As <\/span>Shell32.FolderItem\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> fld = oViewObj.Folder\r\n     For Each itm In fld.Items\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Left<\/span>(itm.Name, 1) = \"P\"<span style=\"color:blue;\"> Then<\/span>\r\n             oViewObj.SelectItem itm, 1\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> itm\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Alle <b>Items<\/b> des <b>Folders<\/b> <b>fld<\/b> werden enumeriert. Deren Namen liefert die Eigenschaft <b>Name<\/b>. Steht links ein <b>P<\/b>, so wird das <b>Item<\/b> wieder per <b>SelectItem<\/b> markiert.<\/p>\n<p>Der Wert <b>1<\/b> sagt der Methode, dass die bisher markierten Elemente ihren Zustand beibehalten sollen.<\/p>\n<p>Wie das Beispiel zum Durchmarkieren aller Elemente der <b>View<\/b> funktioniert (<b>Circle Items<\/b>), k&ouml;nnen Sie sich denken. Hier kommt nichts wirklich Neues hinzu. Interessanter ist da schon der Button zum Sortieren der Ansicht (<b>Sort Files By Size<\/b>):<\/p>\n<pre>oViewObj.SortColumns = \"prop:-System.Size;\"<\/pre>\n<p>&uuml;bergeben Sie der Eigenschaft <b>SortColumns<\/b> des <b>ShellFolderView<\/b>-Objekts einfach den gew&uuml;nschten Sortierausdruck. Hier ist es <b>System.Size<\/b>, was nach Dateigr&ouml;&szlig;e sortiert. Das Minus bedeutet dabei absteigend. Das Semikolon deutet bereits an, dass mehrere Sortieranweisungen kombinierbar sind. Tats&auml;chlich k&ouml;nnen Sie Elemente so etwa nach Gr&ouml;&szlig;e und dann nach &auml;nderungsdatum sortieren:<\/p>\n<pre>oViewObj.SortColumns = \"prop:-System.Size;-System.ModifiedDate;\"<\/pre>\n<p>Das letzte Beispiel sucht nach <b>PDF<\/b>-Dateien im aktuellen Ordner und seinen Unterordnern:<\/p>\n<pre>oViewObj.FilterView \"*.pdf\"<\/pre>\n<p>Einfacher geht&#8220;&#8220;s nicht! Sie k&ouml;nnen den Suchausdruck f&uuml;r die Methode <b>FilterView<\/b> auf gleiche Weise einsetzen wie im Explorer sonst auch. Beliebige Platzhalter sind erlaubt. Die Suche nach <b>MP3<\/b>-Dateien, welche den Ausdruck <b>Zeppelin<\/b> enthalten: <b>&#8220;&#8220;*zeppelin*.mp3&#8220;&#8220;<\/b>. Und schon haben Sie alle St&uuml;cke von <b>Led Zeppelin<\/b> Ihrer MP3-Sammlung in der <b>View<\/b>. Diese zeigt sich &uuml;brigens analog, wie die Suchergebnisse im Explorer. Mit Klick auf den Button <b>Back<\/b> gelangen Sie dann wieder zur&uuml;ck zum eigentlichen Verzeichnis.<\/p>\n<h2>Drop-Ereignisse<\/h2>\n<p>Bei Durchsicht der Ereignisse des <b>ShellFolderView<\/b>-Objekts f&auml;llt Ihnen vielleicht auf, dass es keine zu <b>Drag And Drop<\/b>-Operationen ausl&ouml;st. Ziehen Sie also eine Datei aus einem externen Explorer in die <b>View<\/b> des Controls, um sie zu kopieren, so l&ouml;st dies h&ouml;chsten deren Ereignis <b>SelectionChanged<\/b> aus.  Ein Vergleich aller <b>Items<\/b> der <b>View<\/b> mit denen nach dem <b>Drop<\/b> k&ouml;nnte zwar die neue Datei identifizieren. Das ist aber viel zu unzuverl&auml;ssig. <\/p>\n<p>Leider wird es nun richtig kompliziert und die folgenden Ausf&uuml;hrungen finden Sie nur deshalb im Beitrag, weil die Sache so in der Beispieldatenbank implementiert ist. Aber nur &uuml;ber die eingesetzte Technik l&auml;sst sich leider erreichen, dass die <b>View<\/b> das <b>Droppen<\/b> von Dateien unterbindet. Das hat uns einige Stunden <b>Trial and Error<\/b> gekostet &#8230;<\/p>\n<p>Dann mal los! Grundlage f&uuml;r alle <b>Drop<\/b>-Operationen der <b>Shell<\/b> ist deren Interface <b>IDropTarget<\/b>. Die <b>View<\/b> des Controls implementiert dieses. Man kann also eine Objektvariable auf dieses Interface setzen, wobei hier eine einfache <b>Set<\/b>-Anweisung nicht ausreicht. Man muss schon die Methode <b>QueryInterface<\/b> des allen COM-Objekten eigenen <b>IUnknown<\/b>-Interfaces bem&uuml;hen:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Const IID_IDropTarget = _\r\n                                 \"{00000122-0000-0000-C000-000000000046}\" \r\n<span style=\"color:blue;\">Private <\/span>IDrop<span style=\"color:blue;\"> As <\/span>oleexp.IDropTarget\r\n<span style=\"color:blue;\">Dim <\/span>IIDDropTarget<span style=\"color:blue;\"> As <\/span>oleexp.UUID\r\n<span style=\"color:blue;\">Dim <\/span>IUnk<span style=\"color:blue;\"> As <\/span>oleexp.IUnknown\r\n<span style=\"color:blue;\">Dim <\/span>ret<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Set<\/span> IUnk = IShView\r\noleexp.CLSIDFromString IID_IDropTarget, IIDDropTarget\r\nret = IUnk.QueryInterface(IIDDropTarget, IDrop)<\/pre>\n<p><b>IShView<\/b> war ja der <b>IShellView<\/b>-Parameter, der vom Ereignis <b>OnViewCreated<\/b> der <b>ExplorerBrowserEvents<\/b> zur&uuml;ckgeliefert wird. Auf diese Schnittstelle wird nun die <b>IUnknown<\/b>-Variable <b>IUnk<\/b> gecastet. Nur <b>IUnknown<\/b> kennt direkt die Methode <b>QueryInterface<\/b>, welche zum Ermitteln implementierter Schnittstellen eingesetzt wird. Die gew&uuml;nschte Schnittstelle zu <b>IDropTarget<\/b> wird als <b>GUID<\/b> &uuml;bergeben, die zun&auml;chst &uuml;ber die API-Funktion <b>CLSIDFromString<\/b> aus der String-Konstanten ganz oben erzeugt wird. Klappt die Sache, dann gibt <b>QueryInterface<\/b> in <b>ret<\/b> ein <b>OK<\/b> zur&uuml;ck. Das w&auml;re der Wert <b>0<\/b>. In diesem Fall steht nun im zweiten Parameter der Verweis auf das abgefragte Interface. Die Objektvariable <b>IDrop<\/b> nimmt ihn auf.<\/p>\n<p>Toll! Nun haben wir das in der View eingesetzte Interface <b>IDropTarget<\/b> im Zugriff, welches diese Methoden beherbergt: <b>DragEnter<\/b>, <b>DragOver<\/b>, <b>DragLeave<\/b> und <b>Drop<\/b>. Diese Methoden werden beim Eintritt einer gezogenen Datei in die <b>View<\/b> ausgel&ouml;st, beim Dar&uuml;berziehen und beim Verlassen. <b>Drop<\/b> schlie&szlig;lich passiert beim Fallenlassen des Elements. <\/p>\n<p>Nur sind das alles leider noch keine Ereignisse! Es gibt auch kein <b>Advise<\/b>, wie beim <b>ExplorerBrowser<\/b>-Objekt, oder eine Event-Verbindung &uuml;ber <b>ConnectToConnectionPoint<\/b>, wie f&uuml;r die <b>ShellFolderView<\/b>-Schnittstelle, da es sich hier nicht um ein Event-Interface handelt. Die einzige L&ouml;sung, die uns hier einfiel, ist das Patchen des Interfaces <b>IDropTarget<\/b> selbst.<\/p>\n<p>Dabei wird eine Methode, die von ihm aufgerufen wird, in eine andere Funktion unter VBA umgeleitet. Dazu ist die sogenannte <b>VTable<\/b> des Interfaces zu modifizieren. Die ist gleichsam ein Verzeichnis aller Methoden-Speicheradressen. Man kommt an sie &uuml;ber den Zeiger auf ein Objekt und die versteckte VBA-Funktion <b>ObjPtr<\/b>. Mit verschiedenen API-Funktionen kann ein Eintrag in dieser Tabelle ausgetauscht werden. Die Routine <b>SwapVtableEntry<\/b> im Modul <b>mdlDragDrop<\/b> der Beispieldatenbank (Listing 7) erledigt das. Sie &uuml;bergeben ihr den Objekt-Zeiger in <b>pObj<\/b>, die Nummer der zu patchenden Methode in <b>EntryNumber<\/b> und die Speicheradresse der neuen Funktion in <b>lpfn<\/b>. Der Patch f&uuml;r unser <b>IDropTarget<\/b>-Interface und seine Methode <b>Drop<\/b> sieht so aus:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>SwapVtableEntry(ByVal pObj<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal EntryNumber<span style=\"color:blue;\"> As Integer<\/span>, ByVal lpfn<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lOldAddr<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lpVtableHead<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lpfnAddr<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lOldProtect<span style=\"color:blue;\"> As Long<\/span>\r\n     CopyMemory lpVtableHead, ByVal pObj, 4\r\n     lpfnAddr = lpVtableHead + EntryNumber * 4\r\n     CopyMemory lOldAddr, ByVal lpfnAddr, 4\r\n     <span style=\"color:blue;\">Call<\/span> VirtualProtect(lpfnAddr, 4, _\r\n         PAGE_EXECUTE_READWRITE, lOldProtect)\r\n     CopyMemory ByVal lpfnAddr, lpfn, 4\r\n     <span style=\"color:blue;\">Call<\/span> VirtualProtect(lpfnAddr, 4, _\r\n         lOldProtect, lOldProtect)\r\n     SwapVtableEntry = lOldAddr\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Routine zum Patchen der Methoden eines Objekts<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>fuDrop<span style=\"color:blue;\"> As Long<\/span>\r\nfuDrop = SwapVtableEntry(ObjPtr(IDrop), 6, AddressOf DropProc)<\/pre>\n<p><b>fuDrop<\/b> nimmt dabei den Zeiger auf die urspr&uuml;nglich im Interface f&uuml;r <b>Drop<\/b> anspringende Speicheradresse entgegen. Wir brauchen diesen Wert sp&auml;ter, um den Patch r&uuml;ckg&auml;ngig zu machen. Denn sonst w&auml;re mit Abst&uuml;rzen zu rechnen. Der Zeiger auf die <b>VTable<\/b> ergibt sich &uuml;ber <b>ObjPtr<\/b> auf <b>IDrop<\/b>.<\/p>\n<p>Die <b>Drop<\/b>-Methode hat in ihr die Eintragsnummer <b>6<\/b>. F&uuml;r <b>DragEnter<\/b> w&auml;re es etwa die <b>3<\/b>. Als neue anzuspringende Funktion nehmen wir die im Modul eingebaute Prozedur <b>DropProc<\/b>. Deren Adresse ermittelt die VBA-Klausel <b>AddressOf<\/b>.<\/p>\n<p>In der Folge springt das Interface nun jedes Mal, wenn eine Datei oder ein Verzeichnis &uuml;ber der <b>View<\/b> des Controls fallengelassen wird, unsere eigene Funktion <b>DropProc<\/b> an. Die eigentliche Funktion der Methode <b>Drop<\/b> ist damit au&szlig;er Kraft gesetzt. Es handelt sich hier um eine &auml;hnliche Technik wie beim <b>Subclassing<\/b> von Fenstern.<\/p>\n<p>Der ganze Code ist in einem Modul untergebracht, weil die <b>AddressOf<\/b>-Klausel nur f&uuml;r Prozeduren von normalen Modulen funktioniert, aber nicht f&uuml;r Klassenmodule wie bei unserem Formular.<\/p>\n<p>Nat&uuml;rlich muss die neue Funktion genau die gleiche Parametersyntax besitzen, wie die im Interface verbaute. F&uuml;r <b>Drop<\/b> w&auml;re das laut Objektkatalog<\/p>\n<pre>''''IDropTarget\r\n<span style=\"color:blue;\">Sub <\/span>Drop(pDataObj<span style=\"color:blue;\"> As <\/span>IDataObject, grfKeyState<span style=\"color:blue;\"> As Long<\/span>, _\r\n                   ptX<span style=\"color:blue;\"> As Long<\/span>, ptY<span style=\"color:blue;\"> As Long<\/span>, pdwEffect<span style=\"color:blue;\"> As <\/span>DROPEFFECTS)<\/pre>\n<p>Doch beim Aufruf der eigenen Funktion wird zus&auml;tzlich ein Zeiger auf das ausl&ouml;sende Interface als erster Parameter &uuml;bergeben. Deshalb sieht die <b>DropProc<\/b>-Deklaration schlie&szlig;lich so aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>DropProc(ByVal Dummyobj<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal pDataObj<span style=\"color:blue;\"> As <\/span>oleexp.IDataObject, ByVal grfKeyState<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal ptx<span style=\"color:blue;\"> As Long<\/span>, ByVal pty<span style=\"color:blue;\"> As Long<\/span>, ByRef pdwEffect<span style=\"color:blue;\"> As Long<\/span>)<\/pre>\n<p><b>DummyObj<\/b> ben&ouml;tigen wir nicht. In <b>pDataObj<\/b> steht beim Droppen ein Objekt, welches Informationen &uuml;ber die gezogene Datei oder das Verzeichnis enth&auml;lt. <b>grfKeystate<\/b> liefert den Zustand der dabei gedr&uuml;ckten <b>SHIFT<\/b>&#8211; oder <b>STRG<\/b>-Tasten. <b>pty<\/b> und <b>pty<\/b> sind die Koordinaten, auf denen das Fallenlassen geschah. <b>pdwEffekt<\/b> ist ein <b>ByRef<\/b>-Wert, der von der Prozedur selbst gef&uuml;llt werden sollte. Er bestimmt, wie der Mauszeiger beim Dar&uuml;berziehen oder Fallenlassen aussehen soll.<\/p>\n<p>Auf die gleiche Weise kann die Methode <b>DragEnter<\/b> gepatcht werden. Tut man das, so entsteht beim Ziehen einer Datei im <b>View<\/b>-Fenster ein <b>Stop<\/b>-Symbol, welches dar&uuml;ber informiert, dass in diesem Verzeichnis kein <b>Drop<\/b> einer Datei stattfinden kann. Tats&auml;chlich geschieht dies dann auch nicht.<\/p>\n<p>&uuml;ber dieses Patchen kann also das <b>ExplorerBrowser Control<\/b> dazu gebracht werden, jegliche<b> Drag And Drop<\/b>-Operationen zu ignorieren. Das gilt allerdings nur f&uuml;r die <b>View<\/b> des Controls. Ein <b>Drop<\/b> in den Verzeichnisbaum ist damit noch nicht unterbunden. Wollte man die Sache auch f&uuml;r diesen einsetzen, so w&auml;re die ganze Arbeit auch noch f&uuml;r weitere interne Interfaces des Controls zu erledigen. Das haben wir au&szlig;en vor gelassen.<\/p>\n<p>Damit die Geschichte au&szlig;er dem Verhindern des <b>Droppen<\/b> noch einen weiteren Sinn hat, wertet die Funktion <b>DropProc<\/b> das &uuml;bergebene <b>IDataObject<\/b> aus:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>sFiles<span style=\"color:blue;\"> As String<\/span>\r\nsFiles = GetDropFile(pDataObj)\r\n<span style=\"color:blue;\">MsgBox<\/span> sFiles, vbInformation, \"Dropping files\"<\/pre>\n<p>Dabei &uuml;bernimmt die Hilfsfunktion <b>GetDropFile<\/b> die eigentliche Arbeit. Sie zu erl&auml;utern f&uuml;hrt hier zu weit. Sie nutzt diverse API-Funktionen, um eine Liste der Dateien im <b>IDataObjekt<\/b> zu erstellen. Im R&uuml;ckgabeergebnis erhalten Sie einen String, der die Pfade aller Dateien zeilengetrennt enth&auml;lt. Die <b>Msgbox<\/b> zeigt diese dann an. Nat&uuml;rlich k&ouml;nnen Sie mit diesem String auch andere Dinge anfangen &#8211; etwa seine Weitergabe an das Formularmodul, um dort ein weiteres Control-Ereignis zu erzeugen. Das war eingangs ja auch das Ansinnen.<\/p>\n<p>Das Modul enth&auml;lt noch einige Teile, auf die wir nicht weiter eingehen. Ziel ist es etwa, das Droppen trotz Patch der <b>IDropTarget<\/b>-Methoden mithilfe eines Objekts <b>IDropTargetHelper<\/b> dennoch m&ouml;glich zu machen. Das Ganze ist aber momentan noch <b>work in progress<\/b> und funktioniert nicht zufriedenstellend!<\/p>\n<h2>Auslagern der ExplorerBrowser-Prozeduren in ein Klassenmodul<\/h2>\n<p>Die Wiederverwendbarkeit der besprochenen Routinen ist ausgesprochen gering, solange sie sich alle im Formularmodul befinden. Wer m&ouml;chte schon all dies in ein neues Formular importieren und dort anpassen Deshalb gibt es mit <b>cExplorerBrowser<\/b> in der Beispieldatenbank ein Klassenmodul, das sich leicht in andere Datenbanken &uuml;bertragen l&auml;sst.<\/p>\n<p>Img Grunde enth&auml;lt es dieselben Routinen, wie das Formular <b>frmExplorerCtl<\/b>. Nur muss hier ja eine Verkn&uuml;pfung zum instanzierenden Formular hergestellt sein. Deshalb hat die zentrale Methode dieses Klassenmoduls folgende Syntax:<\/p>\n<p>[50038]<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>CreateExplorer(ByVal frm<span style=\"color:blue;\"> As <\/span>Access.Form, _<\/pre>\n<p>[50265]<\/p>\n<pre>     <span style=\"color:blue;\">Optional<\/span> ByVal Where<span style=\"color:blue;\"> As <\/span>Access.AcSection = acDetail, _<\/pre>\n<p>[50317]<\/p>\n<pre>     <span style=\"color:blue;\">Optional<\/span> DummyControl<span style=\"color:blue;\"> As <\/span>Access.Control, _<\/pre>\n<p>[50376]<\/p>\n<pre>     <span style=\"color:blue;\">Optional<\/span> x<span style=\"color:blue;\"> As Long<\/span>, <span style=\"color:blue;\">Optional<\/span> y<span style=\"color:blue;\"> As Long<\/span>, _<\/pre>\n<p>[50423]<\/p>\n<pre>     <span style=\"color:blue;\">Optional<\/span> Width<span style=\"color:blue;\"> As Long<\/span>, <span style=\"color:blue;\">Optional<\/span> Height<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Boolean<\/span><\/pre>\n<p>[50469]<\/p>\n<p>Nachdem Sie eine Instanz der Klasse im Formular erzeugt haben, brauchen Sie im Prinzip nur diese eine Methode aufzurufen, um zu einem funktionsf&auml;higen Explorer Control zu kommen. Da die Klasse auch Ereignisse hervorruft, deklarieren Sie sie im Formularmodul <b>WithEvents<\/b>:<\/p>\n<p>[50533]<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oExplorer<span style=\"color:blue;\"> As <\/span>cExplorerBrowser<\/pre>\n<p>[50803][50852]<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()<\/pre>\n<p>[50853]<\/p>\n<pre>     <span style=\"color:blue;\">Set<\/span> oExplorer = <span style=\"color:blue;\">New<\/span> cExplorerBrowser<\/pre>\n<p>[50877]<\/p>\n<pre>     <span style=\"color:blue;\">With<\/span> oExplorer<\/pre>\n<p>[50918]<\/p>\n<pre>         .CanResize = <span style=\"color:blue;\">True<\/span><\/pre>\n<p>[50937]<\/p>\n<pre>         .AllowDrop = <span style=\"color:blue;\">True<\/span><\/pre>\n<p>[50963]<\/p>\n<pre>         .CreateExplorer Me, acDetail, Me.rExplore<\/pre>\n<p>[50989]<\/p>\n<pre>     End <span style=\"color:blue;\">With<\/span><\/pre>\n<p>[51039]<\/p>\n<pre><span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>[51052]<\/p>\n<p>Beim Laden des Formulars legt die <b>New<\/b>-Anweisung ein neues Objekt in der Variablen <b>oExplorer<\/b> an. Die Eigenschaft <b>CanResize<\/b> gibt an, ob sich das Explorer Control sp&auml;ter Gr&ouml;&szlig;en&auml;nderungen des Formulars anpassen oder ob es eine feste Gr&ouml;&szlig;e besitzen soll. Mit <b>AllowDrop<\/b> legen Sie fest, ob das Control auf das <b>Droppen<\/b> von Dateien oder Verzeichnissen reagieren und diese umsetzen soll. Allerdings ben&ouml;tigt die Klasse dazu hilfsweise auch noch das besprochene Modul <b>mdlDragDrop<\/b>! Schlie&szlig;lich &uuml;bergeben Sie der Methode <b>CreateExplorer<\/b> einen Verweis auf das Formular mit <b>Me<\/b> und sagen ihr, dass Sie das Control im Detailbereich platziert wissen m&ouml;chten (<b>acDetail<\/b>). Sie k&ouml;nnten bei eingeblendetem Formularkopf ebenso die Konstante <b>acHeader<\/b> angeben, was das Control in eben diesen Bereich verfrachten w&uuml;rde.<\/p>\n<p>[51060]<\/p>\n<p>Die Methode ist aber noch mit einem weiteren <b>Goodie<\/b> ausgestattet. Da ein Formular, in welches das Control eingebaut werden soll, in der Entwurfsansicht ziemlich nackt aussieht (s. Bild 3) und ein visuelles Feedback &uuml;ber sein Layout somit fehlt, kann der Methode <b>CreateExplorer<\/b> optional der Verweis auf ein Steuerelement &uuml;bergeben werden, welches als Platzhalter f&uuml;r den Explorer dienen soll. Im Beispiel oben geschieht das. <b>rExplore<\/b> ist ein Rechtecksteuerelement mit F&uuml;llung, welches das Explorer Control symbolisieren soll und zur Laufzeit dann von diesem &uuml;berlagert wird. Bild 9 zeigt den Entwurf des Beispielformulars <b>frmExplorerSimplest<\/b>. Geben Sie ein Platzhaltersteuerelement an, dann hat die Eigenschaft <b>CanResize<\/b> folgende Auswirkung, wenn sie auf <b>True<\/b> steht: Beim Start des Formulars nimmt das Explorer Control die Abmessungen des Ersatzsteuerelements ein. Bei Gr&ouml;&szlig;en&auml;nderungen des Formulars aber dehnt es sich entsprechend vertikal und horizontal aus. Das entspr&auml;che der <b>Verankern<\/b>-Einstellung <b>Quer und nach unten dehnen<\/b>. Die Listbox rechts im Formular dient der Ausgabe der Ereignisse des Explorers. Ihre Verankerung ist auf <b>Rechts und nach unten dehnen<\/b> eingestellt. Damit &uuml;berlappt das Explorer Control die Listbox niemals und der Abstand bleibt gewahrt. Zur Laufzeit zeigt sich das Formular dann wie in Bild 10.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmExplorerSimplest_DS.png\" alt=\"In der Entwurfsansicht des Formulars dient das Rechteck-Element links als Platzhalter\" width=\"650\" height=\"384,6938\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: In der Entwurfsansicht des Formulars dient das Rechteck-Element links als Platzhalter<\/span><\/b><\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/frmExplorerSimplest_RT.png\" alt=\"Das Formular frmExplorerSimplest listet zur Laufzeit rechts die Explorer-Ereignisse auf\" width=\"700\" height=\"398,7152\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Das Formular frmExplorerSimplest listet zur Laufzeit rechts die Explorer-Ereignisse auf<\/span><\/b><\/p>\n<p>[51852]<\/p>\n<p>Dieses Feature f&uuml;hrt dazu, dass die <b>Resize<\/b>-Methode des Klassenmoduls <b>cExplorerBrowser<\/b> naturgem&auml;&szlig; etwas komplexer ausf&auml;llt als in der Version des Formulars <b>frmExplorerCtl<\/b>. Den kompletten Formularcode ohne die bereits weiter oben angef&uuml;hrte Initialisierung in <b>Form_Load<\/b> finden Sie in Listing 8. Im Grunde besteht er ausschlie&szlig;lich aus der Reaktion auf die Ereignisse des Klassenobjekts <b>oExplorer<\/b>. Verzeichnisse, zu denen im Control navigiert wird, kommen dabei immer als Strings zu den Pfaden herein. Die Prozedur <b>AddToLog<\/b> unten listet die Ereignisse in der Listbox <b>lstEvents<\/b> auf. Das Ereignis <b>SelectionChanged<\/b> liefert die ausgew&auml;hlten Dateien als <b>Collection<\/b> im Parameter. Damit k&ouml;nnen diese komfortabel &uuml;ber eine <b>For-Each<\/b>-Schleife enumeriert werden. &uuml;ber die eigentliche Programmierung des <b>ExplorerBrowsers<\/b> brauchen Sie sich mit dieser L&ouml;sung keine Gedanken mehr zu machen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Set<\/span> oExplorer = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_BeginDrag()\r\n     AddToLog \"Start drag item\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_DefaultVerbInvoked()\r\n     AddToLog \"Default verb invoked\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_EnumDone()\r\n     AddToLog \"Items enumerated\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_OnNavigationComplete _\r\n                         (ByVal sFolder<span style=\"color:blue;\"> As String<\/span>)\r\n     AddToLog \"Navigation complete: \" & sFolder\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_OnNavigationFailed(ByVal sFolder<span style=\"color:blue;\"> As String<\/span>)\r\n     AddToLog \"Navigation failed: \" & sFolder\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_OnNavigationPending(ByVal sFolder<span style=\"color:blue;\"> As String<\/span>)\r\n     AddToLog \"Navigation pending: \" & sFolder\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_OnViewCreated _\r\n                          (ByVal psv<span style=\"color:blue;\"> As <\/span>oleexp.IShellView)\r\n     AddToLog \"View created\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_SelectionChanged(FileSelection<span style=\"color:blue;\"> As <\/span>Collection)\r\n     <span style=\"color:blue;\">Dim <\/span>itm<span style=\"color:blue;\"> As Variant<\/span>, S<span style=\"color:blue;\"> As String<\/span>\r\n      AddToLog \"Item(s) selected:\"\r\n     For Each itm In FileSelection\r\n         S = CStr(itm)\r\n         AddToLog \"   \" & IIf(<span style=\"color:blue;\">Left<\/span>(S, 1) = \"d\", \"Folder:\", \"File:\") & <span style=\"color:blue;\">Mid<\/span>(S, 2)\r\n     <span style=\"color:blue;\">Next<\/span> itm\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oExplorer_VerbInvoked()\r\n     AddToLog \"Invoked a verb\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>AddToLog(<span style=\"color:blue;\">Optional<\/span> ByVal sText<span style=\"color:blue;\"> As String<\/span>)\r\n     Me!lstEvents.AddItem \"&#149;\" & sText\r\n     Me!lstEvents.Selected(Me!lstEvents.ListCount - 1) = 1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Code des Formulars frmExplorerSimplest<\/span><\/b><\/p>\n<h2>Zusammenfassung<\/h2>\n<p>[54047]<\/p>\n<p>Die neue Bibliothek <b>OLEEXP<\/b> er&ouml;ffnet uns neue spannende M&ouml;glichkeiten unter VBA, die sich sonst auf keine andere Weise erreichen lassen. Wir werden sicher noch in der einen oder anderen Ausgabe auf sie zur&uuml;ckgreifen. Material enth&auml;lt sie mehr als genug. <\/p>\n<p>[54063]<\/p>\n<p>Bei den hier vorgestellten L&ouml;sungen zum <b>Explorer-Browser<\/b> handelt es sich weitgehend um Pionierarbeit. Es kann sein, dass deshalb nicht immer alles ganz rund l&auml;uft. Besonders gilt das f&uuml;r alle Vorg&auml;nge beim <b>Drag And Drop <\/b>von Dateien. Gegebenenfalls liefern wir hier optimiertere L&ouml;sungen nach. Die Klasse <b>cExplorerBrowser<\/b> k&ouml;nnte au&szlig;erdem noch deutlich erweitert und mit neuen Features ausgestattet werden.<\/p>\n<p>[54317]<\/p>\n<p>Die Beispiele dieser Ausgabe dienen lediglich der grundlegenden Demonstration. Was hier fehlt, sind konkretere Anwendungsf&auml;lle f&uuml;r Ihre Datenbank. Wenn Ihnen solche einfallen, dann teilen Sie es uns mit! <\/p>\n<p>[54722]<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>ExplorerCtl.accdb<\/p>\n<p>oleexp.tlb<\/p>\n<p>register_tlb.bat<\/p>\n<p>regtlibv12.exe<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/A341D96D-01DF-4300-BAEF-C74FBD330552\/aiu_1096.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>F&uuml;r manche Aufgaben ben&ouml;tigen auch Datenbanken die Anzeige oder Auswahl von Dateien oder Ordnern des Betriebssystems. Manche davon lassen sich mit dem Dateiauswahldialog von Office erledigen. Hin und wieder ist aber eine unmittelbare Einsicht in das Dateisystem n&uuml;tzlich. Der Windows Explorer l&auml;sst sich mit Einschr&auml;nkungen fernsteuern, doch schicker w&auml;re ein Explorer direkt in einem Formular. Und das geht!<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662017,66042017,44000026],"tags":[],"class_list":["post-55001096","post","type-post","status-publish","format-standard","hentry","category-662017","category-66042017","category-Interaktiv"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Explorer Control - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Explorer_Control\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Explorer Control\" \/>\n<meta property=\"og:description\" content=\"F&uuml;r manche Aufgaben ben&ouml;tigen auch Datenbanken die Anzeige oder Auswahl von Dateien oder Ordnern des Betriebssystems. Manche davon lassen sich mit dem Dateiauswahldialog von Office erledigen. Hin und wieder ist aber eine unmittelbare Einsicht in das Dateisystem n&uuml;tzlich. Der Windows Explorer l&auml;sst sich mit Einschr&auml;nkungen fernsteuern, doch schicker w&auml;re ein Explorer direkt in einem Formular. Und das geht!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Explorer_Control\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:26:24+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"47\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Explorer Control\",\"datePublished\":\"2020-05-13T21:26:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/\"},\"wordCount\":8270,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/b47061bde7da4e6a9823d4f4792f4bb2\",\"articleSection\":[\"2017\",\"4\\\/2017\",\"Interaktiv\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/\",\"name\":\"Explorer Control - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/b47061bde7da4e6a9823d4f4792f4bb2\",\"datePublished\":\"2020-05-13T21:26:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/b47061bde7da4e6a9823d4f4792f4bb2\",\"contentUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/b47061bde7da4e6a9823d4f4792f4bb2\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Explorer_Control\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Explorer Control\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Explorer Control - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/","og_locale":"de_DE","og_type":"article","og_title":"Explorer Control","og_description":"F&uuml;r manche Aufgaben ben&ouml;tigen auch Datenbanken die Anzeige oder Auswahl von Dateien oder Ordnern des Betriebssystems. Manche davon lassen sich mit dem Dateiauswahldialog von Office erledigen. Hin und wieder ist aber eine unmittelbare Einsicht in das Dateisystem n&uuml;tzlich. Der Windows Explorer l&auml;sst sich mit Einschr&auml;nkungen fernsteuern, doch schicker w&auml;re ein Explorer direkt in einem Formular. Und das geht!","og_url":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:26:24+00:00","og_image":[{"url":"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"47\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Explorer Control","datePublished":"2020-05-13T21:26:24+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/"},"wordCount":8270,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2","articleSection":["2017","4\/2017","Interaktiv"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Explorer_Control\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/","url":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/","name":"Explorer Control - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2","datePublished":"2020-05-13T21:26:24+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Explorer_Control\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#primaryimage","url":"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2","contentUrl":"http:\/\/vg09.met.vgwort.de\/na\/b47061bde7da4e6a9823d4f4792f4bb2"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Explorer_Control\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Explorer Control"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001096","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001096"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001096\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001096"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001096"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001096"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}