Frage

Ist es möglich, den gesamten VBA-Code mithilfe der API aus einem Word 2007-Dokument „docm“ zu extrahieren?

Ich habe herausgefunden, wie man VBA-Code zur Laufzeit einfügt und wie man den gesamten VBA-Code löscht, aber nicht den eigentlichen Code in einen Stream oder String herauszieht, den ich speichern (und in Zukunft in andere Dokumente einfügen) kann.

Für Tipps oder Ressourcen wäre ich dankbar.

Bearbeiten:Danke an alle, ErdferkelDie Antwort von 's war genau das, was ich gesucht habe.Ich habe seinen Code in C# konvertiert und konnte ihn mit Visual Studio 2008 aus einer Klassenbibliothek aufrufen.

using Microsoft.Office.Interop.Word;
using Microsoft.Vbe.Interop;

...

public List<string> GetMacrosFromDoc()
{
    Document doc = GetWordDoc(@"C:\Temp\test.docm");

    List<string> macros = new List<string>();

    VBProject prj;
    CodeModule code;
    string composedFile;

    prj = doc.VBProject;
    foreach (VBComponent comp in prj.VBComponents)
    {
        code = comp.CodeModule;

        // Put the name of the code module at the top
        composedFile = comp.Name + Environment.NewLine;

        // Loop through the (1-indexed) lines
        for (int i = 0; i < code.CountOfLines; i++)
        {
            composedFile += code.get_Lines(i + 1, 1) + Environment.NewLine;
        }

        // Add the macro to the list
        macros.Add(composedFile);
    }

    CloseDoc(doc);

    return macros;
}
War es hilfreich?

Lösung

Sie müssen einen Verweis auf Microsoft Visual Basic for Applications Extensibility 5.3 (oder welche Version auch immer Sie haben) hinzufügen.Ich habe das VBA-SDK und dergleichen auf meiner Box – daher ist dies möglicherweise nicht genau das, was Office im Lieferumfang enthält.

Außerdem müssen Sie den Zugriff auf das VBA-Objektmodell speziell aktivieren – siehe „Vertrauensstellungscenter“ in den Word-Optionen.Dies gilt zusätzlich zu allen anderen Makrosicherheitseinstellungen, die Office bereitstellt.

In diesem Beispiel wird Code aus dem aktuellen Dokument extrahiert, in dem es sich befindet – es selbst ist ein VBA-Makro (und zeigt sich selbst und jeden anderen Code ebenfalls an).Es gibt auch eine Application.vbe.VBProjects-Sammlung für den Zugriff auf andere Dokumente.Obwohl ich das noch nie gemacht habe, gehe ich davon aus, dass eine externe Anwendung mithilfe dieser VBProjects-Sammlung auch Dateien öffnen könnte.Die Sicherheit ist bei solchen Dingen komisch, daher kann es knifflig sein.

Ich frage mich auch, was das DOCM-Dateiformat jetzt ist – XML wie DocX?Wäre das ein besserer Ansatz?

Sub GetCode()

    Dim prj As VBProject
    Dim comp As VBComponent
    Dim code As CodeModule
    Dim composedFile As String
    Dim i As Integer

    Set prj = ThisDocument.VBProject
        For Each comp In prj.VBComponents
            Set code = comp.CodeModule

            composedFile = comp.Name & vbNewLine

            For i = 1 To code.CountOfLines
                composedFile = composedFile & code.Lines(i, 1) & vbNewLine
            Next

            MsgBox composedFile
        Next

End Sub

Andere Tipps

Sie können den Code in Dateien exportieren und diese dann wieder einlesen.

Ich habe den folgenden Code verwendet, um einige Excel-Makros unter Quellcodeverwaltung zu halten (mithilfe von Subversion und TortoiseSVN).Grundsätzlich wird der gesamte Code jedes Mal in Textdateien exportiert, wenn ich ihn mit geöffnetem VBA-Editor speichere.Ich habe die Textdateien in Subversion eingefügt, damit ich Unterschiede machen kann.Sie sollten in der Lage sein, einiges davon anzupassen/zu stehlen, um in Word zu funktionieren.

Die Registrierungsprüfung in CanAccessVBOM() entspricht dem „Zugriff auf Visual Basic Project vertrauen“ in der Sicherheitseinstellung.

Sub ExportCode()

    If Not CanAccessVBOM Then Exit Sub ' Exit if access to VB object model is not allowed
    If (ThisWorkbook.VBProject.VBE.ActiveWindow Is Nothing) Then
        Exit Sub ' Exit if VBA window is not open
    End If
    Dim comp As VBComponent
    Dim codeFolder As String

    codeFolder = CombinePaths(GetWorkbookPath, "Code")
    On Error Resume Next
    MkDir codeFolder
    On Error GoTo 0
    Dim FileName As String

    For Each comp In ThisWorkbook.VBProject.VBComponents
        Select Case comp.Type
            Case vbext_ct_ClassModule
                FileName = CombinePaths(codeFolder, comp.Name & ".cls")
                DeleteFile FileName
                comp.Export FileName
            Case vbext_ct_StdModule
                FileName = CombinePaths(codeFolder, comp.Name & ".bas")
                DeleteFile FileName
                comp.Export FileName
            Case vbext_ct_MSForm
                FileName = CombinePaths(codeFolder, comp.Name & ".frm")
                DeleteFile FileName
                comp.Export FileName
            Case vbext_ct_Document
                FileName = CombinePaths(codeFolder, comp.Name & ".cls")
                DeleteFile FileName
                comp.Export FileName
        End Select
    Next

End Sub
Function CanAccessVBOM() As Boolean
    ' Check resgistry to see if we can access the VB object model
    Dim wsh As Object
    Dim str1 As String
    Dim AccessVBOM As Long

    Set wsh = CreateObject("WScript.Shell")
    str1 = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & _
        Application.Version & "\Excel\Security\AccessVBOM"
    On Error Resume Next
    AccessVBOM = wsh.RegRead(str1)
    Set wsh = Nothing
    CanAccessVBOM = (AccessVBOM = 1)
End Function


Sub DeleteFile(FileName As String)
    On Error Resume Next
    Kill FileName
End Sub

Function GetWorkbookPath() As String
    Dim fullName As String
    Dim wrkbookName As String
    Dim pos As Long

    wrkbookName = ThisWorkbook.Name
    fullName = ThisWorkbook.fullName

    pos = InStr(1, fullName, wrkbookName, vbTextCompare)

    GetWorkbookPath = Left$(fullName, pos - 1)
End Function

Function CombinePaths(ByVal Path1 As String, ByVal Path2 As String) As String
    If Not EndsWith(Path1, "\") Then
        Path1 = Path1 & "\"
    End If
    CombinePaths = Path1 & Path2
End Function

Function EndsWith(ByVal InString As String, ByVal TestString As String) As Boolean
    EndsWith = (Right$(InString, Len(TestString)) = TestString)
End Function
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top