2013-02-11 23 views
2

我有一个Excel文件.xlam在色带增加了一个按钮来执行以下操作:是Excel VBA有可能改变模块的源代码中的另一个模块

  1. 扫描ActiveSheet一段预-set参数
  2. 以我的源文本(字符串值,硬在VBA模块直接编码的)并与来自步骤1
  3. 检索到的参数替换指定区域生成一个文件含有文本计算

我以这种方式保存源文本,因为它可以用密码保护,并且我不需要在.xlam文件遍地的任何地方拖动另一个文件。源文本保存在一个名为“源”一个独立的模块,看起来是这样的(感谢VBA不具有here文档):

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

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

+0

可以“出口”和“进口”编程.BAS文件。要做你正在问的东西,那必须是这种方法。我不相信有可能修改内存中的代码。请参阅[本文](http://communities.bentley.com/products/microstation/w/microstation__wiki/using-vba-to-programmatically-import-a-vba-projects-components-and-references-cs.aspx) – Floris 2013-02-11 12:07:47

+0

@弗洛伊斯:这应该工作。如果你把它作为答案,我可以将其标记为正确 – neelsg 2013-02-11 12:18:48

+1

并不能解决你的问题,但是在XLAM代码中存储常量的另一种方法是将它们存储在XLAM中工作表上的单元格(最好是命名单元格)中。 – 2013-02-11 12:42:28

回答

4

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

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将是相同的功能...

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

+0

+1。我实际遇到的一个问题是,在Excel中的单个单元显然不能超过65536个字符。我的来源实际上超过了10万个字符。不过,我想我可以编程方式将导入分割成多个单元格。将在本周晚些时候尝试,看看它如何。谢谢 – neelsg 2013-02-11 15:13:10

+0

那么你可以在你的代码中使用每行一个单元格...注意你的原始问题中没有暗示你会有相当多的文本!并感谢上涨。 – Floris 2013-02-11 15:16:05

1

您可以通过编程方式“导出”和“导入”.bas文件。要做你正在问的东西,那必须是这种方法。我不相信有可能修改内存中的代码。请参阅this article

+2

这是不正确的。请参阅http://www.cpearson.com/excel/vbe.aspx – brettdj 2013-02-11 12:42:37

+0

+1的建议,但似乎@brettdj对此也是正确的 – neelsg 2013-02-11 14:39:14

1

正如@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 
相关问题