Estrai codice macro (VBA) a livello di codice da documenti Word 2007
-
09-06-2019 - |
Domanda
È possibile estrarre tutto il codice VBA da un documento "docm" di Word 2007 utilizzando l'API?
Ho scoperto come inserire il codice VBA in fase di esecuzione e come eliminare tutto il codice VBA, ma non estrarre il codice effettivo in un flusso o una stringa che posso archiviare (e inserire in altri documenti in futuro).
Eventuali suggerimenti o risorse sarebbero apprezzati.
Modificare:grazie a tutti, AardvarkLa risposta di era esattamente quello che cercavo.Ho convertito il suo codice in C# e sono riuscito a richiamarlo da una libreria di classi utilizzando 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;
}
Soluzione
Dovrai aggiungere un riferimento a Microsoft Visual Basic for Applications Extensibility 5.3 (o qualunque versione tu abbia).Ho l'SDK VBA e simili sulla mia scatola, quindi potrebbe non essere esattamente ciò con cui Office viene fornito.
Inoltre è necessario abilitare specificatamente l'accesso al modello a oggetti VBA: vedere il "Centro protezione" nelle opzioni di Word.Ciò è in aggiunta a tutte le altre impostazioni di sicurezza macro fornite da Office.
Questo esempio estrarrà il codice dal documento corrente in cui risiede: esso stesso è una macro VBA (e visualizzerà se stesso e anche qualsiasi altro codice).Esiste anche una raccolta Application.vbe.VBProjects per accedere ad altri documenti.Anche se non l'ho mai fatto, presumo che un'applicazione esterna possa riuscire ad aprire file utilizzando anche questa raccolta VBProjects.La sicurezza è divertente con queste cose, quindi potrebbe essere complicata.
Mi chiedo anche quale sia ora il formato del file docm: XML come docx?Sarebbe un approccio migliore?
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
Altri suggerimenti
È possibile esportare il codice in file e quindi rileggerlo.
Ho utilizzato il codice seguente per aiutarmi a mantenere alcune macro di Excel sotto il controllo del codice sorgente (utilizzando Subversion e TortoiseSVN).Fondamentalmente esporta tutto il codice in file di testo ogni volta che salvo con l'editor VBA aperto.Metto i file di testo in subversion in modo da poter eseguire le differenze.Dovresti essere in grado di adattare/rubare parte di questo per funzionare in Word.
Il controllo del registro in CanAccessVBOM() corrisponde a "Accesso attendibile al progetto Visual Basic" nell'impostazione di sicurezza.
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