是否可以在Excel VBA中更改另一个模块中的Module的源代码

时间:2013-02-11 11:58:16

标签: excel vba excel-vba

我有一个Excel .xlam文件,在功能区中添加一个按钮来执行以下操作:

  1. 扫描ActiveSheet以获取一些预设参数
  2. 获取我的源文本(字符串值,直接在VBA模块中硬编码)并使用从步骤1检索的参数替换指定区域
  3. 生成包含计算文本的文件
  4. 我以这种方式保存源文本,因为它可以受密码保护,我不需要在.xlam文件所在的任何地方拖动另一个文件。源文本保存在一个名为“Source”的单独模块中,看起来像这样(感谢VBA没有Heredocs):

    'Source Module
    Public Function GetSource() As String
        Dim s As String
        s = ""
    
        s = s & "This is the first line of my source text" & vbCrLf
        s = s & "This is a parameter {par1}" & vbCrLf
        s = s & "This is another line" & vbCrLf
    
        GetSource = s
    End Function
    

    该功能正常。我的问题是如果我想更新源文本,我现在必须在.xlam文件中手动执行此操作。我想要做的是在另一个模块中构建类似Sub ImportSource()的东西,它将解析一些文件,以编程方式重建“源”模块,然后用我计算的源代码替换该模块。我不知道的是,是否/如何用字符串变量中的某个值替换模块的源代码。

    这就像元编程在最糟糕的情况下,哲学上我反对这样做是我的核心。但实际上,我想知道是否以及如何做到这一点。

3 个答案:

答案 0 :(得分:5)

我现在意识到,您真正想要做的是以VBA可访问的方式在文档中存储一些值,但这对电子表格的用户来说是不可读的。根据Charles Williams建议将值存储在工作表的命名区域中,并解决您不希望用户访问这些值的问题,您必须加密字符串......

this article中描述了执行此操作的“正确方法” - 但这是相当多的工作。

发现了一个更短的例程here。它只是使用简单的XOR加密和硬编码密钥 - 但它应该足以满足“大多数用途”。密钥将被“隐藏”在您的宏中,因此无法通过窥探眼睛(嗯,不容易)。

现在您可以使用此功能,让我们称之为encrypt(string),将您的字符串转换为电子表格中的值:

range("mySecretCell").value = encrypt("The lazy dog jumped over the fox")

当您需要使用它时,您可以使用

Public Function GetSource()
    GetSource = decrypt(Range("mySecretCell").value)
End Function

如果您使用XOR版本(第二个链接),encryptdecrypt将是相同的功能......

这会更好地满足您的需求吗?

答案 1 :(得分:2)

正如@brettdj已经指出他的cpearson.com/excel/vbe.aspx 链接,您可以使用 VBA可扩展性库以编程方式更改为VBA模块的代码!要使用它,请在VBA编辑器中选择库工具 - > 参考。请注意,您还需要更改信任中心的选项,然后选择: Excel选项 - > 信任中心 - > 信任中心设置 - > 宏设置 - > 信任对VBA项目对象模型的访问

然后类似下面的代码应该做的工作:

Private mCodeMod As VBIDE.CodeModule

Sub UpdateModule()
    Const cStrModuleName As String = "Source"

    Dim VBProj As VBIDE.VBProject
    Dim VBComp As VBIDE.VBComponent

    Set VBProj = Workbooks("___YourWorkbook__").VBProject

    'Delete the module
    VBProj.VBComponents.Remove VBProj.VBComponents(cStrModuleName)

    'Add module
    Set VBComp = VBProj.VBComponents.Add(vbext_ct_StdModule)
    VBComp.Name = cStrModuleName
    Set mCodeMod = VBComp.CodeModule

    'Add procedure header and start
    InsertLine "Public Function GetSource() As String"
    InsertLine "Dim s As String", 1
    InsertLine ""

    'Add text
    InsertText ThisWorkbook.Worksheets("Sourcetext") _
        .Range("___YourRange___")

    'Finalize procedure
    InsertLine "GetSource = s", 1
    InsertLine "End Function"

End Sub

Private Sub InsertLine(strLine As String, _
    Optional IndentationLevel As Integer = 0)
    mCodeMod.InsertLines _
        mCodeMod.CountOfLines + 1, _
        Space(IndentationLevel * 4) & strLine
End Sub

Private Sub InsertText(rngSource As Range)
    Dim rng As Range
    Dim strCell As String, strText As String
    Dim i As Integer

    Const cLineLength = 60
    For Each rng In rngSource.Cells
        strCell = rng.Value
        For i = 0 To Len(strCell) \ cLineLength
            strText = Mid(strCell, i * cLineLength, cLineLength)
            strText = Replace(strText, """", """""")
            InsertLine "s = s & """ & strText & """", 1
        Next i
    Next rng
End Sub

答案 2 :(得分:1)

您可以通过编程方式“导出”和“导入”.bas文件。要做你想要的,那就必须是方法。我不相信可以修改内存中的代码。见this article