2008-09-08 11 views
14

Est-il possible d'extraire tout le code VBA d'un document Word 2007 "docm" à l'aide de l'API?Extraire par programme le code de macro (VBA) à partir de Word 2007 docs

J'ai trouvé comment insérer du code VBA à l'exécution, et comment supprimer tout le code VBA, mais pas extraire le code réel dans un flux ou une chaîne que je peux stocker (et insérer dans d'autres documents).

Des conseils ou des ressources seraient appréciés.

Modifier: merci à tous, Aardvark La réponse était exactement ce que je cherchais. J'ai converti son code C#, et a pu appeler à partir d'une bibliothèque de classes en utilisant 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; 
} 
+1

Utilisez le StringBuilder pour optimiser l'utilisation de la mémoire: StringBuilder sb = new StringBuilder(); Pour sb.AppendLine ("votre ligne de code"); ... macros.Add (sb.ToString()); – Skuami

Répondre

9

Vous devez ajouter une référence à Microsoft Visual Basic pour Applications Extensibilité 5.3 (ou quelle que soit la version tu as). J'ai le SDK VBA et tel sur ma boîte - donc ce n'est peut-être pas exactement ce que le bureau est livré avec.

Vous devez également activer spécifiquement l'accès au modèle objet VBA - voir le "Centre de gestion de la confidentialité" dans les options Word. Cela s'ajoute à tous les autres paramètres de sécurité Macro fournis par Office.

Cet exemple extraira le code du document en cours dans lequel il se trouve - il s'agit d'une macro VBA (et elle s'affichera elle-même ainsi que tout autre code). Il existe également une collection Application.vbe.VBProjects pour accéder à d'autres documents. Bien que je ne l'aie jamais fait, je suppose qu'une application externe pourrait également ouvrir des fichiers en utilisant cette collection VBProjects. La sécurité est drôle avec ce genre de choses, donc ça peut être difficile.

Je me demande également ce que le format de fichier docm est maintenant - XML ​​comme le docx? Serait-ce une meilleure approche?

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 
+1

C'est génial, merci! J'ai converti votre code en C#, et je suis capable de l'appeler à partir d'une application WPF et d'imprimer le code de la macro dans une liste. Je posterai la version C# du code dans ma réponse éditée. –

+1

Si vous avez des formulaires dans votre projet, ce n'est pas idéal. Il n'exporte pas la partie de définition de contrôle du formulaire. – MarkJ

+0

Juste pour confirmer les fichiers '.xlsb' sont des fichiers zip (comme prévu) mais le vbaProject est toujours stocké dans un fichier' .bin' qui est clairement un document composé (l'une des premières chaînes lisibles est 'Root Entry' '). –

25

Vous pouvez exporter le code aux fichiers puis les relire.

J'utilise le code ci-dessous pour me aider à garder certaines macros Excel sous contrôle de source (en utilisant Subversion & TortoiseSVN). Il exporte tout le code vers des fichiers texte à chaque fois que j'enregistre avec l'éditeur VBA ouvert. Je mets les fichiers texte dans subversion pour que je puisse faire des diffs. Vous devriez être capable d'adapter/voler une partie de ceci pour travailler dans Word.

La vérification du Registre dans CanAccessVBOM() correspond au "Trust d'accès au projet Visual Basic" dans le paramètre de sécurité.

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

C'est sympa puisque vous aurez des formes et des choses intactes. +1 – Aardvark

Questions connexes