当前位置:  开发笔记 > 后端 > 正文

Excel VBA代码模块的源代码控制

如何解决《ExcelVBA代码模块的源代码控制》经验,为你挑选了2个好方法。

我希望能够控制我的Excel电子表格的VBA模块(目前使用的是Excel 2003 SP3),以便我可以共享和管理一堆不同电子表格使用的代码 - 因此我想重新加载它们从电子表格打开时的文件.

我有一个名为Loader.bas的模块,我用它来完成大部分驴工作(加载和卸载所需的任何其他模块) - 我希望能够尽快从文件中加载它当电子表格打开时.

我已将以下代码附加到Workbook_Open事件(在ThisWorkbook类中).

Private Sub Workbook_Open()
    Call RemoveLoader
    Call LoadLoader
End Sub

RemoveLoader(也在ThisWorkbook类中)包含以下代码:

Private Sub RemoveLoader()
    Dim y As Integer
    Dim OldModules, NumModules As Integer
    Dim CompName As String

    With ThisWorkbook.VBProject
        NumModules = ThisWorkbook.VBProject.VBComponents.Count
        y = 1
        While y <= NumModules
            If .VBComponents.Item(y).Type = 1 Then
                CompName = .VBComponents.Item(y).Name
                If VBA.Strings.InStr(CompName, "Loader") > 0 Then
                    OldModules = ThisWorkbook.VBProject.VBComponents.Count
                    .VBComponents.Remove .VBComponents(CompName)
                    NumModules = ThisWorkbook.VBProject.VBComponents.Count
                    If OldModules - NumModules = 1 Then
                        y = 1
                    Else
                        MsgBox ("Failed to remove " & CompName & " module from VBA project")
                    End If
                End If
            End If
            y = y + 1
        Wend
    End With
End Sub

这可能有点过于复杂和略显粗糙 - 但我正在尝试我能找到的所有东西来加载外部模块!

通常,当我打开电子表格时,RemoveLoader函数发现VBA项目中已经包含一个"Loader1"模块,它无法删除,并且它也无法从文件中加载新的Loader模块.

任何想法,如果我想做什么是可能的?Excel似乎非常喜欢在这些模块名称上添加1 - 无论是在加载还是删除时(我不确定哪个).



1> CodeKid..:

这里有一个很好的解决vba版本控制问题的方法:https://github.com/hilkoc/vbaDeveloper

关于这一点的好处是它会在您保存工作簿时自动导出代码.此外,当您打开工作簿时,它会导入代码.

您不需要运行任何构建脚本或maven命令,也不需要对工作簿进行任何更改.它适用于所有人.

它还解决了导入问题,其中ModName等模块作为ModName1导入到重复模块中.导入工作正常,即使多次执行也是如此.

作为奖励,它带有一个简单的代码格式化程序,允许您在VBA编辑器中编写时格式化vba代码.


1菜单将由workbook_open事件创建.为此,构建保存并关闭加载项.然后再次打开它后,将触发workbook_open事件,除非您手动禁用它:Application.EnableEvents = False 2默认情况下禁用自动导入/导出:https://github.com/hilkoc/vbaDeveloper/issues/8

2> DaveParillo..:

查看VBAMaven页面。我有一个使用相同概念的本地解决方案。我有一个带有一堆源代码,一个蚂蚁构建和一个“导入” VB脚本的公共库。Ant控制着构建,该构建接受一个空白的excel文件并将所需的代码推送到其中。@Mike绝对正确-任何重复的模块定义都会在模块名称后自动添加一个数字。同样,类模块(如在Sheet和ThisWorkbook中)需要特殊处理。您无法创建这些模块,必须读取输入文件并将缓冲区写入适当的模块。这是我当前用来执行此操作的VB脚本。包含@分隔文本的部分(即@build file @)是占位符-ant build将这些标签替换为有意义的内容。它不是完美的,但是对我有用。

''
' Imports VB Basic module and class files from the src folder
' into the excel file stored in the bin folder. 
'

Option Explicit

Dim pFileSystem, pFolder,  pPath
Dim pShell
Dim pApp, book

Dim pFileName

pFileName = "@build file@"

Set pFileSystem = CreateObject("Scripting.FileSystemObject")

Set pShell = CreateObject("WScript.Shell")
pPath = pShell.CurrentDirectory

If IsExcelFile (pFileName) Then
    Set pApp = WScript.CreateObject ("Excel.Application")
    pApp.Visible = False
    Set book = pApp.Workbooks.Open(pPath & "\build\" & pFileName)
Else
    Set pApp = WScript.CreateObject ("Word.Application")
    pApp.Visible = False
    Set book = pApp.Documents.Open(pPath & "\build\" & pFileName)
End If


'Include root source folder code if no args set
If Wscript.Arguments.Count = 0 Then
    Set pFolder = pFileSystem.GetFolder(pPath & "\src")
    ImportFiles pFolder, book
    '
    ' Get selected modules from the Common Library, if any
    @common path@@common file@
Else
    'Add code from subdirectories of src . . .
    If Wscript.Arguments(0) <> "" Then
        Set pFolder = pFileSystem.GetFolder(pPath & "\src\" & Wscript.Arguments(0))
        ImportFiles pFolder, book
    End If
End If





Set pFolder = Nothing
Set pFileSystem = Nothing
Set pShell = Nothing


If IsExcelFile (pFileName) Then
    pApp.ActiveWorkbook.Save
Else
    pApp.ActiveDocument.Save
End If

pApp.Quit
Set book = Nothing
Set pApp = Nothing


'' Loops through all the .bas or .cls files in srcFolder
' and calls InsertVBComponent to insert it into the workbook wb.
'
Sub ImportFiles(ByVal srcFolder, ByVal obj)
    Dim fileCollection, pFile
    Set fileCollection = srcFolder.Files
    For Each pFile in fileCollection
        If Right(pFile, 3) = "bas _
          Or Right(pFile, 3) = "cls _
          Or Right(pFile, 3) = "frm Then
            InsertVBComponent obj, pFile
        End If
    Next
    Set fileCollection = Nothing
End Sub


'' Inserts the contents of CompFileName as a new component in 
'  a Workbook or Document object.
'
'  If a class file begins with "Sheet", then the code is
'  copied into the appropriate code module 1 painful line at a time.
'
'  CompFileName must be a valid VBA component (class or module) 
Sub InsertVBComponent(ByVal obj, ByVal CompFileName)
    Dim t, mName
    t = Split(CompFileName, "\")
    mName = Split(t(UBound(t)), ".")
    If IsSheetCodeModule(mName(0), CompFileName) = True Then
        ImportCodeModule obj.VBProject.VBComponents(mName(0)).CodeModule, _
                         CompFileName
    Else
        If Not obj Is Nothing Then
            obj.VBProject.VBComponents.Import CompFileName
        Else
            WScript.Echo  "Failed to import " & CompFileName
        End If
    End If 
End Sub

''
' Imports the code in the file fName into the workbook object
' referenced by mName.
' @param target destination CodeModule object in the excel file
' @param fName file system file containing code to be imported
Sub ImportCodeModule (ByVal target, ByVal fName)
    Dim shtModule, code, buf    
    Dim fso
    Set fso = CreateObject("Scripting.FileSystemObject") 
    Const ForReading = 1, ForWriting = 2, ForAppending = 3
    Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

    Set buf = fso.OpenTextFile(fName, ForReading, False, TristateUseDefault)
    buf.SkipLine
    code = buf.ReadAll

    target.InsertLines 1, code
    Set fso = Nothing
End Sub


''
' Returns true if the code module in the file fName
' appears to be a code module for a worksheet.
Function IsSheetCodeModule (ByVal mName, ByVal fName)
    IsSheetCodeModule = False
    If mName = "ThisWorkbook" Then
       IsSheetCodeModule = False
    ElseIf Left(mName, 5) = "Sheet" And _
       IsNumeric(Mid (mName, 6, 1)) And _
       Right(fName, 3) = "cls Then
       IsSheetCodeModule = True
    End If
End Function

''
' Returns true if fName has a xls file extension
Function IsExcelFile (ByVal fName)
    If Right(fName, 3) = "xls" Then
        IsExcelFile = True
    Else
        IsExcelFile = False
    End If 
End Function

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有