{"id":55000495,"date":"2025-12-01T00:00:00","date_gmt":"2026-02-05T12:00:18","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=495"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Per_VBA_von_Early_Binding_zu_Late_Binding_wechseln","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Per_VBA_von_Early_Binding_zu_Late_Binding_wechseln\/","title":{"rendered":"Per VBA von Early Binding zu Late Binding wechseln"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/f7d78bb3497f4d1f8860b4b1757ff0d3\" width=\"1\" height=\"1\" alt=\"\"><b>Im Artikel &#8220;VBA: Early Binding und Late Binding&#8221; (www.vbentwickler.de\/4) haben wir die beiden Methoden Early Binding und Late Binding vorgestellt und ihre Vor- und Nachteile beschrieben. Im vorliegenden Artikel zeigen wir nun eine automatische L&ouml;sung, um schnell einige oder alle per Early Binding definierten Elemente nach Late Binding zu migrieren. Dazu nutzen wir Code, der zun&auml;chst alle Early Binding-Elemente ermittelt, diese in einem Formular anzeigt und es dann erm&ouml;glicht, diese in Late Binding-Elemente umzuwandeln. <\/b><\/p>\n<p>Die L&ouml;sung aus diesem Artikel soll es erm&ouml;glichen, alle Module der aktuellen Datenbank aus einem Listenfeld auszuw&auml;hlen und alle dort in Deklarationszeilen vorhandenen Klassen, Typen und Enumerationen einzulesen.<\/p>\n<p>Wir ben&ouml;tigen zwar die Typen und Enumerationen nicht, da wir diese nicht nach Late Binding migrieren k&ouml;nnen, aber aus technischen Gr&uuml;nden k&ouml;nnen wir diese nicht ohne erheblichen Aufwand aus der Ermittlung ausschlie&szlig;en. <\/p>\n<p>Das Formular zur Steuerung dieses Vorgangs sehen wir in Bild 1. Hier haben wir das Modul <b>mdlTest <\/b>ausgew&auml;hlt und anschlie&szlig;end auf die Schaltfl&auml;che <b>Typen einlesen <\/b>geklickt, um alle dort enthaltenen Typen zu ermitteln und in einem weiteren Listenfeld anzuzeigen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_06\/pic_495_001.png\" alt=\"Formular zum Steuern der Migration nach Late Binding\" width=\"574,6265\" height=\"737,238\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Formular zum Steuern der Migration nach Late Binding<\/span><\/b><\/p>\n<p>Wenn wir nun einen oder mehrere dieser Eintr&auml;ge markieren und auf die Schaltfl&auml;che Early Binding ersetzen klicken, werden die als Early Binding deklarierten Elemente samt der zur Initialisierung verwendeten Anweisungen in Late Binding umgewandelt &#8211; und zwar in allen Modulen, die im oberen Listenfeld markiert sind.<\/p>\n<p>Zus&auml;tzlich finden wir dort noch ein Kontrollk&auml;stchen namens <b>Ersetzte Zeilen als Kommentar behalten<\/b>. Damit k&ouml;nnen wir festlegen, dass die Early Binding-Anweisungen nicht gel&ouml;scht, sondern lediglich auskommentiert werden.<\/p>\n<p>Im Beispielmodul <b>mdlTest <\/b>haben wir einige mit Early Binding versehene Anweisungen untergebracht &#8211; und zwar in den unterschiedlichsten Auspr&auml;gungen:<\/p>\n<ul>\n<li>als einfache Deklarationszeilen, <\/li>\n<li>als Parameter von Prozeduren, <\/li>\n<li>als Deklaration in Prozeduren, <\/li>\n<li>als R&uuml;ckgabewert von Prozeduren und <\/li>\n<li>mit und ohne Zeilenumbr&uuml;che (siehe Bild 2).<\/li>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_06\/pic_495_002.png\" alt=\"Beispielanweisungen mit Early Binding\" width=\"649,627\" height=\"404,9859\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Beispielanweisungen mit Early Binding<\/span><\/b><\/p>\n<\/ul>\n<p>Nachdem wir die beiden Typen <b>ADODB.Connection <\/b>und <b>ADODB.Recordset <\/b>mit unserem Formular umgestellt haben, sieht der abgebildete Ausschnitt des Moduls wie in Bild 3 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_06\/pic_495_003.png\" alt=\"Beispielanweisungen mit Late Binding und auskommentierter Early Binding-Version\" width=\"649,627\" height=\"500,0595\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Beispielanweisungen mit Late Binding und auskommentierter Early Binding-Version<\/span><\/b><\/p>\n<h2>Beschreibung des Formulars<\/h2>\n<p>Im Formular finden wir in der Entwurfsansicht die folgenden Steuerelemente (siehe Bild 4):<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_06\/pic_495_004.png\" alt=\"Das Formular frmEarlyBindingToLateBinding in der Entwurfsansicht\" width=\"649,627\" height=\"836,5625\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Das Formular frmEarlyBindingToLateBinding in der Entwurfsansicht<\/span><\/b><\/p>\n<ul>\n<li><b>txtSucheModule<\/b>: Erlaubt das schnelle Filtern der im Listenfeld <b>lstModule <\/b>angezeigten Module. <\/li>\n<li>Schaltfl&auml;che <b>cmdAlleAuswahlen<\/b>: Markiert alle Eintr&auml;ge im Listenfeld <b>lstModules<\/b>.<\/li>\n<li>Listenfeld <b>lstModules<\/b>: Zeigt die gefundenen Module an, die den jeweiligen Typ enthalten.<\/li>\n<li>Schaltfl&auml;che <b>cmdTypenEinlesen<\/b>: Liest alle Typen der markierten Module ein und zeigt diese im Listenfeld <b>lstTypes <\/b>an.<\/li>\n<li>Textfeld <b>txtSucheTypen<\/b>: Filtert das Listenfeld <b>lstTypes <\/b>nach dem eingegebenen Suchbegriff.<\/li>\n<li>Schaltfl&auml;che <b>cmdAlleTypenAuswaehlen<\/b>: Markiert alle Eintr&auml;ge des Listenfeldes <b>lstTypes<\/b>.<\/li>\n<li>Listenfeld <b>lstTypes<\/b>: Zeigt alle gefundenen Typen in den markierten Modulen an.<\/li>\n<li>Schaltfl&auml;che <b>cmdEarlyBindingErsetzen<\/b>: Ersetzt f&uuml;r alle markierten Typen in den markierten Modulen Early Binding durch Late Binding.<\/li>\n<li>Kontrollk&auml;stchen <b>chkErsetzeZeilenAlsKommentarBehalten<\/b>: Gibt an, ob die ersetzten Zeilen auskommentiert oder einfach ersetzt werden sollen.<\/li>\n<\/ul>\n<h2>Ereignis beim Laden des Formulars<\/h2>\n<p>Beim Laden des Formulars wird das Ereignis aus Listing 1 ausgel&ouml;st. Es referenziert die aktuelle Datenbank mit der <b>CodeDb<\/b>-Funktion (dies ist eine Vorbereitung, um die L&ouml;sung als Add-In zu nutzen). Dann l&ouml;scht es die beiden Tabellen <b>tblModules <\/b>und <b>tblTypes<\/b>, in denen wir die ermittelten Daten speichern, um sie in den Listenfeldern anzuzeigen. <b>tblModules <\/b>enth&auml;lt das Prim&auml;rschl&uuml;sselfeld <b>ModulID <\/b>und das Textfeld <b>Modul<\/b>. Die Tabelle <b>tblTypes <\/b>enth&auml;lt die beiden Felder <b>TypeID <\/b>und <b>Type <\/b>sowie <b>Line <\/b>und <b>LineNumber<\/b>, um jeweils eine Zeile zu speichern, in der dieser Typ auftritt (diese wurden eher zu Testzwecken w&auml;hrend der Programmierung der L&ouml;sung genutzt).<\/p>\n<pre><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>objVBProject<span style=\"color:blue;\"> As <\/span>VBIDE.VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBComponent<span style=\"color:blue;\"> As <\/span>VBIDE.VBComponent\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CodeDb\r\n     db.Execute \"DELETE * FROM tblModules\", dbFailOnError\r\n     db.Execute \"DELETE * FROM tblTypes\", dbFailOnError\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> objVBProject = CurrentVBProject\r\n     For Each objVBComponent In objVBProject.VBComponents\r\n         db.Execute \"INSERT INTO tblModules(Modul) VALUES(''\" & objVBComponent.name & \"'')\", dbFailOnError\r\n     <span style=\"color:blue;\">Next<\/span> objVBComponent\r\n     \r\n     Me.lstModules.Requery\r\n     Me.lstTypes.Requery\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me.OpenArgs)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n         <span style=\"color:blue;\">Dim <\/span>strVBComponent<span style=\"color:blue;\"> As String<\/span>\r\n         strVBComponent = Me.OpenArgs\r\n         For i = 0 To Me.lstModules.ListCount - 1\r\n             <span style=\"color:blue;\">If <\/span>Me.lstModules.Column(1, i) = strVBComponent<span style=\"color:blue;\"> Then<\/span>\r\n                 Me.lstModules.Selected(i) = <span style=\"color:blue;\">True<\/span>\r\n                 <span style=\"color:blue;\">Call<\/span> cmdTypenEinlesen_Click\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Next<\/span> i\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 1: Ereignisprozedur, die beim Laden des Formulars ausgel&ouml;st wird<\/span><\/b><\/p>\n<p>Danach holen wir mit der Funktion <b>CurrentVBProject <\/b>einen Verweis auf das VBA-Projekt der aktuellen Datenbank. Dies ist notwendig, da beim Vorhandensein von Access-Add-Ins oder eingebundenen Bibliotheksdatenbanken sonst gegebenenfalls das falsche VBA-Projekt verwendet wird. Die Funktion <b>CurrentVBProject <\/b>sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CurrentVBProject()<span style=\"color:blue;\"> As <\/span>VBIDE.VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBProject<span style=\"color:blue;\"> As <\/span>VBIDE.VBProject\r\n     For Each objVBProject In VBE.VBProjects\r\n         <span style=\"color:blue;\">If <\/span>objVBProject.FileName = CurrentDb.Name<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> CurrentVBProject = objVBProject\r\n             <span style=\"color:blue;\">Exit Function<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> objVBProject\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Sie durchl&auml;uft alle vorhandenen VB-Projekte und pr&uuml;ft, ob der Pfad dem Pfad der aktuell ge&ouml;ffneten Access-Datenbank entspricht. Ist das der Fall, wird der Verweis auf dieses VB-Projekt zur&uuml;ckgegeben.<\/p>\n<p>F&uuml;r die Verwendung dieser und anderer nachfolgend genutzter Elemente, die auf den VBA-Editor und seine Module zugreifen, f&uuml;gen wir dem VBA-Projekt einen Verweis auf die Bibliothek <b>Microsoft Visual Basic for Applications Extensibility 5.3 Object Library <\/b>hinzu.<\/p>\n<p>Die Prozedur <b>Form_Load <\/b>durchl&auml;uft nun alle Elemente der Auflistung <b>VBComponents<\/b>, was den Modulen entspricht. F&uuml;r jedes Modul wird ein Eintrag in der Tabelle <b>tblModules <\/b>angelegt. Danach werden die beiden Listenfelder <b>lstModules <\/b>und <b>lstTypes <\/b>aktualisiert, damit sie den aktuellen Inhalt der beiden Tabellen <b>tblModules <\/b>und <b>tblTypes <\/b>anzeigen.<\/p>\n<p>Schlie&szlig;lich haben wir noch den Fall vorbereitet, dass das Formular direkt f&uuml;r ein bestimmtes Modul aufgerufen wird. Dann w&uuml;rden wir das Argument OpenArgs mit dem Namen des gew&uuml;nschten Moduls f&uuml;llen. Dies wird dann direkt im Listenfeld lstModules markiert.<\/p>\n<p>Der Aufruf des Formulars f&uuml;r diesen Fall sieht wie folgt aus:<\/p>\n<pre>DoCmd.OpenForm \"frmEarlyBindingToLateBinding\", _    OpenArgs:=\"mdlTest\"<\/pre>\n<h2>Ausw&auml;hlen aller Module<\/h2>\n<p>Um alle Module auszuw&auml;hlen, klicken wir auf die Schaltfl&auml;che <b>cmdAlleTypenAuswaehlen<\/b>. Diese durchl&auml;uft alle Elemente des Listenfeldes und stellt die Eigenschaft <b>Selected <\/b>f&uuml;r den jeweiligen Index auf <b>True <\/b>ein:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdAlleTypenAuswaehlen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngItem<span style=\"color:blue;\"> As Long<\/span>\r\n     For lngItem = 0 To Me.lstTypes.ListCount - 1\r\n         Me.lstTypes.Selected(lngItem) = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> lngItem\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Einlesen der Typen der markierten Module<\/h2>\n<p>Ein Klick auf die Schaltfl&auml;che <b>cmdTypenEinlesen <\/b>soll alle Typen der markierten Module ermitteln und in die Tabelle <b>tblTypes <\/b>schreiben.<\/p>\n<p>Dazu referenziert sie wieder die Datenbank mit dem Formular und leert die Tabelle <b>tblTypes<\/b>. Dann pr&uuml;ft sie, ob &uuml;berhaupt Eintr&auml;ge im Listenfeld <b>lstModules <\/b>markiert sind, und weist darauf hin, falls das nicht der Fall ist.<\/p>\n<p>Danach durchl&auml;uft sie alle markierten Eintr&auml;ge des Listenfeldes <b>lstModules <\/b>&uuml;ber die <b>ItemsSelected<\/b>-Auflistung und ermittelt mit <b>Column(1, var) <\/b>den Namen des jeweiligen Moduls. Innerhalb der Schleife ruft sie f&uuml;r jedes dieser Elemente die Prozedur <b>TypesToTable<\/b> auf und &uuml;bergibt dieser den Namen des Moduls. Schlie&szlig;lich aktualisiert sie die Liste der Typen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdTypenEinlesen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>var<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strModule<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     \r\n     <span style=\"color:blue;\">Set<\/span> db = CodeDb\r\n     DoCmd.Hourglass <span style=\"color:blue;\">True<\/span>\r\n     db.Execute \"DELETE * FROM tblTypes\", dbFailOnError\r\n     \r\n     <span style=\"color:blue;\">If <\/span>Me.lstModules.ItemsSelected.Count = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Markiere die zu untersuchenden Module.\", _\r\n             vbOKOnly + vbExclamation, \"Kein Modul markiert\"\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     For Each var In Me.lstModules.ItemsSelected\r\n         strModule = Me.lstModules.Column(1, var)\r\n         <span style=\"color:blue;\">Call<\/span> TypesToTable(strModule)\r\n     <span style=\"color:blue;\">Next<\/span> var\r\n     Me.lstTypes.Requery\r\n     DoCmd.Hourglass <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Auslesen der Typen eines Moduls<\/h2>\n<p>Die Prozedur <b>TypesToTable <\/b>referenziert wieder die Code-Datenbank und das aktuelle VBA-Projekt (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TypesToTable(strModule<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>objVBProject<span style=\"color:blue;\"> As <\/span>VBIDE.VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBComponent<span style=\"color:blue;\"> As <\/span>VBIDE.VBComponent\r\n     <span style=\"color:blue;\">Dim <\/span>objCodeModule<span style=\"color:blue;\"> As <\/span>VBIDE.CodeModule\r\n     <span style=\"color:blue;\">Dim <\/span>strLine<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strProc<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngProcType<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngProcBodyLine<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strLineOriginal<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngLine<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngProcline<span style=\"color:blue;\"> As Long<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CodeDb\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> objVBProject = CurrentVBProject\r\n     <span style=\"color:blue;\">Set<\/span> objVBComponent = objVBProject.VBComponents(strModule)\r\n     <span style=\"color:blue;\">Set<\/span> objCodeModule = objVBComponent.CodeModule\r\n     For lngLine = 1 To objCodeModule.CountOfLines\r\n         strLineOriginal = objCodeModule.Lines(lngLine, 1)\r\n         strLine = <span style=\"color:blue;\">Trim<\/span>(strLineOriginal)\r\n         strLine = KommentarAbschneiden(strLine)\r\n         strLine = TextAusLiteralenEntfernen(strLine)\r\n         ...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Einlesen der Typen (Teil 1)<\/span><\/b><\/p>\n<p>Danach f&uuml;llt sie die Variable <b>objVBComponent <\/b>mit einem Verweis auf das &uuml;bergebene Modul und holt einen weiteren Verweis auf das enthaltene <b>CodeModule<\/b>-Objekt, das in <b>objCodeModule <\/b>landet.<\/p>\n<p>Dann durchl&auml;uft sie in einer <b>For&#8230;Next<\/b>-Schleife alle Codezeilen, wobei die letzte Zeile mit der Eigenschaft <b>CountOfLines <\/b>ermittelt wird.<\/p>\n<p>Hier speichert sie die Originalzeile in <b>strLineOriginal <\/b>und in <b>strLine <\/b>die um f&uuml;hrende und folgende Leerzeichen bereinigte Version der Zeile.<\/p>\n<p>F&uuml;r diese ruft sie nun die Funktion <b>KommentarAbschneiden <\/b>auf, die wir ebenfalls im Modul finden und die alle am Ende der Zeile befindlichen Kommentare aus <b>strLine <\/b>entfernt.<\/p>\n<p>Eine weitere Funktion namens <b>TextAusLiteralenEntfernen <\/b>leert eventuell in Anf&uuml;hrungszeichen vorhandene Texte. Aus der Zeile <b>strText = &#8220;Beispieltext&#8221; <\/b>wird dann zum Beispiel <b>strText = &#8220;&#8221;<\/b>.<\/p>\n<p>Dies dient der Vereinfachung, damit eventuell in Literalen enthaltene Bezeichnungen der gesuchten Typen nicht ber&uuml;cksichtigt werden. Die Ersetzung schl&auml;gt sich nicht auf die sp&auml;teren &Auml;nderungen nieder.<\/p>\n<p>Danach steigen wir in eine <b>Select Case<\/b>-Bedingung ein, die verschiedene Aspekte &uuml;berpr&uuml;ft (siehe Listing 3). Der erste <b>Case<\/b>-Zweig pr&uuml;ft, ob die Anweisung der aktuellen Zeile mit <b>Const<\/b>, <b>Public Const <\/b>oder <b>Private Const <\/b>beginnt. Solche Zeilen sollen nicht ber&uuml;cksichtigt werden, da Konstanten keine der f&uuml;r uns interessanten Typen aufnehmen k&ouml;nnen.<\/p>\n<pre>         ...\r\n         Select Case <span style=\"color:blue;\">True<\/span>\r\n             <span style=\"color:blue;\">Case <\/span><span style=\"color:blue;\">Left<\/span>(strLine, 5) = \"Const\", <span style=\"color:blue;\">Left<\/span>(strLine, 12) = \"Public Const\", <span style=\"color:blue;\">Left<\/span>(strLine, 13) = \"Private Const\"\r\n             <span style=\"color:blue;\">Case Else<\/span>\r\n                 lngProcline = lngLine\r\n                 <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Right<\/span>(strLine, 1) = \"_\"\r\n                     lngProcline = lngProcline + 1\r\n                     strLine = <span style=\"color:blue;\">Left<\/span>(strLine, <span style=\"color:blue;\">Len<\/span>(strLine) - 1)\r\n                     strLine = strLine & <span style=\"color:blue;\">Trim<\/span>(objCodeModule.Lines(lngProcline, 1))\r\n                 <span style=\"color:blue;\">Loop<\/span>\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">InStr<\/span>(1, strLine, \"<span style=\"color:blue;\"> As <\/span>\") = 0<span style=\"color:blue;\"> Then<\/span>\r\n                     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strLine) = 0<span style=\"color:blue;\"> Then<\/span>\r\n                         strProc = \"\"\r\n                         strProc = objCodeModule.ProcOfLine(lngLine, lngProcType)\r\n                         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strProc) = 0<span style=\"color:blue;\"> Then<\/span>\r\n                             lngProcBodyLine = objCodeModule.ProcBodyLine(strProc, lngProcType)\r\n                         <span style=\"color:blue;\">Else<\/span>\r\n                             If <span style=\"color:blue;\">Split<\/span>(strLine, \" \")(0) = \"Event\" Or <span style=\"color:blue;\">Split<\/span>(strLine, \" \")(1) = \"Event\" _\r\n                                     Or <span style=\"color:blue;\">Split<\/span>(strLine, \" \")(0) = \"Declare\" Or <span style=\"color:blue;\">Split<\/span>(strLine, \" \")(1) = \"Declare\" Then\r\n                                 lngProcBodyLine = lngLine\r\n                             <span style=\"color:blue;\">End If<\/span>\r\n                         <span style=\"color:blue;\">End If<\/span>\r\n                         <span style=\"color:blue;\">If <\/span>lngProcBodyLine = lngLine<span style=\"color:blue;\"> Then<\/span>\r\n                             <span style=\"color:blue;\">Call<\/span> ProzedurparameterVerarbeiten(db, strLine, strLineOriginal, lngLine)\r\n                             <span style=\"color:blue;\">Call<\/span> RueckgabewertVerarbeiten(db, strLine, strLineOriginal, lngLine)\r\n                         <span style=\"color:blue;\">Else<\/span>\r\n                             Select Case <span style=\"color:blue;\">True<\/span>\r\n                                 <span style=\"color:blue;\">Case <\/span><span style=\"color:blue;\">Left<\/span>(strLine, 3) = \"Dim\", <span style=\"color:blue;\">Left<\/span>(strLine, 6) = \"Public\", <span style=\"color:blue;\">Left<\/span>(strLine, 7) = \"Private\"\r\n                                     <span style=\"color:blue;\">Call<\/span> DeklarationenVerarbeiten(db, strLine, strLineOriginal, lngLine)\r\n                             <span style=\"color:blue;\">End Select<\/span>\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 If<\/span>\r\n                 lngLine = lngProcline\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n         DoEvents\r\n     <span style=\"color:blue;\">Next<\/span> lngLine\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Einlesen der Typen (Teil 2)<\/span><\/b><\/p>\n<p>Der zweite Case-Zweig bearbeitet alle &uuml;brigen Zeilen, wo wir als Erstes eventuell auf mehrere Zeilen aufgeteilte Anweisungen in eine Zeile schreiben. Aus <\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestParameterCrLf( _\r\n     rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset)<\/pre>\n<p>wird dann beispielsweise<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestParameterCrLf(rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset)<\/pre>\n<p>Dazu holen wir uns als Erstes die Nummer der aktuellen Zeile und speichern diese in <b>lngProcLine<\/b>. Solange die Zeile mit dem Unterstrich endet und die Anweisung somit in der n&auml;chsten Zeile fortgesetzt wird, erh&ouml;hen wir <b>lngProcLine <\/b>um den Wert <b>1 <\/b>und lesen den Teil der Zeile vor dem Unterstrich in <b>strLine <\/b>ein. Aus <\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestParameterCrLf( _<\/pre>\n<p>wird somit die folgende Zeile:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestParameterCrLf(<\/pre>\n<p>Dann f&uuml;gen wir den Inhalt der folgenden Zeile zu <b>strLine <\/b>hinzu. Diesen Vorgang wiederholen wir, bis die letzte Zeile der Anweisung erreicht ist. Sp&auml;ter stellen wir lngLine auf <b>lngProcLine <\/b>ein, damit die Zeilenfortsetzungen nicht erneut eingelesen werden.<\/p>\n<p>Nun untersuchen wir weitere Aspekte. Zun&auml;chst pr&uuml;fen wir, ob die Zeile das Schl&uuml;sselwort <b>As <\/b>enth&auml;lt. Nur in diesem Fall kann &uuml;berhaupt eine Deklaration f&uuml;r einen Typ vorliegen.<\/p>\n<p>Als N&auml;chstes pr&uuml;fen wir, ob es sich bei der aktuellen Zeile um eine einfache Deklaration oder um einen Prozedurkopf handelt. Dazu ermitteln wir mit der Funktion <b>ProcOfLine<\/b>, ob sich die aktuelle Zeile innerhalb einer Prozedur befindet. In diesem Fall liefert die Funktion den Namen der Prozedur zur&uuml;ck, den wir in <b>strProc <\/b>speichern. Ist <b>strProc <\/b>nicht leer, befindet sich die Zeile innerhalb einer Prozedur. Um herauszufinden, ob es sich bei der Zeile um den Prozedurkopf handelt, ermitteln wir mit <b>ProcBodyLine <\/b>die Nummer der Zeile, in der sich der Prozedurkopf der aktuellen Prozedur befindet. Ist <b>strProc <\/b>leer, handelt es sich um eine Prozedurkopf-&auml;hnliche Anweisung, etwa ein Event oder eine API-Deklaration. Auch diese wollen wir wie einen Prozedurkopf behandeln und speichern auch hier die Zeilennummer in <b>lngProc<\/b>.<\/p>\n<p>Wenn die aktuelle Zeile aus <b>lngLine <\/b>nun dem Wert aus <b>lngProc <\/b>entspricht, handelt es sich um einen Prozedurkopf oder eine <b>Event<\/b>&#8211; oder <b>Declare<\/b>-Anweisung.<\/p>\n<p>In diesem Fall rufen wir eine weitere Prozedur namens <b>ProzedurparameterVerarbeiten <\/b>auf und &uuml;bergeben die relevanten Parameter. Diese Prozedur beschreiben wir im Anschluss. Au&szlig;erdem rufen wir noch die Prozedur <b>RueckgabewertVerarbeiten <\/b>auf, denn auch die R&uuml;ckgabewerte einer Prozedur k&ouml;nnen Typen enthalten, die wir umwandeln wollen.<\/p>\n<p>Ist es keine Prozedurkopfzeile, handelt es sich um eine Deklarationszeile. Dies pr&uuml;fen wir noch, indem wir untersuchen, ob die ersten Zeichen der Anweisung <b>Dim<\/b>, <b>Public <\/b>oder <b>Private <\/b>lauten. In diesem Fall rufen wir die Prozedur <b>DeklarationenVerarbeiten <\/b>auf.<\/p>\n<p>Auf diese Weise haben wir nun alle Anweisungen auf Typen untersucht. In den aufgerufenen Prozeduren werden die Typen in die Tabelle <b>tblTypes <\/b>eingetragen.<\/p>\n<h2>Deklarationszeilen analysieren<\/h2>\n<p>Wir schauen uns diese Verarbeitung beispielhaft an der Prozedur <b>DeklarationenVerarbeiten<\/b> an (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DeklarationenVerarbeiten(db<span style=\"color:blue;\"> As <\/span>DAO.Database, strLine<span style=\"color:blue;\"> As String<\/span>, strLineOriginal<span style=\"color:blue;\"> As String<\/span>, _\r\n         lngLine<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intDeclaration<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDeclarations()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDeclaration<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngStartAs<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strLineBehindAs<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strType<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     strDeclarations = <span style=\"color:blue;\">Split<\/span>(strLine, \",\")\r\n     For intDeclaration = <span style=\"color:blue;\">LBound<\/span>(strDeclarations) To <span style=\"color:blue;\">UBound<\/span>(strDeclarations)\r\n         strDeclaration = strDeclarations(intDeclaration)\r\n         \r\n         strDeclaration = <span style=\"color:blue;\">Replace<\/span>(strDeclaration, \" <span style=\"color:blue;\">New<\/span> \", \" \")\r\n         lngStartAs = <span style=\"color:blue;\">InStr<\/span>(strDeclaration, \"<span style=\"color:blue;\"> As <\/span>\")\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngStartAs = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strLineBehindAs = <span style=\"color:blue;\">Mid<\/span>(strDeclaration, <span style=\"color:blue;\">InStr<\/span>(1, strDeclaration, \"<span style=\"color:blue;\"> As <\/span>\") + 4)\r\n             strType = <span style=\"color:blue;\">Split<\/span>(strLineBehindAs, \" \")(0)\r\n             <span style=\"color:blue;\">Call<\/span> SaveTypesToTable(db, strType, strLineOriginal, lngLine)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> intDeclaration\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Verarbeiten der Deklarationszeilen<\/span><\/b><\/p>\n<p>Diese splittet die Deklarationszeile zun&auml;chst am Komma auf und schreibt die einzelnen Elemente in ein Array. Dies ber&uuml;cksichtigt Deklarationen wie die folgende:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset, cnn<span style=\"color:blue;\"> As <\/span>ADODB.Connection<\/pre>\n<p>Das Array durchlaufen wir in einer <b>For&#8230;Next<\/b>-Schleife. Hier schreiben wir zun&auml;chst das aktuelle Element in die Variable <b>strDeclaration<\/b>, zum Beispiel <b>Dim rst As ADODB.Recordset<\/b>. Wir pr&uuml;fen, ob das Element das Schl&uuml;sselwort <b>New <\/b>enth&auml;lt und ersetzen dieses durch eine leere Zeichenkette.<\/p>\n<p>Dann ermitteln wir die Position des Schl&uuml;sselwortes <b>As<\/b>. Wenn diese nicht <b>0 <\/b>ist, lesen wir den Teil hinter dem Schl&uuml;sselwort As ein, zum Beispiel <b>ADODB.Recordset<\/b>, und tragen diesen Typ in <b>strLineBehindAs <\/b>ein. Dieser kann wiederum aus mehreren Elementen bestehen, wobei uns nur das erste Element interessiert. Dieses landet in der Variablen <b>strType<\/b>.<\/p>\n<p>Mit der Prozedur <b>SaveTypesToTable <\/b>tragen wir diesen Typ in die Tabelle <b>tblTypes <\/b>ein und bearbeiten anschlie&szlig;end eventuell weitere in dieser Zeile enthaltene Deklarationen.<\/p>\n<h2>Schreiben der Typen in die Tabelle tblTypes<\/h2>\n<p>Die Prozedur <b>SaveTypesToTable <\/b>untersucht, ob es sich bei dem Typ um einen der einfachen Datentypen wie <b>Boolean<\/b>, <b>String<\/b>, <b>Long <\/b>und so weiter handelt.<\/p>\n<p>Diese werden nicht in der Tabelle gespeichert. Nur die &uuml;brigen Typen landen in der Tabelle <b>tblTypes<\/b> (siehe Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>SaveTypesToTable(db<span style=\"color:blue;\"> As <\/span>DAO.Database, strType<span style=\"color:blue;\"> As String<\/span>, strLine<span style=\"color:blue;\"> As String<\/span>, lngStartline<span style=\"color:blue;\"> As Long<\/span>)\r\n     Select Case strType\r\n         <span style=\"color:blue;\">Case <\/span>\"Boolean\", \"Byte\", \"Currency\", \"Date\", \"Decimal\", \"Object\", \"Variant\", \"String\", \"Long\", \"Double\", _\r\n             \"Single\", \"Integer\", \"LongPtr\", \"Byte()\", \"Any\", \"Collection\", \"LongLong\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n             db.Execute \"INSERT INTO tblTypes(Type, Line, LineNumber) VALUES(''\" & strType & \"'', ''\" & strLine & \"'', \" _\r\n                 & lngStartline & \")\", dbFailOnError\r\n             <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Speichern der Typen in der Tabelle tblTypes<\/span><\/b><\/p>\n<h2>Schreiben der Typen aus Prozedurparametern und R&uuml;ckgabewerten<\/h2>\n<p>Die beiden Prozeduren <b>ProzedurparameterVerarbeiten <\/b>und <b>RueckgabewertVerarbeiten <\/b>arbeiten &auml;hnlich wie DeklarationenVerarbeiten, sind aber etwas aufwendiger. Daher wollen wir diese hier nicht ausf&uuml;hrlich beschreiben, sondern nur zusammenfassen:<\/p>\n<p>Die Prozedur <b>ProzedurparameterVerarbeiten <\/b>untersucht die Liste der Parameter von Prozedurk&ouml;pfen und <b>Declare<\/b>&#8211; und <b>Event<\/b>-Anweisungen. Dabei durchl&auml;uft sie wiederum alle enthaltenen Elemente und schreibt die entsprechenden Typen in die Tabelle <b>tblTypes<\/b>. Die Prozedur <b>RueckgabewertVerarbeiten<\/b> erledigt dies f&uuml;r die R&uuml;ckgabewerte von Funktionen.<\/p>\n<h2>Typen von Early Binding in Late Binding umwandeln<\/h2>\n<p>Um den Umwandlungsprozess zu starten, klicken wir die Schaltfl&auml;che <b>cmdEarlyBindingErsetzen <\/b>an. Diese l&ouml;st die Prozedur aus Listing 6 aus.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEarlyBindingErsetzen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>varModule<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>varType<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strModule<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strType<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bolErsetzteZeilenAlsKommentarBehalten<span style=\"color:blue;\"> As Boolean<\/span>\r\n     \r\n     DoCmd.Hourglass <span style=\"color:blue;\">True<\/span>\r\n     \r\n     bolErsetzteZeilenAlsKommentarBehalten = Me.chkErsetzteZeilenAlsKommentarBehalten\r\n     \r\n     <span style=\"color:blue;\">If <\/span>Me.lstTypes.ItemsSelected.Count = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Markiere die zu ersetzenden Typen.\", vbOKOnly + vbExclamation, \"Keine Typen markiert\"\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     For Each varModule In Me.lstModules.ItemsSelected\r\n         strModule = Me.lstModules.Column(1, varModule)\r\n         For varType = Me.lstTypes.ListCount - 1 To 0 Step -1\r\n             <span style=\"color:blue;\">If <\/span>Me.lstTypes.Selected(varType) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                 strType = Me.lstTypes.Column(1, varType)\r\n                 <span style=\"color:blue;\">Call<\/span> TypeErsetzen(strModule, strType, bolErsetzteZeilenAlsKommentarBehalten)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Next<\/span> varType\r\n     <span style=\"color:blue;\">Next<\/span> varModule\r\n     \r\n     DoCmd.Hourglass <span style=\"color:blue;\">False<\/span>\r\n     \r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Start der Umwandlung<\/span><\/b><\/p>\n<p>Hier tragen wir den Wert des Kontrollk&auml;stchens <b>chkErsetzteZeilenAlsKommentarBehalten <\/b>in die Variable <b>bolErsetzteZeilenAlsKommentarBehalten <\/b>ein.<\/p>\n<p>Dann pr&uuml;fen wir, ob &uuml;berhaupt Typen f&uuml;r die Umwandlung markiert sind, und geben gegebenenfalls eine entsprechende Meldung aus.<\/p>\n<p>Danach durchlaufen wir alle markierten Module aus <b>lstModules <\/b>und schreiben deren Namen in <b>strModule<\/b>. In einer inneren Schleife durchlaufen wir nun alle markierten Eintr&auml;ge des Listenfeldes <b>lstTypes<\/b> in umgekehrter Reihenfolge und rufen f&uuml;r jede Kombination aus Modul und Typ die Prozedur <b>TypeErsetzen <\/b>auf.<\/p>\n<h2>Prozedur zum Ersetzen von Early Binding durch Late Binding<\/h2>\n<p>Die Hauptarbeit erledigt die Prozedur <b>TypeErsetzen<\/b>, der wir den Namen des Moduls, den Typ und den Wert aus <b>bolErsetzteZeilenAlsKommentarBehalten <\/b>&uuml;bergeben (siehe Listing 7).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TypeErsetzen(strModule<span style=\"color:blue;\"> As String<\/span>, strType<span style=\"color:blue;\"> As String<\/span>, bolErsetzteZeilenAlsKommentarBehalten<span style=\"color:blue;\"> As Boolean<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>objVBProject<span style=\"color:blue;\"> As <\/span>VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBComponent<span style=\"color:blue;\"> As <\/span>VBComponent\r\n     <span style=\"color:blue;\">Dim <\/span>objCodeModule<span style=\"color:blue;\"> As <\/span>CodeModule\r\n     <span style=\"color:blue;\">Dim <\/span>lngLine<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngCountOfLines<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngProcline<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strLine<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strLineOld<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strWork<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bolHasContinuation<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bolReplaced<span style=\"color:blue;\"> As Boolean<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> objVBProject = CurrentVBProject\r\n     <span style=\"color:blue;\">Set<\/span> objVBComponent = objVBProject.VBComponents(strModule)\r\n     <span style=\"color:blue;\">Set<\/span> objCodeModule = objVBComponent.CodeModule\r\n     lngCountOfLines = objCodeModule.CountOfLines\r\n     <span style=\"color:blue;\">Do While<\/span> lngLine &lt; lngCountOfLines\r\n         lngLine = lngLine + 1\r\n         bolReplaced = <span style=\"color:blue;\">False<\/span>\r\n         bolHasContinuation = <span style=\"color:blue;\">False<\/span>\r\n         lngProcline = 0\r\n         strLine = objCodeModule.Lines(lngLine, 1)\r\n         <span style=\"color:blue;\">If <\/span>Left$(Trim$(strLine), 1) = \"''\"<span style=\"color:blue;\"> Then<\/span>\r\n             GoTo NextLine\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         strLineOld = strLine\r\n         strWork = strLine\r\n         <span style=\"color:blue;\">If <\/span>Right$(Trim$(strWork), 1) = \"_\"<span style=\"color:blue;\"> Then<\/span>\r\n             bolHasContinuation = <span style=\"color:blue;\">True<\/span>\r\n             lngProcline = lngLine\r\n             <span style=\"color:blue;\">Do While<\/span> Right$(Trim$(strWork), 1) = \"_\"\r\n                 lngProcline = lngProcline + 1\r\n                 strWork = Left$(strWork, <span style=\"color:blue;\">Len<\/span>(strWork) - 1)\r\n                 strWork = strWork & Trim$(objCodeModule.Lines(lngProcline, 1))\r\n             <span style=\"color:blue;\">Loop<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         ...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Hauptprozedur zum Umwandeln (Teil 1)<\/span><\/b><\/p>\n<p>Hier referenzieren wir wieder das aktuelle VBA-Projekt und holen uns Verweise auf das zu bearbeitende <b>VBComponent<\/b>&#8211; und <b>CodeModule<\/b>-Objekt.<\/p>\n<p>Au&szlig;erdem ermitteln wir die Anzahl der zu untersuchenden Zeilen mit <b>CountOfLines <\/b>und speichern diesen Wert in <b>lngCountOfLines<\/b>.<\/p>\n<p>Anschlie&szlig;end durchlaufen wir eine Schleife, die so lange l&auml;uft, bis die aktuelle Zeile aus <b>lngLine <\/b>nicht mehr kleiner als <b>lngCountOfLines <\/b>ist. Warum keine <b>For&#8230;Next<\/b>-Schleife? Weil sich die Anzahl der Zeilen ver&auml;ndern kann, weil wir beispielsweise Zeilen f&uuml;r die auskommentierten Early Binding-Zeilen unterbringen m&uuml;ssen.<\/p>\n<p>Hier springen wir zur n&auml;chsten Zeile und setzen die Variablen <b>bolReplaced <\/b>und <b>bolHasContinuation <\/b>auf <b>False <\/b>sowie <b>lngProcLine <\/b>auf <b>0<\/b> ein.<\/p>\n<p>Dann lesen wir die aktuelle Zeile in <b>strLine <\/b>ein. Handelt es sich um eine Kommentarzeile, springen wir zur Marke <b>NextLine <\/b>und wenden uns in der Schleife gleich der n&auml;chsten Zeile zu. Anderenfalls speichern wir die aktuelle Zeile in <b>strOldLine <\/b>und in <b>strWork<\/b>.<\/p>\n<p>Nun ziehen wir Anweisungen, die durch den Unterstrich auf mehrere Zeilen aufgeteilt sind, in einer einzigen Zeile zusammen und speichern das Ergebnis in der Variablen <b>strWork<\/b>. Au&szlig;erdem erh&ouml;hen wir <b>lngProcline <\/b>f&uuml;r jede dieser Zeilen um den Wert <b>1<\/b>, damit wir die Fortsetzungszeilen sp&auml;ter &uuml;berspringen k&ouml;nnen.<\/p>\n<p>Damit kommen wir zu dem Teil, der in Listing 8 abgebildet ist. Hier pr&uuml;fen wir mit der Funktion <b>WouldReplaceType<\/b>, ob die Zeile &uuml;berhaupt den aktuell zu ersetzenden Typ enth&auml;lt. Falls ja, speichern wir <b>strWork <\/b>in <b>strLineOld <\/b>und ersetzen die umgebrochene Zeile im Modul tats&auml;chlich durch die zusammengezogene Zeile.<\/p>\n<pre>         ...\r\n         <span style=\"color:blue;\">If <\/span>WouldReplaceType(strWork, strType)<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>bolHasContinuation<span style=\"color:blue;\"> Then<\/span>\r\n                 strLineOld = strWork\r\n                 objCodeModule.ReplaceLine lngLine, strWork\r\n                 objCodeModule.DeleteLines lngLine + 1, lngProcline - lngLine\r\n                 lngCountOfLines = objCodeModule.CountOfLines\r\n                 strLine = strWork\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 strLine = strWork\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             strLine = ReplaceTypeInLine(strLine, strType, bolReplaced)\r\n             <span style=\"color:blue;\">If <\/span>bolReplaced<span style=\"color:blue;\"> Then<\/span>\r\n                 objCodeModule.ReplaceLine lngLine, strLine\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, <span style=\"color:blue;\">vbCrLf<\/span>) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n                     lngLine = lngLine + 1\r\n                     lngCountOfLines = objCodeModule.CountOfLines\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>bolErsetzteZeilenAlsKommentarBehalten<span style=\"color:blue;\"> Then<\/span>\r\n                     objCodeModule.InsertLines lngLine, \"''\" & strLineOld\r\n                     lngLine = lngLine + 1\r\n                     lngCountOfLines = objCodeModule.CountOfLines\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 If<\/span>\r\nNextLine:\r\n         lngCountOfLines = objCodeModule.CountOfLines\r\n         DoEvents\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 8: Hauptprozedur zum Umwandeln (Teil 2)<\/span><\/b><\/p>\n<p>Au&szlig;erdem l&ouml;schen wir die Zeilenfortsetzungen mit der <b>Delete<\/b>-Methode im Code, wobei wir die Startzeile und die Anzahl der zu l&ouml;schenden Zeilen &uuml;bergeben.<\/p>\n<p>Au&szlig;erdem aktualisieren wir nun die Anzahl der zu bearbeitenden Zeilen in <b>lngCountOfLines <\/b>mit der aktuellen Zeilenanzahl, da ja Zeilen gel&ouml;scht wurden. Der aktuelle Zwischenstand aus <b>strWork <\/b>landet in <b>strLine <\/b>&#8211; sowohl f&uuml;r eine zusammengezogene Anweisung als auch f&uuml;r eine einzeilige Anweisung.<\/p>\n<p>Schlie&szlig;lich folgt die eigentliche Ersetzung, die in der Funktion <b>ReplaceTypeInLine <\/b>durchgef&uuml;hrt wird.<\/p>\n<p>Dieser &uuml;bergeben wir die Zeilennummer, den Typ sowie den Wert der Variablen <b>bolReplaced<\/b>.<\/p>\n<p>Wenn <b>bolReplaced <\/b>anschlie&szlig;end den Wert <b>True <\/b>aufweist, wurden Ersetzungen vorgenommen und wir ersetzen die ersetzte Zeile mit der Nummer <b>lngLine <\/b>durch die in <b>strLine <\/b>geschriebene neue Version der Zeile. Hier kann es vorkommen, dass zus&auml;tzliche Zeilen entstanden sind. Die Anzahl der Zeilen ermitteln wir &uuml;ber die Anzahl der Zeilenumbr&uuml;che in der Zeile (<b>vbCrLf<\/b>) und springen in <b>lngLine <\/b>um die entsprechende Anzahl weiter. Au&szlig;erdem passen wir wieder <b>lngCountOfLines <\/b>an.<\/p>\n<p>Ist die Option <b>bolErsetzteZeilenAlsKommentarBehalten <\/b>gesetzt, f&uuml;gen wir die urspr&uuml;ngliche Anweisung noch als Kommentar &uuml;ber der neuen Version der Zeile hinzu und passen wieder <b>lngLine <\/b>und <b>lngCountOfLines <\/b>an.<\/p>\n<p>Auf diese Weise durchlaufen wir nun alle Zeilen und nehmen die erforderlichen &Auml;nderungen vor.<\/p>\n<h2>Pr&uuml;fen, ob eine Zeile ersetzt werden muss<\/h2>\n<p>In der Funktion <b>WouldReplaceType <\/b>pr&uuml;fen wir, ob eine Zeile &uuml;berhaupt einen zu ersetzenden Typen enth&auml;lt (siehe Listing 9).<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>WouldReplaceType(ByVal strLine<span style=\"color:blue;\"> As String<\/span>, ByVal strType<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \"<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> \" & strType, vbTextCompare) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         WouldReplaceType = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \" = <span style=\"color:blue;\">New<\/span> \" & strType, vbTextCompare) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         WouldReplaceType = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \"<span style=\"color:blue;\"> As <\/span>\" & strType, vbTextCompare) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         WouldReplaceType = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Function<\/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 9: Pr&uuml;fen, ob in einer Zeile &Auml;nderungen vorgenommen werden m&uuml;ssen<\/span><\/b><\/p>\n<p>Die Funktion pr&uuml;ft, ob einer der Ausdr&uuml;cke <b>As New [Type]<\/b>, <b>= New [Type] <\/b>oder <b>As [Type] <\/b>enthalten ist und gibt in diesem Fall den Wert <b>True <\/b>als Funktionsergebnis zur&uuml;ck.<\/p>\n<p>Dazu nutzen wir jeweils die <b>Instr<\/b>-Funktion mit dem entsprechenden Ausdruck als Suchbegriff.<\/p>\n<h2>Funktion zum Ersetzen von Typen in Anweisungen<\/h2>\n<p>Die eigentliche Ersetzung wird in der Funktion <b>ReplaceTypeInLine <\/b>durchgef&uuml;hrt (siehe Listing 10). Die Prozedur nimmt die anzupassende Zeile, den Typ sowie den R&uuml;ckgabeparameter <b>bolReplaced <\/b>entgegen. Dieser wird zun&auml;chst auf <b>False <\/b>eingestellt.<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>ReplaceTypeInLine(ByVal strLine<span style=\"color:blue;\"> As String<\/span>, ByVal strType<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByRef bolReplaced<span style=\"color:blue;\"> As Boolean<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngStart<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngSpaces<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strVariable<span style=\"color:blue;\"> As String<\/span>\r\n     bolReplaced = <span style=\"color:blue;\">False<\/span>\r\n     Select Case <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Case <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \"<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> \" & strType, vbTextCompare) &gt; 0\r\n             <span style=\"color:blue;\">If <\/span>Right$(Trim$(strLine), <span style=\"color:blue;\">Len<\/span>(strType)) = strType<span style=\"color:blue;\"> Then<\/span>\r\n                 lngSpaces = <span style=\"color:blue;\">Len<\/span>(strLine) - <span style=\"color:blue;\">Len<\/span>(LTrim$(strLine))\r\n                 strVariable = Trim$(Replace$(strLine, strType, \"\", , , vbTextCompare))\r\n                 strVariable = Trim$(Replace$(strVariable, \"<span style=\"color:blue;\"> As <\/span>New\", \"\", , , vbTextCompare))\r\n                 strVariable = Trim$(Mid$(strVariable, <span style=\"color:blue;\">InStrRev<\/span>(strVariable, \" \")))\r\n                 strLine = Replace$(strLine, \"<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> \" & strType, \"<span style=\"color:blue;\"> As Object<\/span>\", , , vbTextCompare)\r\n                 strLine = strLine & <span style=\"color:blue;\">vbCrLf<\/span> & Space$(lngSpaces) & _\r\n                           \"<span style=\"color:blue;\">Set<\/span> \" & strVariable & \" = CreateObject(\"\"\" & strType & \"\"\")\"\r\n                 bolReplaced = <span style=\"color:blue;\">True<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Case <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \" = <span style=\"color:blue;\">New<\/span> \" & strType, vbTextCompare) &gt; 0\r\n             strLine = Replace$(strLine, \" = <span style=\"color:blue;\">New<\/span> \" & strType, _\r\n                                \" = CreateObject(\"\"\" & strType & \"\"\")\", , , vbTextCompare)\r\n             bolReplaced = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Case <\/span><span style=\"color:blue;\">InStr<\/span>(1, strLine, \"<span style=\"color:blue;\"> As <\/span>\" & strType, vbTextCompare) &gt; 0\r\n             lngStart = <span style=\"color:blue;\">InStr<\/span>(1, strLine, strType, vbTextCompare)\r\n             <span style=\"color:blue;\">Do While<\/span> lngStart &gt; 0\r\n                 Select Case <span style=\"color:blue;\">True<\/span>\r\n                     <span style=\"color:blue;\">Case <\/span>Right$(Trim$(strLine), <span style=\"color:blue;\">Len<\/span>(strType)) = strType\r\n                         strLine = Left$(strLine, <span style=\"color:blue;\">Len<\/span>(strLine) - <span style=\"color:blue;\">Len<\/span>(strType)) & \"Object\"\r\n                         bolReplaced = <span style=\"color:blue;\">True<\/span>\r\n                     <span style=\"color:blue;\">Case <\/span>Mid$(strLine, lngStart + <span style=\"color:blue;\">Len<\/span>(strType), 1) = \",\" _\r\n                       Or Mid$(strLine, lngStart + <span style=\"color:blue;\">Len<\/span>(strType), 1) = \")\" _\r\n                       Or Mid$(strLine, lngStart + <span style=\"color:blue;\">Len<\/span>(strType) + 1, 1) = \"=\"\r\n                         strLine = Left$(strLine, lngStart - 1) & \"Object\" & Mid$(strLine, lngStart + <span style=\"color:blue;\">Len<\/span>(strType))\r\n                         bolReplaced = <span style=\"color:blue;\">True<\/span>\r\n                 <span style=\"color:blue;\">End Select<\/span>\r\n                 lngStart = <span style=\"color:blue;\">InStr<\/span>(lngStart + 1, strLine, strType, vbTextCompare)\r\n             <span style=\"color:blue;\">Loop<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     ReplaceTypeInLine = strLine\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Durchf&uuml;hrung der &Auml;nderungen am Code<\/span><\/b><\/p>\n<p>Die Funktion pr&uuml;ft in einer <b>Select Case<\/b>-Bedingung, ob eine der gesuchten Anwendungen des Typs vorhanden ist.<\/p>\n<p>Im ersten <b>Case<\/b>-Zweig untersucht sie, ob <b>As New [Type] <\/b>gefunden werden kann. Hier pr&uuml;ft sie, ob der Typ am Ende der Zeile enthalten ist. Falls ja, holt sie die Anzahl der einger&uuml;ckten Zeichen und schreibt diese in <b>lngSpaces<\/b>, damit die Einr&uuml;ckung anschlie&szlig;end wiederhergestellt werden kann.<\/p>\n<p>Anschlie&szlig;end liest sie den Namen der verwendeten Variablen f&uuml;r diesen Typ in die Variable <b>strVariable <\/b>ein. In der Zeile wird nun <b>As New [Type] <\/b>durch <b>As Object <\/b>ersetzt. Au&szlig;erdem wird in diesem Fall eine weitere Zeile hinzugef&uuml;gt, die das neue Objekt erstellt.<\/p>\n<p>Aus <\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> ADODB.Recordset<\/pre>\n<p>wird nun:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As Object<\/span>\r\n<span style=\"color:blue;\">Set<\/span> rst = CreateObject(\"ADODB.Recordset\")<\/pre>\n<p><b>bolReplaced <\/b>wird auf <b>True <\/b>eingestellt, damit die aufrufende Prozedur die Zeile tats&auml;chlich im Code ersetzt.<\/p>\n<p>Im zweiten <b>Case<\/b>-Zweig suchen wir nach Vorkommen von <b>= New [Type]<\/b>.<\/p>\n<p>Hier ersetzen wir zum Beispiel<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> rst = <span style=\"color:blue;\">New<\/span> ADODB.Recordset<\/pre>\n<p>durch die folgende Zeile:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> rst = CreateObject(\"ADODB.Recordset\")<\/pre>\n<p>Der folgende <b>Case<\/b>-Zweig ist der aufwendigste, weil wir hier reine Deklarationen ersetzen. Das ist an sich nicht aufwendig, aber sie behandelt auch Prozedurk&ouml;pfe etc., die mehrere Zuweisungen des Typs enthalten k&ouml;nnen und die alle untersucht und gegebenenfalls ersetzt werden m&uuml;ssen.<\/p>\n<p>Sie sucht nach Vorkommen von <b>As [Type]<\/b>, erledigt dies aber in einer <b>Do While<\/b>-Schleife, bis alle Vorkommen ersetzt wurden.<\/p>\n<p>So wird beispielsweise aus<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestMixedParametersZweiVorkommen(rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset, rst2<span style=\"color:blue;\"> As <\/span>ADODB.Recordset)<\/pre>\n<p>die folgende Zeile:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TestMixedParametersZweiVorkommen(rst<span style=\"color:blue;\"> As Object<\/span>, rst2<span style=\"color:blue;\"> As Object<\/span>)<\/pre>\n<p>Schlie&szlig;lich gibt <b>ReplaceTypeInLine <\/b>den aktuellen Wert von <b>strLine <\/b>zur&uuml;ck.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Die hier vorgestellten Techniken wurden mit einer Reihe von Datenbanken getestet. Dennoch ist nicht auszuschlie&szlig;en, dass es Konstellationen gibt, wo sie nicht vollst&auml;ndig funktioniert. In diesem Fall schreib mir gern eine E-Mail an <b>support@andreminhorst.de<\/b>.<\/p>\n<p>Ein weiterer Schritt, der beispielsweise bei Verwendung der ADODB-Bibliothek n&ouml;tig ist, ist das Ersetzen der Konstanten durch Zahlenwerte oder durch entsprechende Deklaration der Konstanten.<\/p>\n<p>Wenn im Code zum Beispiel <b>adOpenDynamic <\/b>(Wert <b>2<\/b>) in einer <b>Open<\/b>-Methode verwendet wird, musst Du entweder in der <b>Open<\/b>-Methode die Konstante durch den Zahlenwert ersetzen oder diesen wie folgt &ouml;ffentlich in einem Standardmodul deklarieren:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Const adOpenDynamic<span style=\"color:blue;\"> As Long<\/span> = 2<\/pre>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>EarlyBindingInLateBindingUmwandeln.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/BEA1CCCF-A385-412F-B060-B2F239692286\/vbe_495.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Artikel &#8220;VBA: Early Binding und Late Binding&#8221; (www.vbentwickler.de\/494) haben wir die beiden Methoden Early Binding und Late Binding vorgestellt und ihre Vor- und Nachteile beschrieben. Im vorliegenden Artikel zeigen wir nun eine automatische L&ouml;sung, um schnell einige oder alle per Early Binding definierten Elemente nach Late Binding zu migrieren. Dazu nutzen wir Code, der zun&auml;chst alle Early Binding-Elemente ermittelt, diese in einem Formular anzeigt und es dann erm&ouml;glicht, diese in Late Binding-Elemente umzuwandeln. <\/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,66062025,44000037],"tags":[],"yst_prominent_words":[],"class_list":["post-55000495","post","type-post","status-publish","format-standard","hentry","category-662025","category-66062025","category-VBAEditor_programmieren"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000495","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=55000495"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000495\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000495"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000495"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000495"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000495"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}