【问题标题】:Is it possible in Excel VBA to change the source code of Module in another ModuleExcel VBA中是否可以在另一个模块中更改模块的源代码
【发布时间】:2013-02-12 06:49:58
【问题描述】:

我有一个 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() 的东西,它将解析一些文件,以编程方式重建“源”模块,然后用我计算的源代码替换该模块。我不知道是否/如何用字符串变量中的某个值替换模块的源代码。

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

【问题讨论】:

  • 您可以以编程方式“导出”和“导入”.bas 文件。要按照您的要求进行操作,就必须采用这种方法。我不相信可以修改内存中的代码。见this article
  • @Floris:应该可以。如果您将其作为答案,我可以将其标记为正确
  • 不能解决您的问题,但在 XLAM 代码中存储常量的另一种方法是将它们存储在 XLAM 工作表上的单元格(最好是命名单元格)中。
  • @CharlesWilliams:问题是如果有人知道去哪里看,他们可以看到这些值而无需 VBA 宏的密码。即使您使用密码保护工作表,您仍然可以使用公式从另一个工作表访问它的值
  • 好吧,除了加密的工作簿之外,所有 Excel 和 VBA 的安全性都很薄弱,而且很容易被破解,但是除非您至少知道内部工作表的名称,否则您无法访问 XLA 内工作表上的单元格XLA,如果不破解 XLA,你就看不到这一点

标签: vba excel


【解决方案1】:

我现在意识到,您真正想要做的是以您的 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 为此。我实际使用这种方法会遇到的一个问题是,excel 中的单个单元格显然可以容纳不超过 65536 个字符。我的来源实际上超过 100k 个字符。但是,我想我可以以编程方式将导入拆分为多个单元格。这周晚些时候会试试这个,看看效果如何。谢谢
  • 好吧,您可以在代码中每行使用一个单元格...请注意,您的原始问题中没有暗示您将拥有如此多的文本!并感谢您的支持。
【解决方案2】:

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

然后类似下面的代码应该可以完成这项工作:

私有 mCodeMod 作为 VBIDE.CodeModule 子更新模块() 常量 cStrModuleName As String = "Source" 将 VBProj 调暗为 VBIDE.VBProject 将 VBComp 调暗为 VBIDE.VBComponent 设置 VBProj = Workbooks("___YourWorkbook__").VBProject '删除模块 VBProj.VBComponents.Remove VBProj.VBComponents(cStrModuleName) '添加模块 设置 VBComp = VBProj.VBComponents.Add(vbext_ct_StdModule) VBComp.Name = cStrModuleName 设置 mCodeMod = VBComp.CodeModule '添加程序头并开始 InsertLine "公共函数 GetSource() 作为字符串" InsertLine "Dim s As String", 1 插入行“” '添加文字 InsertText ThisWorkbook.Worksheets("Sourcetext") _ .Range("___YourRange___") '完成程序 InsertLine "GetSource = s", 1 InsertLine "结束函数" 结束子 Private Sub InsertLine(strLine As String, _ 可选 IndentationLevel As Integer = 0) mCodeMod.InsertLines _ mCodeMod.CountOfLines + 1, _ 空格(缩进级别 * 4) & strLine 结束子 Private Sub InsertText(rngSource As Range) 调暗为范围 将 strCell 调暗为字符串,将 strText 调暗为字符串 将 i 调暗为整数 常量 cLineLength = 60 对于 rngSource.Cells 中的每个 rng strCell = rng.Value 对于 i = 0 到 Len(strCell) \ cLineLength strText = Mid(strCell, i * cLineLength, cLineLength) strText = 替换(strText, """", """""") InsertLine "s = s & """ & strText & """", 1 接下来我 下一环 结束子

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 2017-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多