4

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

  1. 扫描 ActiveSheet 以获取一些预设参数
  2. 获取我的源文本(一个字符串值,直接在 VBA 模块中硬编码)并用从步骤 1 中检索到的参数替换指定区域
  3. 生成包含计算文本的文件

我以这种方式保存源文本,因为它可以受密码保护,并且我不需要在 .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()在另一个模块中构建类似的东西,它将解析一些文件,以编程方式重建“源”模块,然后用我计算的源代码替换那个模块。我不知道是否/如何用字符串变量中的某个值替换模块的源代码。

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

4

3 回答 3

5

As @brettdj already pointed out with his link to cpearson.com/excel/vbe.aspx , you can programmatically change to code of a VBA module using the VBA Extensibility library! To use it, select the library in the VBA editor Tools->References. Note that you need to also change the options in your Trust center and select: Excel Options->Trust Center->Trust Center Settings->Macro Settings->Trust access to the VBA project object model

Then something like the following code should do the job:

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
于 2013-02-11T22:49:58.407 回答
5

我现在意识到你真正想做的是以你的 VBA 可以访问的方式在你的文档中存储一些值,但是电子表格的用户是不可读的。遵循查尔斯威廉姆斯的建议,将值存储在工作表的命名范围中,并解决您不希望用户访问这些值的担忧,您必须加密字符串......

本文描述了执行此操作的“正确方法” - 但这是一项相当多的工作。

在这里可以找到一个更短的例程。它只是使用带有硬编码密钥的简单 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版本(第二个链接),encrypt并且decrypt将具有相同的功能...

是否更好地满足您的需求?

于 2013-02-11T15:07:17.970 回答
1

您可以以编程方式“导出”和“导入”.bas 文件。要按照您的要求进行操作,就必须采用这种方法。我不相信可以修改内存中的代码。看这篇文章

于 2013-02-11T12:37:41.523 回答