{"id":55000481,"date":"2025-08-01T00:00:00","date_gmt":"2025-10-14T20:49:53","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=481"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"WindowsKontextmenue_mit_TreeView_verwalten","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/WindowsKontextmenue_mit_TreeView_verwalten\/","title":{"rendered":"Windows-Kontextmen&uuml; mit TreeView verwalten"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/cbbd3cefc6984ebb9e1ce3515cde9f9c\" width=\"1\" height=\"1\" alt=\"\"><b>Im Artikel &#8220;UstIdNr, IBAN und Co. per Kontextmen&uuml;&#8221; (www.vbentwickler.de\/480) haben wir gezeigt, wie wir die Windows-Kontextmen&uuml;s erweitern k&ouml;nnen. In diesem Fall haben wir Daten, die man gegebenenfalls nicht alle im Kopf hat, aber regelm&auml;&szlig;ig ben&ouml;tigt, einfach &uuml;ber ein Kontextmen&uuml; in die Zwischenablage einf&uuml;gen kann, um diese dann an der gew&uuml;nschten Stelle beispielsweise in einem Bestellformular eintr&auml;gt. Um das Hinzuf&uuml;gen und Aktualisieren dieser Eintr&auml;ge weiter zu vereinfachen und die zahlreichen Handgriffe zu ersparen, zeigen wir im vorliegenden Artikel eine Access-L&ouml;sung, mit der wir die Kontextmen&uuml;-Befehle mit einem einfachen TreeView verwalten und erweitern k&ouml;nnen.<\/b><\/p>\n<p>Dazu wollen wir die Struktur der benutzerdefinierten Kontextmen&uuml;-Eintr&auml;ge im Windows-Men&uuml; in einem <b>TreeView<\/b>-Steuerelement abbilden.<\/p>\n<p>Darin k&ouml;nnen wir Ordner, Unterordner und die enthaltenen Befehle verwalten. Nachdem wir diese Elemente angelegt haben, wollen wir diese per Mausklick direkt in die Registry schreiben k&ouml;nnen.<\/p>\n<h2>Datenmodell f&uuml;r die Anwendung<\/h2>\n<p>Wir wollen die Daten, wir wie sie zum Windows-Kontextmen&uuml; hinzuf&uuml;gen wollen, strukturiert in Tabellen ablegen, damit wir sie dynamisch erg&auml;nzen und bearbeiten k&ouml;nnen. Dazu ben&ouml;tigen wir zwei Tabellen:<\/p>\n<ul>\n<li><b>tblMenuFolders<\/b>: Enth&auml;lt die Ordner und die Unterordner.<\/li>\n<li><b>tblMenuEntries<\/b>: Enth&auml;lt die Eintr&auml;ge zu den jeweiligen Ordnern und Unterordnern.<\/li>\n<\/ul>\n<p>Die Tabelle <b>tblMenuFolders <\/b>gestalten wir wie in Bild 1. Das Feld <b>ParentMenuFolderID<\/b> verkn&uuml;pfen wir mit dem Feld <b>MenuFolderID <\/b>der gleichen Tabelle, damit wir die Zuordnung von Unterordnern zu Ordnern definieren k&ouml;nnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_001.png\" alt=\"Tabelle zum Speichern der Men&uuml;-Ordner\" width=\"549,6265\" height=\"376,1597\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Tabelle zum Speichern der Men&uuml;-Ordner<\/span><\/b><\/p>\n<p>Die zweite Tabelle <b>tblMenuEntries <\/b>nimmt die eigentlichen Eintr&auml;ge auf (siehe Bild 2). Sie nimmt die ID, die Beschriftung des Men&uuml;-Eintrags und den Text auf, der beim Bet&auml;tigen des Men&uuml;-Eintrags in die Zwischenablage kopiert werden soll.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_002.png\" alt=\"Tabelle zum Speichern der Men&uuml;-Eintr&auml;ge\" width=\"649,627\" height=\"406,9951\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Tabelle zum Speichern der Men&uuml;-Eintr&auml;ge<\/span><\/b><\/p>\n<p>Au&szlig;erdem wird &uuml;ber das Feld <b>ParentMenuFolderID <\/b>die Zuordnung zu einem Ordner angegeben.<\/p>\n<p>Im Datenmodell sehen wir die anzulegenden Beziehungen (siehe Bild 3). Die Tabelle <b>tblMenuEntries <\/b>ist &uuml;ber das Feld <b>ParentMenuFolderID <\/b>mit der Tabelle <b>tblMenuFolders <\/b>verkn&uuml;pft. Die Tabelle <b>tblMenuFolders <\/b>ist au&szlig;erdem &uuml;ber das Feld <b>ParentMenuFolderID <\/b>mit dem Feld <b>MenuFolderID <\/b>der gleichen Tabelle verkn&uuml;pft. F&uuml;r beide Beziehungen haben wir referenzielle Integrit&auml;t mit L&ouml;schweitergabe definiert, damit beim L&ouml;schen eines &uuml;bergeordneten Men&uuml;eintrags auch alle untergeordneten Elemente gel&ouml;scht werden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_003.png\" alt=\"Datenmodell der Anwendung\" width=\"549,6265\" height=\"389,2206\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Datenmodell der Anwendung<\/span><\/b><\/p>\n<h2>Aufbau des TreeView-Steuerelements<\/h2>\n<p>Wir f&uuml;gen einem neuen Formular namens <b>frmWindowsKontextmenue <\/b>ein <b>TreeView<\/b>-Steuerelement und ein <b>ImageList<\/b>-Steuerelement hinzu. Diese nennen wir <b>ctlTreeView <\/b>und <b>ctlImageList<\/b> (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_004.png\" alt=\"Formular mit TreeView- und ImageList-Steuerelement\" width=\"499,6267\" height=\"563,894\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Formular mit TreeView- und ImageList-Steuerelement<\/span><\/b><\/p>\n<p>Damit k&ouml;nnen wir nun den Code zusammenstellen, der zum Anzeigen der Eintr&auml;ge aus den Tabellen <b>tblMenuFolders <\/b>und <b>tblMenuEntries <\/b>verwendet wird.<\/p>\n<p>Die Prozedur soll beim Laden des Formulars ausgel&ouml;st werden und sieht wie in Listing 1 aus. Hier deklarieren wie zun&auml;chst eine modulweit erreichbare Variable f&uuml;r das <b>TreeView<\/b>-Steuerelement mit dem Schl&uuml;sselwort <b>WithEvents<\/b>: <\/p>\n<pre><span style=\"color:blue;\">Private <\/span>objTreeView<span style=\"color:blue;\"> As <\/span>MSComctlLib.TreeView\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>dao.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rstImages<span style=\"color:blue;\"> As <\/span>dao.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstFolders<span style=\"color:blue;\"> As <\/span>dao.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstEntries<span style=\"color:blue;\"> As <\/span>dao.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     <span style=\"color:blue;\">Dim <\/span>objImageList<span style=\"color:blue;\"> As <\/span>MSComctlLib.ImageList\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> objImageList = Me.ctlImageList.Object\r\n     objImageList.ImageHeight = 16\r\n     objImageList.ImageWidth = 16\r\n     <span style=\"color:blue;\">Set<\/span> rstImages = dbc.OpenRecordset(\"SELECT * FROM MSysResources WHERE type = ''img''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstImages.EOF\r\n         amvAddIconToImageListFromResources objImageList, rstImages!ID, rstImages!Name\r\n         rstImages.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     \r\n     \r\n     <span style=\"color:blue;\">Set<\/span> objTreeView = Me.ctlTreeview.Object\r\n     objTreeView.Nodes.Clear\r\n     <span style=\"color:blue;\">Set<\/span> objTreeView.ImageList = objImageList\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstFolders = db.OpenRecordset(\"SELECT * FROM tblMenuFolders WHERE ParentMenuFolderID IS NULL\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstFolders.EOF\r\n         strKey = \"f\" & rstFolders!MenuFolderID\r\n         <span style=\"color:blue;\">Set<\/span> objNode = objTreeView.Nodes.Add(, , strKey, rstFolders!MenuFolderCaption, \"folder\")\r\n         objNode.Expanded = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Call<\/span> AddSubfolders(db, rstFolders!MenuFolderID, strKey)\r\n         <span style=\"color:blue;\">Call<\/span> AddEntries(db, rstFolders!MenuFolderID, strKey)\r\n         rstFolders.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstEntries = db.OpenRecordset(\"SELECT * FROM tblMenuEntries WHERE ParentMenuFolderID IS NULL\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstEntries.EOF\r\n         strKey = \"e\" & rstEntries!MenuEntryID\r\n         objTreeView.Nodes.Add , , strKey, rstEntries!MenuEntryCaption, \"breakpoint\"\r\n         rstEntries.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Prozedur zum Initialisieren des TreeView- und des ImageList-Steuerelements<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private <\/span>objTreeView<span style=\"color:blue;\"> As <\/span>MSComctlLib.TreeView<\/pre>\n<p>Die Prozedur <b>Form_Load <\/b>f&uuml;llt zun&auml;chst das <b>ImageList<\/b>-Steuerelement mit allen Bildern, die wir in der Tabelle <b>MSysResources <\/b>finden. Die ben&ouml;tigten Icons haben wir zuvor hinzugef&uuml;gt, in dem wir ein Formular in der Entwurfsansicht ge&ouml;ffnet und die gew&uuml;nschten Icons mit dem Befehl <b>Bild einf&uuml;gen<\/b> &uuml;ber das Ribbon hinzugef&uuml;gt haben. Diese Bilder werden automatisch in der Tabelle <b>MSysResources <\/b>gespeichert (siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_005.png\" alt=\"Bilder f&uuml;r die TreeView-Eintr&auml;ge aus der Tabelle MSysResources\" width=\"499,6267\" height=\"198,4683\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Bilder f&uuml;r die TreeView-Eintr&auml;ge aus der Tabelle MSysResources<\/span><\/b><\/p>\n<p>Diese Bilder m&uuml;ssen wir nun zum <b>ImageList<\/b>-Steuerelement hinzuf&uuml;gen, damit wir sie f&uuml;r die <b>TreeView<\/b>-Eintr&auml;ge verwenden k&ouml;nnen. Das erledigen die ersten Anweisungen der Prozedur <b>Form_Load<\/b>. Hier referenzieren wir die Eigenschaft <b>Object <\/b>des <b>ImageList<\/b>-Steuerelements mit der Variablen <b>objImageList<\/b>. Dann stellen wir H&ouml;he und Breite der Bilder jeweils auf <b>16 <\/b>ein.<\/p>\n<p>Schlie&szlig;lich &ouml;ffnen wir ein Recordset auf Basis der Tabelle <b>MSysResources <\/b>f&uuml;r alle Eintr&auml;ge, deren Typ <b>img <\/b>lautet. Diese durchlaufen wir ein einer <b>Do While<\/b>-Schleife und rufen jeweils die Prozedur <b>amvAddIconToImageList <\/b>auf. Diese f&uuml;gt die einzelnen Bilder aus der Tabelle in das <b>ImageList<\/b>-Steuerelement ein. Die Prozedur <b>amvAddIconToImageList<\/b> und ihre Hilfsfunktionen wollen wir aus Platzgr&uuml;nden an dieser Stelle nicht erl&auml;utern.<\/p>\n<p>Indem wir die Bilder dynamisch einlesen, k&ouml;nnen wir diese auch einmal ersetzen, ohne dass wir umst&auml;ndlich am Entwurf des Steuerelements operieren m&uuml;ssen.<\/p>\n<p>Nun referenzieren wir das <b>TreeView<\/b>-Steuerelement mit der Variablen <b>objTreeView<\/b>, die wir bereits weiter oben deklariert haben.<\/p>\n<p>Wir leeren eventuell noch vorhandene Nodes mit der <b>Clear<\/b>-Methode und weisen diesem Steuerelement das <b>ImageList<\/b>-Steuerelement als Quelle f&uuml;r die Icons zu.<\/p>\n<p>Dann erstellen wir ein neues Recordset auf Basis der Eintr&auml;ge der Tabelle <b>tblMenuFolders<\/b>, aber nur f&uuml;r die Eintr&auml;ge, die keinen &uuml;bergeordneten Eintrag haben. Diese durchlaufen wir in einer weiteren <b>Do While<\/b>-Schleife.<\/p>\n<p>In dieser Schleife stellen wir einen eindeutigen Schl&uuml;ssel f&uuml;r jedes <b>Node<\/b>-Element im <b>TreeView<\/b>-Steuerelement zusammen, das f&uuml;r Ordner aus dem Buchstaben <b>f <\/b>und der ID des jeweiligen Datensatzes besteht (zum Beispiel <b>f1<\/b>).<\/p>\n<p>Danach f&uuml;gen wir das neue Element mit der <b>Add<\/b>-Methode der <b>Nodes<\/b>-Auflistung des <b>TreeView<\/b>-Steuerelements hinzu.<\/p>\n<p>Dabei geben wir den Key an, den Namen aus dem Feld <b>MenuFolderCaption <\/b>und das zu verwendende Bild (<b>folder<\/b>). Au&szlig;erdem stellen wir die Eigenschaft <b>Expanded <\/b>f&uuml;r das neue Element auf <b>True <\/b>ein, damit untergeordnete Eintr&auml;ge direkt angezeigt werden.<\/p>\n<p>Schlie&szlig;lich rufen wir zwei weitere Prozeduren auf. <b>AddSubfolders <\/b>f&uuml;gt die untergeordneten Ordner hinzu und <b>AddEntries <\/b>die eigentlichen Eintr&auml;ge.<\/p>\n<p>Beiden &uuml;bergeben wir einen Verweis auf das <b>Database<\/b>-Objekt, die ID des &uuml;bergeordneten Ordners und den Key, den wir f&uuml;r das &uuml;bergeordnete Element verwendet haben.<\/p>\n<p>Da wir auch Elemente in der obersten Ebene anzeigen wollen, f&uuml;gen wir noch Code hinzu, der die Eintr&auml;ge der Tabelle <b>tblMenuEntries <\/b>durchl&auml;uft, die im Feld <b>ParentMenuFolderID <\/b>den Wert <b>NULL <\/b>enthalten. F&uuml;r diese legen wir als Key den Buchstaben <b>e <\/b>(f&uuml;r Entry) sowie den anzuzeigenden Text fest.<\/p>\n<h2>Unterordner zum TreeView hinzuf&uuml;gen<\/h2>\n<p>Die Prozedur <b>AddSubfolders <\/b>(siehe Listing 2) soll die Unterordner hinzuf&uuml;gen, die dem mit dem Parameter <b>lngParentFolderID <\/b>entsprechenden Datensatz der Tabelle <b>tblMenuFolders<\/b> untergeordnete sind.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>AddSubfolders(db<span style=\"color:blue;\"> As <\/span>dao.Database, lngParentFolderID<span style=\"color:blue;\"> As Long<\/span>, strKey<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>rstSubfolders<span style=\"color:blue;\"> As <\/span>dao.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSubkey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstSubfolders = db.OpenRecordset(\"SELECT * FROM tblMenuFolders WHERE ParentMenuFolderID = \" _\r\n         & lngParentFolderID, dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstSubfolders.EOF\r\n         strSubkey = \"f\" & rstSubfolders!MenuFolderID\r\n         <span style=\"color:blue;\">Set<\/span> objNode = objTreeView.Nodes.Add(strKey, tvwChild, strSubkey, rstSubfolders!MenuFolderCaption, \"folder\")\r\n         objNode.Expanded = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Call<\/span> AddSubfolders(db, rstSubfolders!MenuFolderID, strSubkey)\r\n         <span style=\"color:blue;\">Call<\/span> AddEntries(db, rstSubfolders!MenuFolderID, strSubkey)\r\n         rstSubfolders.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Prozedur zum Einf&uuml;gen der untergeordneten Ordner<\/span><\/b><\/p>\n<p>Dazu &ouml;ffnen wir ein Recordset, das genau diese Datens&auml;tze aus der Tabelle <b>tblMenuFolders<\/b> liefert. In der folgenden <b>Do While<\/b>-Schleife durchlaufen wir diese Datens&auml;tze und stellen zun&auml;chst in der Variablen <b>strSubkey <\/b>den Key f&uuml;r die zu erstellenden Untereintr&auml;ge zusammen. Diese bestehen wiederum aus dem Buchstaben f und dem Prim&auml;rschl&uuml;sselwert des neuen Elements, also beispielsweise <b>f2<\/b>.<\/p>\n<p>Dann erstellen wir ein neues <b>Node<\/b>-Objekt unterhalb des &uuml;bergeordneten Objekts. Das &uuml;bergeordnete Element referenzieren wir mit dem Key dieses Elements und geben mit dem zweiten Parameter <b>tvwChild <\/b>an, dass das neue Element unterhalb dieses Elements angeordnet werden soll. Der dritte Parameter nimmt den neuen Key auf und der vierte den anzuzeigenden Text. Mit dem f&uuml;nften Parameter &uuml;bergeben wir wieder das Icon <b>folder<\/b>. Auch f&uuml;r dieses Element stellen wir wieder die Eigenschaft <b>Expanded <\/b>auf <b>True <\/b>ein.<\/p>\n<p>Danach rufen wir erneut die Prozedur <b>AddSubfolders <\/b>auf, falls noch weitere Unterordner vorhanden sind. <\/p>\n<p>Au&szlig;erdem verwenden wir die Prozedur <b>AddEntries<\/b>, um die enthaltenen Eintr&auml;ge hinzuzuf&uuml;gen.<\/p>\n<h2>Elemente zum TreeView hinzuf&uuml;gen<\/h2>\n<p>Die Prozedur <b>AddEntries<\/b> (siehe Listing 3) f&uuml;gt die eigentlichen Eintr&auml;ge hinzu. Sie erwartet die gleichen Eintr&auml;ge wie <b>AddSubfolders<\/b>. Hier definieren wir ein Recordset, dass alle Datens&auml;tze der Tabelle <b>tblMenuEntries <\/b>enth&auml;lt, die dem mit <b>lngParentFolderID <\/b>&uuml;bergebenen Ordner zugeordnet sind.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>AddEntries(db<span style=\"color:blue;\"> As <\/span>dao.Database, lngParentFolderID<span style=\"color:blue;\"> As Long<\/span>, strKey<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>rstEntries<span style=\"color:blue;\"> As <\/span>dao.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSubkey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstEntries = db.OpenRecordset(\"SELECT * FROM tblMenuEntries WHERE ParentMenuFolderID = \" _\r\n         & lngParentFolderID, dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstEntries.EOF\r\n         strSubkey = \"e\" & rstEntries!MenuEntryID\r\n         <span style=\"color:blue;\">Set<\/span> objNode = objTreeView.Nodes.Add(strKey, tvwChild, strSubkey, rstEntries!MenuEntryCaption, \"breakpoint\")\r\n         rstEntries.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Prozedur zum Einf&uuml;gen der untergeordneten Eintr&auml;ge<\/span><\/b><\/p>\n<p>F&uuml;r jeden Datensatz dieses Recordsets f&uuml;gen wir wieder ein Element zum <b>TreeView<\/b>-Steuerelement hinzu, wobei wir &auml;hnlich wie in der zuvor beschriebenen Prozedur vorgehen.<\/p>\n<h2>Testen des TreeView-Steuerelements<\/h2>\n<p>Nachdem wir manuell einige Eintr&auml;ge zu den Tabellen hinzuf&uuml;gt haben, werden diese beim &Ouml;ffnen des Formulars <b>frmWindowsKontextmenue <\/b>wie in Bild 6 dargestellt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_006.png\" alt=\"TreeView-Steuerelement mit einigen Eintr&auml;gen\" width=\"549,6265\" height=\"251,5817\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: TreeView-Steuerelement mit einigen Eintr&auml;gen<\/span><\/b><\/p>\n<h2>Kontextmen&uuml;s zum Hinzuf&uuml;gen und L&ouml;schen von Eintr&auml;gen anlegen<\/h2>\n<p>Wir wollen die Tabelleneintr&auml;ge nicht immer direkt in die Tabellen eingeben, sondern diese &uuml;ber ein Kontextmen&uuml; hinzuf&uuml;gen. Der Hauptknoten <b>Daten <\/b>sollte beispielsweise die Eintr&auml;ge <b>Neuer Ordner <\/b>und <b>Neues Element <\/b>anzeigen. F&uuml;r die Unterordner sollen die Eintr&auml;ge <b>Neuer Ordner<\/b>, <b>Neues Element <\/b>und Ordner l&ouml;schen erscheinen. Schlie&szlig;lich sollen die Elemente im Kontextmen&uuml; den Befehl <b>Element l&ouml;schen <\/b>anbieten.<\/p>\n<p>Die Kontextmen&uuml;s zeigen wir an, wenn das Ereignis <b>MouseDown<\/b> des <b>TreeView<\/b>-Steuerelements ausgel&ouml;st wird (siehe Listing 4). Hier pr&uuml;fen wir, ob die rechte Maustaste zum Anklicken verwendet wurde.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ctlTreeview_MouseDown(ByVal Button<span style=\"color:blue;\"> As Integer<\/span>, ByVal Shift<span style=\"color:blue;\"> As Integer<\/span>, ByVal x<span style=\"color:blue;\"> As Long<\/span>, ByVal y<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node, lngID<span style=\"color:blue;\"> As Long<\/span>, strChar<span style=\"color:blue;\"> As String<\/span>, cbr<span style=\"color:blue;\"> As <\/span>CommandBar\r\n     <span style=\"color:blue;\">Dim <\/span>cbbNewFolder<span style=\"color:blue;\"> As <\/span>CommandBarButton, cbbNewEntry<span style=\"color:blue;\"> As <\/span>CommandBarButton, cbbDeleteFolder<span style=\"color:blue;\"> As <\/span>CommandBarButton\r\n     <span style=\"color:blue;\">Dim <\/span>cbbDeleteEntry<span style=\"color:blue;\"> As <\/span>CommandBarButton\r\n     \r\n     <span style=\"color:blue;\">If <\/span>Button = 2<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> objNode = objTreeView.HitTest(x, y)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objNode Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n             strChar = <span style=\"color:blue;\">Left<\/span>(objNode.Key, 1)\r\n             lngID = <span style=\"color:blue;\">Mid<\/span>(objNode.Key, 2)\r\n             Select Case strChar\r\n                 <span style=\"color:blue;\">Case <\/span>\"f\"\r\n                     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n                     CommandBars(\"Folders\").Delete\r\n                     <span style=\"color:blue;\">On Error GoTo<\/span> 0                    \r\n                     <span style=\"color:blue;\">Set<\/span> cbr = CommandBars.Add(\"Folders\", msoBarPopup, , <span style=\"color:blue;\">True<\/span>)\r\n                     <span style=\"color:blue;\">Set<\/span> cbbNewFolder = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n                     cbbNewFolder.Caption = \"Ordner hinzuf&uuml;gen\"\r\n                     cbbNewFolder.OnAction = \"=AddFolder(\" & lngID & \")\"\r\n                     <span style=\"color:blue;\">Set<\/span> cbbDeleteFolder = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n                     cbbDeleteFolder.Caption = \"Ordner l&ouml;schen\"\r\n                     cbbDeleteFolder.OnAction = \"=DeleteFolder(\" & lngID & \")\"\r\n                     <span style=\"color:blue;\">Set<\/span> cbbNewEntry = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n                     cbbNewEntry.Caption = \"Element hinzuf&uuml;gen\"\r\n                     cbbNewEntry.OnAction = \"=AddEntry(\" & lngID & \")\"\r\n                     cbr.ShowPopup\r\n                 <span style=\"color:blue;\">Case <\/span>\"e\"\r\n                     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n                     CommandBars(\"Entries\").Delete\r\n                     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n                     <span style=\"color:blue;\">Set<\/span> cbr = CommandBars.Add(\"Entries\", msoBarPopup, , <span style=\"color:blue;\">True<\/span>)\r\n                     <span style=\"color:blue;\">Set<\/span> cbbDeleteEntry = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n                     cbbDeleteEntry.Caption = \"Element l&ouml;schen\"\r\n                     cbbDeleteEntry.OnAction = \"=DeleteElement(\" & lngID & \")\"\r\n                     cbr.ShowPopup\r\n             <span style=\"color:blue;\">End Select<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n             CommandBars(\"Folders\").Delete\r\n             <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n             <span style=\"color:blue;\">Set<\/span> cbr = CommandBars.Add(\"Folders\", msoBarPopup, , <span style=\"color:blue;\">True<\/span>)\r\n             <span style=\"color:blue;\">Set<\/span> cbbNewFolder = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n             cbbNewFolder.Caption = \"Ordner hinzuf&uuml;gen\"\r\n             cbbNewFolder.OnAction = \"=AddFolder(0)\"\r\n             <span style=\"color:blue;\">Set<\/span> cbbNewEntry = cbr.Controls.Add(msoControlButton, , , , <span style=\"color:blue;\">True<\/span>)\r\n             cbbNewEntry.Caption = \"Element hinzuf&uuml;gen\"\r\n             cbbNewEntry.OnAction = \"=AddEntry(0)\"\r\n             cbr.ShowPopup\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><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Prozedur zum Anzeigen der Kontextmen&uuml;s<\/span><\/b><\/p>\n<p>Danach holen wir mit den Koordinaten <b>x <\/b>und <b>y <\/b>aus den Parametern &uuml;ber die Funktion <b>HitTest <\/b>das Objekt, das angeklickt wurde. Ist <b>objNode <\/b>danach nicht leer, k&ouml;nnen wir das Kontextmen&uuml; f&uuml;r das entsprechende Element anzeigen.<\/p>\n<p>Anderenfalls hat der Benutzer in den leeren Raum au&szlig;erhalb der Elemente geklickt, was ein Kontextmen&uuml; mit den Befehlen <b>Ordner hinzuf&uuml;gen <\/b>und <b>Element hinzuf&uuml;gen <\/b>anzeigen soll.<\/p>\n<p>Schauen wir uns erst einmal den Fall an, dass der Benutzer auf einen bestehenden Eintrag geklickt hat. In diesem Fall holen wir uns mit Zeichenkettenfunktionen aus der Eigenschaft <b>Key <\/b>des Elements den Buchstaben und die ID und schreiben diese in die Variablen <b>strChar <\/b>und <b>lngID<\/b>.<\/p>\n<p>Im Falle des Buchstaben <b>f <\/b>hat der Benutzer einen Ordner angeklickt. Dann l&ouml;schen wir ein eventuell bereits vorhandenes Kontextmen&uuml; namens <b>Folders <\/b>und legen dieses im n&auml;chsten Schritt erneut an.<\/p>\n<p>Dann f&uuml;gen wir eine Schaltfl&auml;che mit dem Titel <b>Ordner hinzuf&uuml;gen <\/b>hinzu und legen f&uuml;r seine Eigenschaft <b>OnAction <\/b>den Ausdruck zum Aufruf der Funktion <b>OrdnerHinzufuegen <\/b>fest, wobei wir gleich die ID f&uuml;r den &uuml;bergeordneten Ordner hinzuf&uuml;gen.<\/p>\n<p>Der Ausdruck sieht zum Beispiel wie folgt aus:<\/p>\n<pre>=OrdnerHinzufuegen(1)<\/pre>\n<p>Auf die gleiche Weise f&uuml;gen wir den Button mit der Beschriftung <b>Ordner l&ouml;schen <\/b>und einem Befehl wie dem folgenden hinzu:<\/p>\n<pre>=DeleteFolder(1)<\/pre>\n<p>Schlie&szlig;lich folgt noch eine Schaltfl&auml;che mit dem Text Element hinzuf&uuml;gen, welche beispielsweise den folgenden Aufruf enthalten soll:<\/p>\n<pre>=AddEntry(1)<\/pre>\n<p>Schlie&szlig;lich zeigen wir das Kontextmen&uuml; mit der Methode <b>ShowPopup <\/b>an (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_007.png\" alt=\"Kontextmen&uuml; eines Ordners\" width=\"549,6265\" height=\"249,0093\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Kontextmen&uuml; eines Ordners<\/span><\/b><\/p>\n<p>Danach folgt das Kontextmen&uuml;, falls der Benutzer eines der Elemente angeklickt hat. Der Key dieser Elemente beginnt mit <b>e<\/b>, also pr&uuml;fen wir in der <b>Select Case<\/b>-Bedingung auf diesen Buchstaben.<\/p>\n<p>Hier l&ouml;schen wir das gegebenenfalls bereits vorhandene Kontextmen&uuml; namens <b>Entries <\/b>und f&uuml;gen es erneut hinzu. Dieses erh&auml;lt nur einen Button mit der Beschriftung <b>Element l&ouml;schen <\/b>und der folgenden Aktion:<\/p>\n<pre>=DeleteElement(1)<\/pre>\n<p>Danach zeigen wir das Kontextmen&uuml; mit <b>ShowPopup <\/b>an.<\/p>\n<p>Schlie&szlig;lich folgt noch der Fall, dass der Benutzer au&szlig;erhalb eines der Elemente geklickt hat.<\/p>\n<p>Das Kontextmen&uuml; f&uuml;r diesen Fall soll die Befehle <b>Ordner hinzuf&uuml;gen <\/b>und <b>Element hinzuf&uuml;gen <\/b>anzeigen, welche Aufrufe wie die folgenden enthalten:<\/p>\n<pre>=AddFolder(0)\r\n=AddEntry(0)<\/pre>\n<h2>Funktionen f&uuml;r die Kontextmen&uuml;befehle<\/h2>\n<p>Damit h&auml;tten wir auch die Kontextmen&uuml;s hinzugef&uuml;gt und k&ouml;nnen nun die aufzurufenden Funktionen erstellen. Die nachfolgend vorgestellten Funktionen tragen wir in einem neuen Standardmodul namens <b>mdlCommandbars <\/b>ein und deklarieren mit dem Schl&uuml;sselwort <b>Public<\/b>, da diese sonst nicht aufrufbar w&auml;ren.<\/p>\n<p>Die Funktion zum Hinzuf&uuml;gen eines Ordners unterhalb eines bestehenden Ordners finden wir in Listing 5. Hier nehmen wir die ID des &uuml;bergeordneten Ordners entgegen und fragen dann per InputBox den Namen des neuen Ordners ab. Liefert die InputBox keine leere Zeichenkette und ist <b>lngID <\/b>nicht <b>0<\/b>, tr&auml;gt die Prozedur den neuen Datensatz in die Tabelle <b>tblMenuFolders <\/b>ein.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddFolder(lngID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>strFolder<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strSubkey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngSubID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strFolder = InputBox(\"Name des Ordners:\", \"Neuer Unterordner\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strFolder) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngID = 0<span style=\"color:blue;\"> Then<\/span>\r\n             db.Execute \"INSERT INTO tblMenuFolders(MenuFolderCaption, ParentMenuFolderID) VALUES(''\" & strFolder & \"'', _\r\n                 \" & lngID & \")\", dbFailOnError\r\n             lngSubID = db.OpenRecordset(\"SELECT @@IDENTITY\").Fields(0)\r\n             strSubkey = \"f\" & lngSubID\r\n             strKey = \"f\" & lngID\r\n             <span style=\"color:blue;\">Set<\/span> objNode = Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Add(strKey, tvwChild, _\r\n                 strSubkey, strFolder, \"folder\")\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             db.Execute \"INSERT INTO tblMenuFolders(MenuFolderCaption) VALUES(''\" & strFolder & \"'')\", dbFailOnError\r\n             lngSubID = db.OpenRecordset(\"SELECT @@IDENTITY\").Fields(0)\r\n             strSubkey = \"f\" & lngSubID\r\n             <span style=\"color:blue;\">Set<\/span> objNode = Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Add(, , strSubkey, strFolder, \"folder\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         objNode.Expanded = <span style=\"color:blue;\">True<\/span>\r\n         objNode.Parent.Expanded = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Funktion zum Einf&uuml;gen eines untergeordneten Ordners per Kontextmen&uuml;<\/span><\/b><\/p>\n<p>Danach ermittelt sie die ID des neuen Eintrags, stellt <b>strKey <\/b>und <b>strSubkey <\/b>zusammen und f&uuml;gt auch noch das entsprechende Element zum TreeView hinzu.<\/p>\n<p>Falls <b>lngID <\/b>den Wert <b>0 <\/b>enth&auml;lt, wurde die Funktion ohne &uuml;bergeordneten Ordner aufgerufen und wir f&uuml;hren die gleichen Schritte durch &#8211; allerdings wird in der Tabelle <b>tblMenuFolders <\/b>kein &uuml;bergeordneter Ordner angegeben. Au&szlig;erdem legen wir das neue Element im TreeView auf der obersten Ebene an.<\/p>\n<p>Die Funktion zum Anlegen eines neuen Men&uuml;befehls erfolgt weitgehend analog (siehe Listing 6). Auch hier &uuml;bergeben wir mit <b>lngID <\/b>die ID des &uuml;bergeordneten Ordners.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddEntry(lngID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>strEntry<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strSubkey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngSubID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objNode<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strEntry = InputBox(\"Name des Men&uuml;befehls:\", \"Neuer Men&uuml;befehl\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strEntry) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngID = 0<span style=\"color:blue;\"> Then<\/span>\r\n             db.Execute \"INSERT INTO tblMenuEntries(MenuEntryCaption, ParentMenuFolderID) VALUES(''\" & strEntry & \"'', \" _\r\n                 & lngID & \")\", dbFailOnError\r\n             lngSubID = db.OpenRecordset(\"SELECT @@IDENTITY\").Fields(0)\r\n             strSubkey = \"e\" & lngSubID\r\n             strKey = \"f\" & lngID\r\n             <span style=\"color:blue;\">Set<\/span> objNode = Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Add(strKey, tvwChild, strSubkey, _\r\n                 strEntry, \"breakpoint\")\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             db.Execute \"INSERT INTO tblMenuEntries(MenuEntryCaption) VALUES(''\" & strEntry & \"'')\", dbFailOnError\r\n             lngSubID = db.OpenRecordset(\"SELECT @@IDENTITY\").Fields(0)\r\n             strSubkey = \"e\" & lngSubID\r\n             <span style=\"color:blue;\">Set<\/span> objNode = Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Add(, , strSubkey, strEntry, \"breakpoint\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         objNode.Parent.Expanded = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion zum Einf&uuml;gen eines neuen Men&uuml;befehls per Kontextmen&uuml;<\/span><\/b><\/p>\n<p>Wir fragen den Namen des neuen Eintrags per InputBox ab und tragen diesen entweder unterhalb des mit <b>lngID <\/b>angegebenen Ordners ein (wenn ein Wert ungleich <b>0 <\/b>&uuml;bergeben wurde) oder als neues Element auf der obersten Ebene des TreeViews (wenn <b>lngID <\/b>den <b>0 <\/b>hat).<\/p>\n<h2>L&ouml;schen von Ordnern<\/h2>\n<p>Das L&ouml;schen eines Ordners &uuml;bernimmt die Funktion aus Listing 7. Die Funktion nimmt die ID des zu l&ouml;schenden Ordners entgegen und l&ouml;scht diesen zuerst aus der Tabelle <b>tblMenuFolders <\/b>und dann aus dem TreeView.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DeleteFolder(lngID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strKey = \"f\" & lngID\r\n     db.Execute \"DELETE FROM tblMenuFolders WHERE MenuFolderID = \" & lngID, dbFailOnError\r\n     Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Remove strKey\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Funktion zum L&ouml;schen eines Ordners per Kontextmen&uuml;<\/span><\/b><\/p>\n<h2>L&ouml;schen von Men&uuml;eintr&auml;gen<\/h2>\n<p>Schlie&szlig;lich finden wir in Listing 8 noch die Funktion zum L&ouml;schen eines Men&uuml;eintrags. Diese entfernt ein Element f&uuml;r einen Men&uuml;eintrag aus der Tabelle <b>tblMenuEntries <\/b>und anschlie&szlig;end aus dem TreeView.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DeleteEntry(lngID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strKey = \"e\" & lngID\r\n     db.Execute \"DELETE FROM tblMenuEntries WHERE MenuEntryID = \" & lngID, dbFailOnError\r\n     Forms!frmWindowsKontextmenues!ctlTreeview.Object.Nodes.Remove strKey\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Funktion zum L&ouml;schen eines Men&uuml;eintrags per Kontextmen&uuml;<\/span><\/b><\/p>\n<h2>Anzeigen von Men&uuml;eintr&auml;gen im Unterformular<\/h2>\n<p>Bisher haben wir noch keine M&ouml;glichkeit, die gew&uuml;nschte Information, die sich hinter einem der <b>TreeView<\/b>-Elemente verbirgt, einzutragen. Dazu f&uuml;gen wir dem Formular ein Unterformular namens <b>sfmWindowsKontextmenues <\/b>hinzu.<\/p>\n<p>Dieses binden wir an die Tabelle <b>tblMenuEntries <\/b>und f&uuml;gen die beiden Felder <b>MenuEntryCaption <\/b>und <b>MenuEntryContent <\/b>hinzu (siehe Bild 8).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_008.png\" alt=\"Neues Unterformular zur Anzeige von Beschriftung und Parameter\" width=\"599,6265\" height=\"303,1539\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Neues Unterformular zur Anzeige von Beschriftung und Parameter<\/span><\/b><\/p>\n<p>Au&szlig;erdem erweitern wir den Code der Prozedur <b>ctlTreeView_MouseDown<\/b> wie in Listing 9.<\/p>\n<pre><span style=\"color:blue;\">If <\/span>Button = 1<span style=\"color:blue;\"> Then<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objNode = ctlTreeview.HitTest(x, y)\r\n     strChar = <span style=\"color:blue;\">Left<\/span>(objNode.Key, 1)\r\n     Select Case strChar\r\n         <span style=\"color:blue;\">Case <\/span>\"f\"\r\n             <span style=\"color:blue;\">With<\/span> Me.sfmWindowsKontextmenues.Form\r\n                 !txtMenuEntryCaption.enabled = <span style=\"color:blue;\">False<\/span>\r\n                 !txtMenuEntryContent.enabled = <span style=\"color:blue;\">False<\/span>\r\n                 .Filter = \"1=2\"\r\n                 .FilterOn = <span style=\"color:blue;\">True<\/span>\r\n             End <span style=\"color:blue;\">With<\/span>\r\n         <span style=\"color:blue;\">Case <\/span>\"e\"\r\n             lngID = <span style=\"color:blue;\">Mid<\/span>(objNode.Key, 2)\r\n             <span style=\"color:blue;\">With<\/span> Me.sfmWindowsKontextmenues.Form\r\n                 !txtMenuEntryCaption.enabled = <span style=\"color:blue;\">True<\/span>\r\n                 !txtMenuEntryContent.enabled = <span style=\"color:blue;\">True<\/span>\r\n                 .Filter = \"MenuEntryID = \" & lngID\r\n                 .FilterOn = <span style=\"color:blue;\">True<\/span>\r\n             End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End If<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Erweiterung der Prozedur ctlTreeView_MouseDown<\/span><\/b><\/p>\n<p>Hier pr&uuml;fen wir, ob der Benutzer die linke Maustaste gedr&uuml;ckt hat und dabei ein Element des TreeViews angesteuert wurde.<\/p>\n<p>In diesem Fall referenzieren wir dieses mit <b>objNode<\/b> und ermitteln daraus den Buchstaben der <b>Key<\/b>-Eigenschaft. Im Falle des Buchstabens <b>f <\/b>wurde ein Ordner angeklickt. Dann deaktivieren wir die beiden Textfelder im Unterformular und leeren die Datensatzquelle durch Setzen des Kriteriums <b>1=2<\/b>.<\/p>\n<p>Beim Buchstaben <b>e<\/b>, also beim Anklicken eines der Men&uuml;eintr&auml;ge, holen wir uns die ID des angeklickten Elements, setzen einen Filter auf diese ID und aktivieren die beiden Textfelder.<\/p>\n<p>Das Ergebnis sehen wir in Bild 9.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_009.png\" alt=\"Anzeige der Daten f&uuml;r einen Men&uuml;eintrag im Unterformular\" width=\"599,6265\" height=\"303,1539\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Anzeige der Daten f&uuml;r einen Men&uuml;eintrag im Unterformular<\/span><\/b><\/p>\n<p>In diesem Unterformular k&ouml;nnen wir nun die Beschriftung des Kontextmen&uuml;-Eintrags &auml;ndern. Dies soll auch den Text des entsprechenden Elements im TreeView anpassen. Dazu f&uuml;gen wir dem Textfeld <b>txtMenuEntryCaption <\/b>im Unterformular ein Ereignis f&uuml;r die Eigenschaft <b>Nach Aktualisierung<\/b> hinzu. Diese sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtMenuEntryCaption_AfterUpdate()\r\n     Me.Parent.ctlTreeview.Nodes(\"e\" & Me.MenuEntryID).Text _\r\n        = Me.txtMenuEntryCaption\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Eintragen in das Windows-Kontextmen&uuml;<\/h2>\n<p>Damit kommen wir zum entscheidenden Schritt: Wir f&uuml;gen eine Schaltfl&auml;che hinzu, mit der wir die in das Formular eingegebenen Daten in das Windows-Kontextmen&uuml; &uuml;bertragen. Die Schaltfl&auml;che l&ouml;st zun&auml;chst die folgende Prozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdKontextmenuesAnlegen_Click()\r\n     <span style=\"color:blue;\">Call<\/span> UpdateContextmenus\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die dadurch aufgerufene Prozedur und die &uuml;brigen Prozeduren zum &Uuml;bertragen der Daten in die Registry haben wir in einem eigenen Modul namens <b>mdlUpdateContextmenus <\/b>untergebracht.<\/p>\n<p>Die erste Prozedur namens <b>UpdateContextMenus<\/b> sehen wir in Listing 10. Hier erstellen wir als Erstes, falls noch nicht vorhanden, im Verzeichnis der aktuellen Datenbank ein Unterverzeichnis namens <b>Commands<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>UpdateContextmenus()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strRegistryPath<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strCaption<span style=\"color:blue;\"> As String<\/span>\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     MkDir CurrentProject.Path & \"\\Commands\"\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblMenuFolders WHERE ParentMenuFolderID IS NULL\", dbOpenDynaset)\r\n     strRegistryPath = \"Software\\Classes\\Directory\\Background\\shell\\\"\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         strCaption = rst!MenuFolderCaption\r\n         <span style=\"color:blue;\">Call<\/span> DeleteKey(HKEY_CLASSES_ROOT, strRegistryPath & \"\\\" & strCaption)\r\n         <span style=\"color:blue;\">Call<\/span> AddContextMenuFolder(strRegistryPath & strCaption, strCaption, \"SubCommands\")\r\n         <span style=\"color:blue;\">Call<\/span> UpdateCommands(rst!MenuFolderID, strRegistryPath & strCaption)\r\n         <span style=\"color:blue;\">Call<\/span> UpdateContextmenus_Rek(rst!MenuFolderID, strRegistryPath & strCaption)\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Aktualisieren der Windows-Kontextmen&uuml;s<\/span><\/b><\/p>\n<p>Hier speichern wir die Batchdateien, die von den Kontextmen&uuml;-Eintr&auml;gen aufgerufen werden.<\/p>\n<p>Danach &ouml;ffnet die Prozedur ein Recordset auf Basis der Tabelle <b>tblMenuFolders <\/b>f&uuml;r alle Eintr&auml;ge, deren Feld <b>ParentMenuFolderID <\/b>den Wert <b>NULL <\/b>hat und die somit in der ersten Ebene liegen.<\/p>\n<p>Wir stellen au&szlig;erdem den Basispfad f&uuml;r die Registry ein.<\/p>\n<p>Dann durchl&auml;uft die Prozedur alle Datens&auml;tze des Recordsets und l&ouml;scht zun&auml;chst einen eventuell bereits vorhandenen Eintrag mit dem Namen des aktuellen Eintrags aus der Registry.<\/p>\n<p>Diese Datens&auml;tze durchl&auml;uft die Prozedur in einer <b>Do While<\/b>-Schleife. Darin ruft sie die Prozedur <b>UpdateContextmenus_Rek <\/b>auf und anschlie&szlig;end die Prozedur <b>UpdateCommands<\/b>.<\/p>\n<p>Danach ruft sie die Prozedur <b>AddContextMenuFolder <\/b>auf und &uuml;bergibt den Registrypfad plus den Namen des aktuellen Eintrags. Diese Prozedur soll den Hauptordner f&uuml;r das anzuzeigende Kontextmen&uuml; erstellen.<\/p>\n<p>Die danach aufgerufene Prozedur <b>UpdateCommands <\/b>legt die Batch-Datei an. <\/p>\n<p>Schlie&szlig;lich rufen wir die Prozedur <b>UpdateContextmenus_Rek<\/b>, welche die untergeordneten Eintr&auml;ge in anlegt.<\/p>\n<h2>Rekursive Prozdur UpdateContextmenu_Rek<\/h2>\n<p>Die Prozedur <b>UpdateContextmenu_Rek <\/b>enth&auml;lt grunds&auml;tzlich die gleichen Anweisungen wie <b>UpdateContextmenu<\/b>, ist aber so definiert, dass sie sich f&uuml;r weitere Untermen&uuml;s erneut selbst aufruft (siehe Listing 11).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>UpdateContextmenus_Rek(lngID<span style=\"color:blue;\"> As Long<\/span>, strRegistryPath<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblMenuFolders WHERE ParentMenufolderID = \" & lngID, dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         AddContextMenuFolder strRegistryPath & \"\\shell\\\" & rst!MenuFolderCaption, rst!MenuFolderCaption, \"SubCommands\"\r\n         UpdateCommands rst!MenuFolderID, strRegistryPath & \"\\shell\\\" & rst!MenuFolderCaption\r\n         UpdateContextmenus_Rek rst!MenuFolderID, strRegistryPath & \"\\shell\\\" & rst!MenuFolderCaption\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 11: Aktualisieren der untergeordneten Windows-Kontextmen&uuml;s<\/span><\/b><\/p>\n<p>Die Prozedur nimmt die ID des &uuml;bergeordneten Datensatzes entgegen sowie den bisher aufgebauten Registrierungspfad. Sie erstellt ein Recordset mit allen Eintr&auml;gen der Tabelle <b>tblMenuFolders<\/b>, die dem Datensatz mit der gelieferten ID untergeordnet sind.<\/p>\n<p>F&uuml;r diese Datens&auml;tze ruft sie wiederum die Prozedur <b>AddContextMenuFolder <\/b>auf, die den &uuml;bergebenen Pfad um <b>\\shell\\ <\/b>und die Bezeichnung des aktuellen Ordners erweitert. Das Gleiche erledigt sie mit der Prozeduren <b>UpdateCommands<\/b> und ruft sich dann erneut selbst auf &#8211; wiederum f&uuml;r die aktuelle ID und den aktuellen Ordner.<\/p>\n<h2>Prozedur zum Anlegen der Kontextmen&uuml;-Befehle und der Batch-Dateien<\/h2>\n<p>Das eigentliche Anlegen der Kontextmen&uuml;-Eintr&auml;ge und der von diesen Kontextmen&uuml;s aufzurufenden Batch-Dateien erledigt die Prozedur <b>UpdateCommands<\/b> (siehe Listing 12).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>UpdateCommands(lngID<span style=\"color:blue;\"> As Long<\/span>, strRegistryPath<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strCommandFile<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblMenuEntries WHERE ParentMenufolderID = \" & lngID, dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         strCommandFile = CurrentProject.Path & \"\\Commands\\\" & rst!MenuEntryID & \"_\" & rst!MenuEntryCaption & \".bat\"\r\n         <span style=\"color:blue;\">Call<\/span> CreateCommandfile(strCommandFile, Nz(rst!MenuEntryContent, \"\"))\r\n         <span style=\"color:blue;\">Call<\/span> AddContextMenu(strRegistryPath & \"\\shell\\\" & rst!MenuEntryCaption, rst!MenuEntryCaption, strCommandFile)\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 12: Anlegen der eigentlichen Kontextmen&uuml;-Eintr&auml;ge <\/span><\/b><\/p>\n<p>Diese nimmt wieder die ID des &uuml;bergeordneten Elements sowie den Registrierungspfad entgegen und erstellt ein neues Recordset, diesmal auf Basis der Tabelle <b>tblMenuEntries<\/b>.<\/p>\n<p>In <b>strCommandFile <\/b>stellt sie den Pfad f&uuml;r die zu erstellende Batch-Datei zusammen. Dann ruft sie die Prozedur <b>CreateCommandFile <\/b>auf und &uuml;bergibt dieser den Pfad sowie den Inhalt, der von der Batch-Datei in die Zwischenablage kopiert werden soll.<\/p>\n<p>Au&szlig;erdem ruft sie die Prozedur <b>CreateCommandfile<\/b> auf und &uuml;bergibt dieser ebenfalls den Pfad sowie den Namen des anzulegenden Kontextmen&uuml;-Befehls. Schlie&szlig;lich folgt noch ein Aufruf der Prozedur <b>AddContextMenu<\/b>, welche den Kontextmen&uuml;-Befehl zur Registry hinzuf&uuml;gt. Hier h&auml;ngt sie zum aktuellen Registry-Pfad noch <b>\\shell\\ <\/b>und den Namen des gew&uuml;nschten Eintrags an.<\/p>\n<h2>Anlegen der Batch-Dateien<\/h2>\n<p>Wir schauen uns zuerst die Prozedur <b>CreateCommandfile <\/b>an. Die allereinfachste Variante daf&uuml;r sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>CreateCommandfile(strPath<span style=\"color:blue;\"> As String<\/span>, strText<span style=\"color:blue;\"> As String<\/span>)\r\n     Open strPath For Append<span style=\"color:blue;\"> As <\/span>#1\r\n     Print #1, strText\r\n     Close #1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sie erh&auml;lt von der aufrufenden Prozedur <b>UpdateCommands <\/b>den Pfad der zu erstellenden Datei und den Text, der in dieser Datei gespeichert werden soll.<\/p>\n<p>Sie legt die Datei an und tr&auml;gt den Text ein.<\/p>\n<p>Wir haben diese allerdings noch erweitert, sodass wir auch mehrzeilige Inhalte &uuml;bergeben k&ouml;nnen und auch das Escapen von Sonderzeichen, hier spitzen Klammern, ber&uuml;cksichtigt wird (siehe Listing 13).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>CreateCommandfile(strpath<span style=\"color:blue;\"> As String<\/span>, strText<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strTexte()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strClip<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     \r\n     Open strpath For Output<span style=\"color:blue;\"> As <\/span>#1\r\n     strTexte = <span style=\"color:blue;\">Split<\/span>(strText, <span style=\"color:blue;\">vbCrLf<\/span>)\r\n     strClip = strClip & \"@echo off\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strClip = strClip & \"(\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     For i = <span style=\"color:blue;\">LBound<\/span>(strTexte) To <span style=\"color:blue;\">UBound<\/span>(strTexte)\r\n         strTexte(i) = <span style=\"color:blue;\">Replace<\/span>(strTexte(i), \"&lt;\", \"^&lt;\")\r\n         strTexte(i) = <span style=\"color:blue;\">Replace<\/span>(strTexte(i), \"&gt;\", \"^&gt;\")\r\n         strClip = strClip & \"  echo \" & strTexte(i) & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     strClip = strClip & \") &gt; \"\"%temp%\\_clip.txt\"\"\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strClip = strClip & \"clip &lt; \"\"%temp%\\_clip.txt\"\"\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strClip = strClip & \"del \"\"%temp%\\_clip.txt\"\"\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strClip = strClip & \"exit \/b\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     Print #1, strClip\r\n     Close #1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 13: Prozedur zum Erstellen der Batch-Dateien<\/span><\/b><\/p>\n<h2>Anlegen der Kontextmen&uuml;s f&uuml;r die Folder<\/h2>\n<p>F&uuml;r die Ordner k&ouml;nnen wir nicht nur einen einfachen Eintrag zur Registry hinzuf&uuml;gen, sondern dieser muss auch noch einen bestimmten Eintrag enthalten. Dieser hei&szlig;t <b>SubCommands <\/b>und sieht wie in Bild 10 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_010.png\" alt=\"Zusatzeintrag, damit der Ordner im Kontextmen&uuml; auch Unterordner anzeigt\" width=\"599,6265\" height=\"276,4045\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Zusatzeintrag, damit der Ordner im Kontextmen&uuml; auch Unterordner anzeigt<\/span><\/b><\/p>\n<p>Die Prozedur legt mit der API-Funktion <b>RegCreateKey <\/b>aus dem Modul <b>mdlAPIRegistration <\/b>den gew&uuml;nschten Eintrag in der Registry an und f&uuml;gt mit der Funktion <b>RegSetValueEx <\/b>noch den das Element <b>SubCommands <\/b>hinzu (siehe Listing 14).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AddContextMenuFolder(strRegistryPath<span style=\"color:blue;\"> As String<\/span>, strText<span style=\"color:blue;\"> As String<\/span>, strKey<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>lResult<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hKey<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>strCommandKey<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     lResult = RegCreateKeyEx(HKEY_CURRENT_USER, strRegistryPath, 0, vbNullString, 0, KEY_WRITE, 0, hKey, 0)\r\n     <span style=\"color:blue;\">If <\/span>lResult = 0<span style=\"color:blue;\"> Then<\/span>\r\n         RegSetValueEx hKey, strKey, 0, REG_SZ, ByVal strKey, 0\r\n         RegCloseKey hKey\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 14: Hinzuf&uuml;gen eines Ordners f&uuml;r das Kontextmen&uuml;<\/span><\/b><\/p>\n<h2>Anlegen der Kontextmen&uuml;-Eintr&auml;ge f&uuml;r die Befehle<\/h2>\n<p>Schlie&szlig;lich ruft die Prozedur <b>UpdateCommands <\/b>noch die Prozedur <b>AddContextMenu <\/b>auf (siehe Listing 15). Diese legt mithilfe von API-Funktionen die restlichen ben&ouml;tigten Elemente in der Registry an.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AddContextMenu(strRegistryPath<span style=\"color:blue;\"> As String<\/span>, strText<span style=\"color:blue;\"> As String<\/span>, strCommand<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>lResult<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hKey<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>strCommandKey<span style=\"color:blue;\"> As String<\/span>\r\n         \r\n     strCommandKey = strRegistryPath & \"\\command\"\r\n     \r\n     lResult = RegCreateKeyEx(HKEY_CURRENT_USER, strRegistryPath, 0, vbNullString, 0, KEY_WRITE, 0, hKey, 0)\r\n     <span style=\"color:blue;\">If <\/span>lResult = 0<span style=\"color:blue;\"> Then<\/span>\r\n         RegSetValueEx hKey, vbNullString, 0, REG_SZ, ByVal strText, LenB(strText) + 1\r\n         RegCloseKey hKey\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     lResult = RegCreateKeyEx(HKEY_CURRENT_USER, strCommandKey, 0, vbNullString, 0, KEY_WRITE, 0, hKey, 0)\r\n     <span style=\"color:blue;\">If <\/span>lResult = 0<span style=\"color:blue;\"> Then<\/span>\r\n         RegSetValueEx hKey, vbNullString, 0, REG_SZ, ByVal strCommand, LenB(strCommand) + 1\r\n         RegCloseKey hKey\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 15: Hinzuf&uuml;gen der weiteren Kontextmen&uuml;-Elemente<\/span><\/b><\/p>\n<h2>Ergebnis in der Registry<\/h2>\n<p>F&uuml;hren wir diese Prozeduren nun aus, werden die ben&ouml;tigten Eintr&auml;ge in der Registry angelegt (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_011.png\" alt=\"Vollst&auml;ndiger Registry-Eintrag, der f&uuml;r die Anzeige eines Kontextmen&uuml;-Eintrags mit Unterordnern sorgt\" width=\"700\" height=\"304,2161\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Vollst&auml;ndiger Registry-Eintrag, der f&uuml;r die Anzeige eines Kontextmen&uuml;-Eintrags mit Unterordnern sorgt<\/span><\/b><\/p>\n<p>Der aktuelle Eintrag sorgt f&uuml;r die Anzeige eines Kontextmen&uuml;-Eintrags mit der Hierarchie <b>Daten<\/b>\/<b>Kontonummern<\/b>\/<b>American Express<\/b>, der wie in Bild 12 erscheinen wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_481_012.png\" alt=\"Anzeige der soeben erstellten Kontextmen&uuml;-Eintr&auml;ge\" width=\"649,627\" height=\"426,9227\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Anzeige der soeben erstellten Kontextmen&uuml;-Eintr&auml;ge<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit dieser L&ouml;sung k&ouml;nnen wir eine beliebige Struktur aus Ordnern und Befehlen anlegen. Anwendungsf&auml;lle gibt es dazu genug. Ich selbst werde es beispielsweise nutzen f&uuml;r:<\/p>\n<ul>\n<li>Kontonummern<\/li>\n<li>Steuernummern<\/li>\n<li>Wichtige Links, die ich immer wieder in E-Mails kopiere<\/li>\n<\/ul>\n<p>Der Code enth&auml;lt noch einige Funktionen, die wir hier nicht erl&auml;utert haben wie zum Beispiel das Umbenennen von Elementen und wir werden diese L&ouml;sung noch erweitern.<\/p>\n<p>Wir k&ouml;nnten zum Beispiel noch Icons definieren, die im Kontextmen&uuml; angezeigt werden, um die Eintr&auml;ge noch besser hervorzuheben.<\/p>\n<p>Wichtig ist zu wissen, dass diese Eintr&auml;ge nicht in dem neuen Kontextmen&uuml; von Windows 11 angezeigt werden, sondern nur in dem Kontextmen&uuml;, dass nach Auswahl des Befehls <b>Weitere Optionen <\/b>im Standard-Kontextmen&uuml; erscheint.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Artikel &#8220;UstIdNr, IBAN und Co. per Kontextmen&uuml;&#8221; (www.vbentwickler.de\/480) haben wir gezeigt, wie wir die Windows-Kontextmen&uuml;s erweitern k&ouml;nnen. In diesem Fall haben wir Daten, die man gegebenenfalls nicht alle im Kopf hat, aber regelm&auml;&szlig;ig ben&ouml;tigt, einfach &uuml;ber ein Kontextmen&uuml; in die Zwischenablage einf&uuml;gen kann, um diese dann an der gew&uuml;nschten Stelle beispielsweise in einem Bestellformular eintr&auml;gt. Um das Hinzuf&uuml;gen und Aktualisieren dieser Eintr&auml;ge weiter zu vereinfachen und die zahlreichen Handgriffe zu ersparen, zeigen wir im vorliegenden Artikel eine Access-L&ouml;sung, mit der wir die Kontextmen&uuml;-Befehle mit einem einfachen TreeView verwalten und erweitern k&ouml;nnen.<\/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":[662025,66042025,44000004],"tags":[],"yst_prominent_words":[],"class_list":["post-55000481","post","type-post","status-publish","format-standard","hentry","category-662025","category-66042025","category-Loesungen"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000481","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000481"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000481\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000481"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000481"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}