Inhaltsverzeichnis
1. Übersicht Irgendwann wird man aber feststellen, dass bei der täglichen Arbeit mit VB doch so einige Tools fehlen, welche das Schreiben eines Programmes erleichtern könnten. Solche Tools, AddIns genannt, lassen sich in VB einbinden. Leider hat es Microsoft irgendwie versäumt, genauer auf diese Möglichkeit des Erweiterns von VB durch AddIns einzugehen und so findet man in der MSDN sehr wenige Beispiele und Informationen dazu. Auch im Internet gestaltet sich die Suche nach Informationen recht schwierig. Insbesondere Informationen zum VBIDE-Objekt und dessen Klassen, die ja die Grundlage für ein AddIn bilden. Einziger Ausweg bleibt hier wohl nur der "Objekt Browser" und das Ausprobieren der einzelnen Klassen und deren Funktionen. In diesem Workshop möchte ich zeigen, wie man ein AddIn erstellt, das uns eine Aufgabenliste ähnlich wie in VB2005 auch für die Visual Basic 6 IDE bietet. Hiermit soll es möglich sein Kommentare, Aufgaben und Fehler im Code des Programmes als Kommentare zu vermerken und in der Aufgabenliste anzuzeigen. Visual Basic liefert uns glücklicherweise ein fast fertiges AddIn-Template, das „nur“ noch entsprechend angepasst werden muss. Hierzu erstellen wir ein neues Projekt und wählen aus der Projektliste den Projekttyp "AddIn" aus. Nun wird das AddIn-Template geladen und im Projektexplorer wird ein neues Projekt "MeinAddIn" angezeigt. Der Vorteil diese Templates ist, dass man sich nicht um die Verweise kümmern muss und es schon fertigen Code für ein AddIn enthält. Die wichtigsten Verweise sind die "Microsoft Office x.x Object Library" für das Erstellen von Menüeinträgen und die "Microsoft Visual Basic 6.0 Extensibility" für den Zugriff auf die VB-IDE sowie der Verweis "Microsoft Add-In Designer". Dieser Verweis bildet das eigentliche Interface zwischen Visual Basic und einem AddIn. 2. Dockendes Addin Da wir hier ein dockendes AddIn entwickeln möchten, muss das Template noch entsprechend angepasst werden: Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) ' Hinzufügen des AddIns zur VB-IDE On Error GoTo error_handler ' Speichern der VB-Instance Set VBInstance = Application ' VBBuildEvents instanzieren nur in VB6 !!! Set nEvents2 = VBInstance.Events Set VBModeEvents = nEvents2.VBBuildEvents ' Eintrag im Menü erzeugen Set mcbMenuCommandBar = AddToAddInCommandBar("Aufgabenliste") ' Übergeben des Ereignisses an die Behandlungsroutine. Set Me.MenuHandler = VBInstance.Events.CommandBarEvents(mcbMenuCommandBar) If GetSetting(App.Title, "Settings", "Aufgabenliste", "0") = "0" Then ' freie GUID ermitteln, wenn noch keine vorhanden DockingAddInGUID = GUIDGen SaveSetting App.Title, "Settings", "Aufgabenliste", DockingAddInGUID Else ' GUID laden DockingAddInGUID = GetSetting(App.Title, "Settings", "Aufgabenliste", "0") End If ' Hier wird das Userdokument in ein Fenster umgewandelt Set mWindow = VBInstance.Windows.CreateToolWindow(AddInInst, _ "jsdTaskList.dobAddIn", "Aufgabenliste", DockingAddInGUID, mdobAddIn) If ConnectMode = ext_cm_AfterStartup Then If GetSetting(App.Title, "Settings", "DisplayOnConnect", "0") = "1" Then ' Anzeigen der Form nach Connect Me.Show End If End If Exit Sub error_handler: MsgBox Err.Description End Sub Jedes AddIn benötigt eine GUID. Diese wird in der Registry eingetragen. Im Modul "Connect" im Sub "AddinInstance_OnConnection" prüfen wir ob unser AddIn bereits eine GUID besitzt: If GetSetting(App.Title, "Settings", "Aufgabenliste", "0") = "0" Then ' freie GUID ermitteln, wenn noch keine vorhanden DockingAddInGUID = GUIDGen SaveSetting App.Title, "Settings", "Aufgabenliste", DockingAddInGUID Else ' GUID laden DockingAddInGUID = GetSetting(App.Title, "Settings", "Aufgabenliste", "0") End If Ist noch keine GUID vorhanden, so wird eine neue GUID erzeugt. Dies geschieht mittels der Function "GUIDGen" im Modul "modMain". Hierzu ist es notwendig die API zu bemühen. Dazu deklarieren wir zuerst den GUID-Typ und die notwendigen API-Calls: Private Type GUID Data1 As Long Data2 As Long Data3 As Long Data4(8) As Byte End Type Private Declare Function CoCreateGuid Lib "ole32.dll" ( _ pguid As GUID) As Long Private Declare Function StringFromGUID2 Lib "ole32.dll" ( _ rguid As Any, _ ByVal lpstrClsId As Long, _ ByVal cbMax As Long) As Long Die Generierung der GUID übernimmt die Function "GUIDGen", welche uns die neue GUID als String zurückliefert: Public Function GUIDGen() As String ' Erzeugen einer GUID Dim uGUID As GUID Dim sGUID As String Dim tGUID As String Dim bGUID() As Byte Dim lLen As Long Dim RetVal As Long lLen = 40 bGUID = String(lLen, 0) CoCreateGuid uGUID RetVal = StringFromGUID2(uGUID, VarPtr(bGUID(0)), lLen) sGUID = bGUID If (Asc(Mid$(sGUID, RetVal, 1)) = 0) Then RetVal = RetVal - 1 End If GUIDGen = Left$(sGUID, RetVal) End Function Somit haben wir ein funktionsfähiges dockendes AddIn. 3. Ereignisbehandlung Bevor wir aber mit diesen Events arbeiten können, müssen wir diese in unserem AddIn deklarieren. Dazu erweitern wir den Code im Modul "Connect", im Deklarationsabschnitt, um folgende Zeilen: ' Implementierung der Events2 Schnittstelle ' nur in VB6 !!! Dim nEvents2 As Events2 ... ' Ereignisbehandlungsroutine für den Status der ' Entwicklungsumgebung (RunModus, DesignModus) ' nur in VB6 !!! Public WithEvents VBModeEvents As VBBuildEvents Im Code des Benutzerdokumentes muss nun eine öffentliche Variable für den Zustand der Entwicklungsumgebung eingefügt werden: ' 0=RunMode, 1=BreakMode, 2=DesignMode Public IDEMode As Integer Anschließend fügen wir im Modul „Connect“ folgende Eventhandler ein: Private Sub VBModeEvents_EnterDesignMode() ' Ereignis nach Wechsel in Design-Modus mdobAddIn.IDEMode = vbext_vm_Design End Sub Private Sub VBModeEvents_EnterRunMode() ' Ereignis nach Wechsel in Ausführen-Modus mdobAddIn.IDEMode = vbext_vm_Run End Sub Diese Eventhandler setzen je nach Zustand die zuvor deklarierte Variable im Benutzerdokument. Nun sind wir also in der Lage den Zustand der Entwicklungsumgebung auszuwerten. 4. Hinzufügen eines Icons vor den Menüeintrag ' Hinzufügen zum Menü Set cbMenuCommandBar = cbMenu.Controls.Add(1) cbMenuCommandBar.Caption = sCaption fügen wir folgendes hinzu: ' Hinzufügen Icon zu Menü Clipboard.SetData LoadResPicture(101, 0) cbMenuCommandBar.PasteFace Nun wird auch bei unserem AddIn ein Icon vor der Beschriftung angezeigt. 5. Das Benutzerinterface Auf dem Benutzerdokument platzieren wir eine Combobox für die Auswahl der anzuzeigenden Information. Der Eigenschaft List fügen wir folgende Einträge hinzu:
Weiterhin platzieren wir hier ein FlexGrid für die dann anzuzeigenden Kommentarzeilen. Das FlexGrid ist mit folgenden Eigenschaften zu versehen:
Damit unser FlexGrid sich automatisch an die Größe des Fensters anpasst müssen noch einige Anpassungen im Benutzerdokument durchgeführt werden. Die Größenanpassung übernimmt der Code im Sub "UserDocument_Resize": Private Sub UserDocument_Resize() ' Anpassen der Controls VW = UserDocument.ViewportWidth VH = UserDocument.ViewportHeight ' Begrenzung bis zu welcher AddIn-Größe die Controls ' mit angepasst werden sollen If VW < 235 Then VW = 235 If VH < 95 Then VH = 95 ' Controls anpassen flxToDo.Move 5, 30, VW - 10, VH - 30 End Sub Da wir im FlexGrid eingestellt haben, dass die horizontale und die vertikale Scrollbar zulässig sind, wollen wir diese auch bei der Größenänderung des Benutzerdokumentes berücksichtigen. Die Spalte für die Einträge der Kommentarzeilen soll sich automatisch anpassen. Hierzu bedienen wir uns der API. Zuerst müssen einige Konstanten und eine API-Funktion deklariert werden: Private Declare Function GetSystemMetrics Lib "user32" ( _ ByVal nIndex As Long) As Long ' Breite in Pixel für Pfeilsymbol bei horizontaler Scrollbar Private Const SM_CXHSCROLL = 21 ' Höhe in Pixel der horizontalen Scrollbar Private Const SM_CYHSCROLL = 3 ' Breite in Pixel der vertikalen Scrollbar Private Const SM_CXVSCROLL = 2 ' Höhe in Pixel für Pfeilsymbol bei vertikaler Scrollbar Private Const SM_CYVSCROLL = 20 Mit der API-Funktion "GetSystemMetrics" ermitteln wir die Breite der Scrollbars damit diese von der Gesamtbreite der letzten Spalte abgezogen werden kann. Dies geschieht im Sub "SetTodoColumnWidth": Private Sub SetTodoColumnWidth() ' Ermitteln Spaltenbreite für Beschreibungs-Spalte Dim UsableWidth As Long With flxToDo UsableWidth = (.Width * Screen.TwipsPerPixelX) - _ (GetSystemMetrics(SM_CXVSCROLL) * Screen.TwipsPerPixelX) - 4100 .ColWidth(3) = UsableWidth End With End Sub Wichtig ist hierbei zu beachten, dass die Größenangaben hier in Pixel vorliegen! Es ist also eine Umwandlung mittels der Funktion "TwipsPerPixelX" des Screen-Objekts notwendig. Nun fügen Sie noch eine Toolbar für das Schließen und Aktualisieren der Aufgabenliste und ein Imagelist-Control für die Bilder der Toolbar hinzu. Private Sub tbMain_ButtonClick(ByVal Button As MSComctlLib.Button) ' Toolbar Select Case Button.Key Case "Close" Connect.Hide Case "Refresh" Call FillGrid End Select End Sub Beim Klick auf den Schliessen-Button schließen wir unser AddIn. Beim Klick auf den Refresh-Button wird unser FlexGrid neu gefüllt. Wie, das verrate ich Ihnen im nächsten Abschnitt. In der Entwurfsphase zeigt sich dann folgendes Bild: 6. Füllen der Aufgabenliste
Diese Tags können natürlich jederzeit durch Sie verändert bzw. geändert oder erweitert werden. Die Auswahl des entsprechenden Tags erfolgt durch die Combobox auf dem Benutzerdokument und wird im Sub "FillGrid" ausgewertet. ' Prüfen der Auswahl Select Case cbAuswahl.Text Case "Aufgaben" sTag = "TODO:" sGridHeader = "<Projekt|<Komponente|<Prozedur|<ToDo" Case "Kommentare" sTag = "CMT:" sGridHeader = "<Projekt|<Komponente|<Prozedur|<Kommentar" Case "Fehler" sTag = "BUG:" sGridHeader = "<Projekt|<Komponente|<Prozedur|<Fehler" End Select Für das Auslesen der Kommentarzeilen benötigen wir nun den Zugriff auf die geöffneten Objekte und die entsprechenden Code-Module. Hierbei greifen wir auf das VBE-Objekt zurück und iterieren durch alle geladenen Projekte und deren Module im Sub "FillGrid". Hierbei beschränken wir uns für den Quellcode auf folgende Komponenten: Standardmodul, Form, MDI-Form, Klassenmodul, UserControl und ActivXDesigner. ' Iteration durch alle geladenen Projekte For Each VBProj In VBInstance.VBProjects For Each VBMod In VBProj.VBComponents If VBMod.Type = vbext_ct_VBForm Or _ VBMod.Type = vbext_ct_VBMDIForm Or _ VBMod.Type = vbext_ct_StdModule Or _ VBMod.Type = vbext_ct_UserControl Or _ VBMod.Type = vbext_ct_ActiveXDesigner Or _ VBMod.Type = vbext_ct_ClassModule Then lNoCodeLines = VBMod.CodeModule.CountOfLines lNoDeclLines = VBMod.CodeModule.CountOfDeclarationLines lStartLine = 1 lEndLine = -1 lStartCol = 1 lEndCol = -1 ' Suchen des Tags Do Until Not VBMod.CodeModule.Find("'" & sTag, lStartLine, _ lStartCol, lEndLine, lEndCol, False, False, True) sCodeLine = Trim(VBMod.CodeModule.Lines(lStartLine, 1)) sUCCodeline = UCase(sCodeLine) lPos = InStr(1, sUCCodeline, sTag, vbTextCompare) If lPos <> 0 Then If lStartLine <= lNoDeclLines Then sProcName = "Deklarationen" Else lProcType = vbext_pk_Proc sProcName = VBMod.CodeModule.ProcOfLine(lStartLine, lProcType) If lProcType <> vbext_pk_Proc Then Select Case lProcType Case vbext_pk_Get sProcName = sProcName & "(Prop. Get)" Case vbext_pk_Set sProcName = sProcName & "(Prop. Set)" Case vbext_pk_Let sProcName = sProcName & "(Prop. Let)" End Select End If End If ' Hinzufügen Tag zum Flexgrid flxToDo.AddItem VBProj.Name & vbTab & VBMod.Name & vbTab & _ sProcName & vbTab & Trim(Mid(sCodeLine, lPos + Len(sTag))) lNoOfItems = lNoOfItems + 1 flxToDo.RowData(flxToDo.Rows - 1) = lStartLine End If lStartLine = lStartLine + 1 lStartCol = 1 lEndLine = -1 lEndCol = -1 Loop End If Next Next Wir durchsuchen alle Code-Module und fügen die Informationen über Projekt, Modul und Prozedur sowie die Zeilennummer im Codemodul dem FlexGrid hinzu. Anschließend formatieren wir unser FlexGrid und „Mergen“ bei gefundenen Kommentarzeilen die Spalten von Projekt, Modul und Prozedur. Dies führt zu einer Darstellung wie man sie aus Pivot-Tabellen kennt und erlaubt uns, auch innerhalb einer Prozedur mehrere Kommentarzeilen mit gleichem Tag zu nutzen und diese übersichtlich darzustellen: ' Formatierung des Flexgrids With flxToDo If lNoOfItems <> 0 Then .RemoveItem 1 .MergeCells = flexMergeRestrictColumns .MergeCol(0) = True .MergeCol(1) = True .MergeCol(2) = True Else Const sNOITEMS = " keine Einträge verfügbar - " .TextMatrix(1, 0) = sNOITEMS .TextMatrix(1, 1) = sNOITEMS .TextMatrix(1, 2) = sNOITEMS .TextMatrix(1, 3) = sNOITEMS .MergeCells = flexMergeRestrictRows .MergeRow(1) = True .RowData(1) = ROWDATAEMPTYLINE End If .Refresh .Redraw = True End With Nun wird unser FlexGrid mit den entsprechenden Kommentarzeilen aus dem Quellcode gefüllt. Es bietet sich folgendes Erscheinungsbild: 7. Springen zum Code Beim Doppelklick auf eine Zeile führen wir folgenden Code aus: Private Sub flxToDo_DblClick() ' Springen zur aktuellen Codezeile Call GotoTaggedLine End Sub Die Hauptarbeit wird im Sub GotoTaggedLine ausgeführt. Zuerst stellen wir sicher, dass die Entwicklungsumgebung sich im "DesignModus" befindet. Anschließend prüfen wir, ob unser AddIn auch Zeilen enthält, die zu einer Kommentarzeile verzweigen könnte. Dies stellen wir wie folgt sicher: If IDEMode = vbext_vm_Design Then If flxToDo.Row > 1 Or (flxToDo.Row = 1 And _ flxToDo.RowData(1) <> ROWDATAEMPTYLINE) Then … Danach prüfen wir der Reihe nach, ob das Projekt, das Modul und die Kommentarzeile noch vorhanden sind: ' Prüfung Projekt Set oPrj = VBInstance.VBProjects(sPrjName) If oPrj Is Nothing Then sMsg = "Das Projekt " & sPrjName & " ist nicht in der IDE geladen!" & _ vbCrLf & "Wollen Sie die Aufgabenliste aktualisieren ?" If MsgBox(sMsg, vbYesNo + vbExclamation, "Aufgabenliste") = vbYes Then Call FillGrid Else Exit Sub End If Else ' Prüfung Komponente Set oMod = oPrj.VBComponents(sModName) If oMod Is Nothing Then sMsg = "Das Modul " & sModName & " ist im Projekt" & vbCrLf & _ sPrjName & " nicht vorhanden !" & vbCrLf & _ "Wollen Sie die Aufgabenliste aktualisieren ?" + vbCrLf If MsgBox(sMsg, vbYesNo + vbExclamation, "Aufgabenliste") = vbYes Then Call FillGrid Else Set oPrj = Nothing Exit Sub End If Else ' Lesen der Codezeile sCode = oMod.CodeModule.Lines(lCodeLine, 1) sCodeUC = UCase(Trim(sCode)) lPos = InStr(1, sCodeUC, sTag, vbTextCompare) If lPos = 0 Then sMsg = "Die gewählte Zeile enthält kein gültiges Flag!" & vbCrLf & _ "Wollen Sie die Aufgabenliste aktualisieren ?" If MsgBox(sMsg, vbYesNo + vbExclamation, "Aufgabenliste") = vbYes Then Call FillGrid Else Set oPrj = Nothing Set oMod = Nothing Exit Sub End If Else ' Prüfen/Vergleich Inhalt If Trim(sText) <> Trim(Mid(Trim(sCode), lPos + Len(sTag))) Then sMsg = "Der Inhalt des Flags stimmt nicht mit " & vbCrLf & _ "der Aufgabenliste überein!" & vbCrLf & _ "Wollen Sie die Aufgabenliste aktualisieren ?" If MsgBox(sMsg, vbYesNo + vbExclamation, "Aufgabenliste") = vbYes Then Call FillGrid Else Set oPrj = Nothing Set oMod = Nothing Exit Sub End If Else ' Anzeigen der Codezeile oMod.Activate With oMod.CodeModule.CodePane .Show .TopLine = lCodeLine Call .SetSelection(lCodeLine, 1, lCodeLine, 255) End With End If End If End If End If Else Exit Sub End If Sofern noch alles in der Entwicklungsumgebung vorhanden ist, aktivieren wir das CodeModul und selektieren die übergebene Kommentarzeile. ' Anzeigen der Codezeile oMod.Activate With oMod.CodeModule.CodePane .Show .TopLine = lCodeLine Call .SetSelection(lCodeLine, 1, lCodeLine, 255) End With Fällt eine der Prüfungen negativ aus, so wird der Benutzer gefragt, ob die Aufgabenliste aktualisiert werden soll. Sofern er dies bejaht, wird die Aufgabenliste automatisch neu gefüllt. 8. Zusammenfassung Der im Beispielprojekt vorhandene Quellcode ist hinreichend kommentiert und erklärt auch die letzten "Geheimnisse", welche hier nicht ausführlich beschrieben wurden. Weiterführende Informationen für die Programmierung von AddInns hat Frank Schüler in einem sehr empfehlenswerten Tutorial zusammengestellt. Dieses ist erhältlich unter:
Viel Spaß bei der Nutzung der Aufgabenliste unter Visual Basic 6. Download Aufgaben-AddIn Dieser Workshop wurde bereits 15.530 mal aufgerufen.
Anzeige
![]() ![]() ![]() (einschl. Beispielprojekt!) Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
sevWizard für VB5/6 ![]() Professionelle Assistenten im Handumdrehen Erstellen Sie eigene Assistenten (Wizards) im Look & Feel von Windows 2000/XP - mit allem Komfort und zwar in Windeseile :-) Tipp des Monats ![]() Dieter Otter PopUp-Menü wird nicht angezeigt :-( In diesem Tipp verraten wir Ihnen, wie Sie Probleme mit PopUp-Menüs umgehen können, wenn diese unter bestimmten Umständen einfach nicht angezeigt werden. vb@rchiv CD Vol.6 ![]() ![]() Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! Online-Update-Funktion Entwickler-Vollversionen u.v.m. |
|||||||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |