Программное извлечение кода макроса (VBA) из документов Word 2007
-
09-06-2019 - |
Вопрос
Можно ли извлечь весь код VBA из документа Word 2007 "docm" с помощью API?
Я нашел, как вставить код VBA во время выполнения и как удалить весь код VBA, но не извлекать фактический код в поток или строку, которые я могу сохранить (и вставить в другие документы в будущем).
Будем признательны за любые советы или ресурсы.
Редактировать:спасибо всем, Трубкозубответ был именно тем, что я искал.Я преобразовал его код в 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;
}
Решение
Вам нужно будет добавить ссылку на 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
Другие советы
Вы могли бы экспортировать код в файлы, а затем прочитать их обратно.
Я использовал приведенный ниже код, чтобы помочь мне сохранить некоторые макросы Excel под управлением версиями (используя Subversion и TortoiseSVN).По сути, он экспортирует весь код в текстовые файлы каждый раз, когда я сохраняю его при открытом редакторе VBA.Я поместил текстовые файлы в subversion, чтобы иметь возможность выполнять различия.Вы должны быть в состоянии адаптировать / украсть кое-что из этого для работы в 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