以编程方式从 Word 2007 文档中提取宏 (VBA) 代码

Posted

技术标签:

【中文标题】以编程方式从 Word 2007 文档中提取宏 (VBA) 代码【英文标题】:Programmatically extract macro (VBA) code from Word 2007 docs 【发布时间】:2010-09-08 03:53:20 【问题描述】:

是否可以使用 API 从 Word 2007“docm”文档中提取所有 VBA 代码?

我找到了如何在运行时插入 VBA 代码,以及如何删除所有 VBA 代码,但没有将实际代码提取到我可以存储的流或字符串中(并在将来插入到其他文档中)。

任何提示或资源将不胜感激。

编辑:感谢大家,Aardvark 的答案正是我想要的。我已将他的代码转换为 C#,并且能够使用 Visual Studio 2008 从类库中调用它。

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;

【问题讨论】:

使用StringBuilder优化内存使用:StringBuilder sb = new StringBuilder(); for.... sb.AppendLine("你的代码行"); ... 宏.Add(sb.ToString()); 【参考方案1】:

您可以将代码导出到文件中,然后再读回。

我一直在使用下面的代码来帮助我将一些 Excel 宏置于源代码控制之下(使用 Subversion 和 TortoiseSVN)。基本上,只要我打开 VBA 编辑器保存,它就会将所有代码导出到文本文件中。我把文本文件放在颠覆中,这样我就可以做差异了。您应该能够改编/窃取其中的一些内容以在 Word 中工作。

CanAccessVBOM() 中的注册表检查对应于安全设置中的“信任对 Visual Basic 项目的访问”。

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

【讨论】:

这很好,因为您会得到完整的表格等。 +1【参考方案2】:

您必须添加对 Microsoft Visual Basic for Applications Extensibility 5.3(或您拥有的任何版本)的引用。我的盒子上有 VBA SDK 等 - 所以这可能不是 office 附带的。

您还必须专门启用对 VBA 对象模型的访问 - 请参阅 Word 选项中的“信任中心”。这是 Office 提供的所有其他宏安全设置的补充。

这个例子将从它所在的当前文档中提取代码 - 它本身是一个 VBA 宏(并且会显示它自己和任何其他代码)。还有一个 Application.vbe.VBProjects 集合来访问其他文档。虽然我从未这样做过,但我认为外部应用程序也可以使用此 VBProjects 集合打开文件。这些东西的安全性很有趣,所以它可能很棘手。

我也想知道现在的docm 文件格式是什么——XML 之类的docx?那会是更好的方法吗?

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

【讨论】:

这太棒了,谢谢!我将您的代码转换为 C#,并且能够从 WPF 应用程序调用它并在列表框中打印出宏代码。我将在我编辑的答案中发布代码的 C# 版本。 如果您的项目中有表单,这并不理想。它不会导出表单的控件定义部分。 只是确认 .xlsb 文件是 zip 文件(如预期的那样),但 vbaProject 仍存储在 .bin 文件中,这显然是一个复合文档(第一个可读字符串之一是 @987654324 @')。 我刚刚将 ref 添加到可扩展性 5.3 并且没有 VBA SDK 并且代码不包含错误——它已执行,显然已完成。谢谢。

以上是关于以编程方式从 Word 2007 文档中提取宏 (VBA) 代码的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenOffice.org 基本宏以编程方式将 *.odt 文件转换为 MS Word *.doc 文件

word2007如何将4张图片均匀排版在一页中

Access 2007列表框:如何以编程方式单击?

vc 怎么从word里提取图片

如何用VBA宏程序将excel中的内容批量复制到word文档中去

技巧原汁原味批量提取Word图片