2013-02-11 42 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 
相關問題