Überraschung!

Letzte Änderung am 6. Juni 2020 by Christoph Jüngling

Microsoft ist doch immer wieder für Überraschungen gut. Aber bei manchen dieser Überraschungen fragt man sich, ob die Entwickler überhaupt richtig nachdenken, bevor sie etwas entscheiden. So erging es uns in einem alten Projekt mit Visio, aber ich vermute, das hätte z.B. auch in Access-VBA passieren können.

Eigentlich fing es ganz harmlos an. Damals (noch unter Windows 7) hatten wir in dem Projekt den Bedarf, von Visio aus auf eine XML-Datei zuzugreifen und gewisse Informationen dort herauszulesen. Auf der Grundlage dieser Informationen wurde dann das in Visio dargestellte Design individualisiert. Was liegt näher, als die Microsoft-Bibliothek “xml*.dll” zu verwenden? Das taten wir, und einige Zeit lief auch alles wunderbar. Damals hieß die Bibliothek noch “xml2” oder “3”, inzwischen sind wir bei “xml6.dll” angelangt. Alle bisherigen Versionswechsel verliefen reibungslos – bis dann unter Windows 10 ein Update kam …

Im Detail geht es hier um die Klasse DOMDocument, die die Grundlage für den XML-Import darstellt. Dazu wird zunächst eine Referenz auf die Bibliothek “Microsoft XML 6” eingerichtet. Im VBA-Code wird dann die Instanz erzeugt und die Datei eingelesen. Dabei kann man auch gleich noch Parsing-Fehler melden:

Dim doc As MSXML2.DOMDocument

Set doc = New MSXML2.DOMDocument

If Not doc.loadXML(filename) Then
    Err.Raise doc.parseError.ErrorCode, , doc.parseError.reason
End If

Zunächst ist auffällig, dass die Datei msxml6.dll heißt, während der Name der Library im VBA-Code weiterhin MSXML2 lautet. Das ist meiner Ansicht nach nicht wirklich elegant, denn die Änderung des Dateinamens führt dazu, dass die neue Bibliothek nicht automatisch verwendet wird. Dennoch kann man durchaus noch drüber hinweg sehen, zumal bei einem Update zu einer XML-Bibliothek mit einer höheren Versionsnummer nur der Verweis, aber wenigstens nicht der Programmcode verändert werden muss.

Falls kein Parsing Error auftritt, kann nun über die Variable doc auf die Struktur des XML zugegriffen werden. Sogar XPath-Ausdrücke werden unterstützt! Soweit ist das hinreichend trivial, und es gibt auch genügend Beispiele dafür im Netz, so dass ich das hier nicht weiter ausführen möchte. Darum geht es im Moment auch gar nicht.

Der entscheidende Punkt war die Verwendung von DOMDocument, denn hierbei stellte die Bibliothek noch einen Partner bereit, DOMDocument60. Dass wir uns damals für die Verwendung von DOMDocument entschieden haben, folgte einer klaren Logik: Wenn es eine versionslose und eine versionsgebundene Variante einer Klasse gibt, bevorzuge ich im Zweifel immer die versionslose, gerade um den obigen Vorteil möglichst lange zu behalten. Gut gedacht, dazu stehe ich auch heute noch.

Leider hat Microsoft mit der Auslieferung von Windows 10 eine MSXML6.dll einbezogen, die nun ausgerechnet die versionsgebundene Klasse enthält, die versionslose jedoch nicht mehr. Und schlagartig war unser Code, sobald er unter Windows 10 ausgeführt wurde, nicht mehr lauffähig.

Also blieb uns nichts anderes übrig, als in allen Dateien, die diesen Code enthielten, die entsprechende Änderung durchzuführen. Dazu habe ich ein kleines VB6-Programm geschrieben, das im Kern in etwa den folgenden Code enthält:

Const oldString As String = "DOMDocument"
Const newString As String = "DOMDocument60"

Dim visio As Object    ' visio.Application
Dim visiodoc As Object ' visio.Document
Dim vb As Object       ' VBIDE.VBProject

Set visio = CreateObject("Visio.InvisibleApp")
Set visiodoc = visio.Documents.OpenEx(filename, 128) ' 128 = visOpenMacrosDisabled

Set vb = visio.Vbe.ActiveVBProject

For i = 1 To vb.VBComponents.count
    With vb.VBComponents(i).CodeModule
        For j = 1 To .countOfLines
            line = .Lines(j, 1)
            If InStr(1, line, oldString, vbBinaryCompare) > 0 _
                And InStr(1, line, newString, vbBinaryCompare) = 0 Then

                line = Replace(line, oldString, newString, Compare:=vbBinaryCompare)
                .DeleteLines j, 1
                .InsertLines j, line
            End If
        Next j
    End With
Next i

visiodoc.Save
visiodoc.Close
Set visiodoc = Nothing
visio.Quit

Das Prinzip “late binding” habe ich deshalb verwenden müssen, weil unsere Anwender teilweise unterschiedliche Visio-Versionen installiert haben und so der Code nicht unnötig aufwändig wurde. Den Unterschied zu “early binding” hat Thomas Möller auf Access im Unternehmen sehr gut beschrieben. (Paywall-Hinweis: Der vollständige Artikel ist nur für Leser des Magazins von André Minhorst verfügbar. Aber bereits der frei verfügbare Teil des Artikels gibt einen Einblick in das Prinzip.)

Alles in allem hat das recht gut funktioniert. Aber mal ehrlich, das hätte doch nicht sein müssen, oder?

Update: Groß-/Kleinschreibung einheitlich gestaltet und das Größer-als-Zeichen im Code korrigiert

Ähnliche Artikel:

Schreibe einen Kommentar

Deine Email-Adresse wird nicht veröffentlicht.

siebzehn + zehn =