使用 VBA 刷新 Excel 中对 VBProject.VBComponents 所做的更改

发布于 2024-12-26 19:59:31 字数 1415 浏览 1 评论 0原文

我在以编程方式删除模块然后从文件中重新导入它们时,在 Excel 中遇到了一些奇怪的问题。基本上,我有一个名为 VersionControl 的模块,该模块应该将我的文件导出到预定义的文件夹,并根据需要重新导入它们。这是重新导入的代码(问题如下所述):

Dim i As Integer
Dim ModuleName As String
Application.EnableEvents = False
With ThisWorkbook.VBProject
    For i = 1 To .VBComponents.Count
        If .VBComponents(i).CodeModule.CountOfLines > 0 Then
            ModuleName = .VBComponents(i).CodeModule.Name
            If ModuleName <> "VersionControl" Then
                If PathExists(VersionControlPath & "\" & ModuleName & ".bas") Then
                    Call .VBComponents.Remove(.VBComponents(ModuleName))
                    Call .VBComponents.Import(VersionControlPath & "\" & ModuleName & ".bas")
                Else
                    MsgBox VersionControlPath & "\" & ModuleName & ".bas" & " cannot be found. No operation will be attempted for that module."
                End If
            End If
        End If
    Next i
End With

运行此代码后,我注意到有些模块不再出现,而有些模块有重复项(例如 mymodule 和 mymodule1)。在单步执行代码时,很明显一些模块在 Remove 调用后仍然存在,并且它们仍在项目中时需要重新导入。有时,这只会导致模块带有 1 后缀,但有时我同时拥有原始文件和副本。

有没有办法刷新对 RemoveImport 的调用,以便它们自行应用?我想在每个之后调用一个 Save 函数(如果 Application 对象中有一个),尽管如果导入过程中出现问题,这可能会导致损失。

有想法吗?

编辑:将标签 synchronization 更改为 version-control

I've been experiencing some strange quirks in Excel while programatically removing modules then reimporting them from files. Basically, I have a module named VersionControl that is supposed to export my files to a predefined folder, and reimport them on demand. This is the code for reimporting (the problem with it is described below):

Dim i As Integer
Dim ModuleName As String
Application.EnableEvents = False
With ThisWorkbook.VBProject
    For i = 1 To .VBComponents.Count
        If .VBComponents(i).CodeModule.CountOfLines > 0 Then
            ModuleName = .VBComponents(i).CodeModule.Name
            If ModuleName <> "VersionControl" Then
                If PathExists(VersionControlPath & "\" & ModuleName & ".bas") Then
                    Call .VBComponents.Remove(.VBComponents(ModuleName))
                    Call .VBComponents.Import(VersionControlPath & "\" & ModuleName & ".bas")
                Else
                    MsgBox VersionControlPath & "\" & ModuleName & ".bas" & " cannot be found. No operation will be attempted for that module."
                End If
            End If
        End If
    Next i
End With

After running this, I've noticed that some modules don't appear anymore, while some have duplicates (e.g. mymodule and mymodule1). While stepping through the code, it became obvious that some modules still linger after the Remove call, and they get to be reimported while still in the project. Sometimes, this only resulted having the module suffixed with 1, but sometimes I had both the original and the copy.

Is there a way to flush the calls to Remove and Import so they apply themselves? I'm thinking to call a Save function after each, if there's one in the Application object, although this can cause losses if things go wrong during import.

Ideas?

Edit: changed tag synchronization to version-control.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

浪荡不羁 2025-01-02 19:59:31

这是一个实时数组,您在迭代期间添加和删除项目,从而更改索引号。尝试向后处理数组。这是我的解决方案,没有任何错误处理:

Private Const DIR_VERSIONING As String = "\\VERSION_CONTROL"
Private Const PROJ_NAME As String = "PROJECT_NAME"

Sub EnsureProjectFolder()
    ' Does this project directory exist
    If Len(Dir(DIR_VERSIONING & PROJ_NAME, vbDirectory)) = 0 Then
        ' Create it
        MkDir DIR_VERSIONING & PROJ_NAME
    End If
End Sub

Function ProjectFolder() As String
    ' Ensure the folder exists whenever we try to access it (can be deleted mid execution)
    EnsureProjectFolder
    ' Create the required full path
    ProjectFolder = DIR_VERSIONING & PROJ_NAME & "\"
End Function

Sub SaveCodeModules()

    'This code Exports all VBA modules
    Dim i%, sName$

    With ThisWorkbook.VBProject
        ' Iterate all code files and export accordingly
        For i% = 1 To .VBComponents.count
            ' Extract this component name
            sName$ = .VBComponents(i%).CodeModule.Name
            If .VBComponents(i%).Type = 1 Then
                ' Standard Module
                .VBComponents(i%).Export ProjectFolder & sName$ & ".bas"
            ElseIf .VBComponents(i%).Type = 2 Then
                ' Class
                .VBComponents(i%).Export ProjectFolder & sName$ & ".cls"
            ElseIf .VBComponents(i%).Type = 3 Then
                ' Form
                .VBComponents(i%).Export ProjectFolder & sName$ & ".frm"
            ElseIf .VBComponents(i%).Type = 100 Then
                ' Document
                .VBComponents(i%).Export ProjectFolder & sName$ & ".bas"
            Else
                ' UNHANDLED/UNKNOWN COMPONENT TYPE
            End If
        Next i
    End With

End Sub

Sub ImportCodeModules()
    Dim i%, sName$

    With ThisWorkbook.VBProject
        ' Iterate all components and attempt to import their source from the network share
        ' Process backwords as we are working through a live array while removing/adding items
        For i% = .VBComponents.count To 1 Step -1
            ' Extract this component name
            sName$ = .VBComponents(i%).CodeModule.Name
            ' Do not change the source of this module which is currently running
            If sName$ <> "VersionControl" Then
                ' Import relevant source file if it exists
                If .VBComponents(i%).Type = 1 Then
                    ' Standard Module
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".bas"
                ElseIf .VBComponents(i%).Type = 2 Then
                    ' Class
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".cls"
                ElseIf .VBComponents(i%).Type = 3 Then
                    ' Form
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".frm"
                ElseIf .VBComponents(i%).Type = 100 Then
                    ' Document
                    Dim TempVbComponent, FileContents$
                    ' Import the document. This will come in as a class with an increment suffix (1)
                    Set TempVbComponent = .VBComponents.Import(ProjectFolder & sName$ & ".bas")

                    ' Delete any lines of data in the document
                    If .VBComponents(i%).CodeModule.CountOfLines > 0 Then .VBComponents(i%).CodeModule.DeleteLines 1, .VBComponents(i%).CodeModule.CountOfLines

                    ' Does this file contain any source data?
                    If TempVbComponent.CodeModule.CountOfLines > 0 Then
                        ' Pull the lines into a string
                        FileContents$ = TempVbComponent.CodeModule.Lines(1, TempVbComponent.CodeModule.CountOfLines)
                        ' And copy them to the correct document
                        .VBComponents(i%).CodeModule.InsertLines 1, FileContents$
                    End If

                    ' Remove the temporary document class
                    .VBComponents.Remove TempVbComponent
                    Set TempVbComponent = Nothing

                Else
                    ' UNHANDLED/UNKNOWN COMPONENT TYPE
                End If
            End If
            Next i
        End With

End Sub

This is a live array, you are adding and removing items during iteration thereby changing the index numbers. Try processing the array backwards. Here is my solution without any error handling:

Private Const DIR_VERSIONING As String = "\\VERSION_CONTROL"
Private Const PROJ_NAME As String = "PROJECT_NAME"

Sub EnsureProjectFolder()
    ' Does this project directory exist
    If Len(Dir(DIR_VERSIONING & PROJ_NAME, vbDirectory)) = 0 Then
        ' Create it
        MkDir DIR_VERSIONING & PROJ_NAME
    End If
End Sub

Function ProjectFolder() As String
    ' Ensure the folder exists whenever we try to access it (can be deleted mid execution)
    EnsureProjectFolder
    ' Create the required full path
    ProjectFolder = DIR_VERSIONING & PROJ_NAME & "\"
End Function

Sub SaveCodeModules()

    'This code Exports all VBA modules
    Dim i%, sName$

    With ThisWorkbook.VBProject
        ' Iterate all code files and export accordingly
        For i% = 1 To .VBComponents.count
            ' Extract this component name
            sName$ = .VBComponents(i%).CodeModule.Name
            If .VBComponents(i%).Type = 1 Then
                ' Standard Module
                .VBComponents(i%).Export ProjectFolder & sName$ & ".bas"
            ElseIf .VBComponents(i%).Type = 2 Then
                ' Class
                .VBComponents(i%).Export ProjectFolder & sName$ & ".cls"
            ElseIf .VBComponents(i%).Type = 3 Then
                ' Form
                .VBComponents(i%).Export ProjectFolder & sName$ & ".frm"
            ElseIf .VBComponents(i%).Type = 100 Then
                ' Document
                .VBComponents(i%).Export ProjectFolder & sName$ & ".bas"
            Else
                ' UNHANDLED/UNKNOWN COMPONENT TYPE
            End If
        Next i
    End With

End Sub

Sub ImportCodeModules()
    Dim i%, sName$

    With ThisWorkbook.VBProject
        ' Iterate all components and attempt to import their source from the network share
        ' Process backwords as we are working through a live array while removing/adding items
        For i% = .VBComponents.count To 1 Step -1
            ' Extract this component name
            sName$ = .VBComponents(i%).CodeModule.Name
            ' Do not change the source of this module which is currently running
            If sName$ <> "VersionControl" Then
                ' Import relevant source file if it exists
                If .VBComponents(i%).Type = 1 Then
                    ' Standard Module
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".bas"
                ElseIf .VBComponents(i%).Type = 2 Then
                    ' Class
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".cls"
                ElseIf .VBComponents(i%).Type = 3 Then
                    ' Form
                    .VBComponents.Remove .VBComponents(sName$)
                    .VBComponents.Import fileName:=ProjectFolder & sName$ & ".frm"
                ElseIf .VBComponents(i%).Type = 100 Then
                    ' Document
                    Dim TempVbComponent, FileContents$
                    ' Import the document. This will come in as a class with an increment suffix (1)
                    Set TempVbComponent = .VBComponents.Import(ProjectFolder & sName$ & ".bas")

                    ' Delete any lines of data in the document
                    If .VBComponents(i%).CodeModule.CountOfLines > 0 Then .VBComponents(i%).CodeModule.DeleteLines 1, .VBComponents(i%).CodeModule.CountOfLines

                    ' Does this file contain any source data?
                    If TempVbComponent.CodeModule.CountOfLines > 0 Then
                        ' Pull the lines into a string
                        FileContents$ = TempVbComponent.CodeModule.Lines(1, TempVbComponent.CodeModule.CountOfLines)
                        ' And copy them to the correct document
                        .VBComponents(i%).CodeModule.InsertLines 1, FileContents$
                    End If

                    ' Remove the temporary document class
                    .VBComponents.Remove TempVbComponent
                    Set TempVbComponent = Nothing

                Else
                    ' UNHANDLED/UNKNOWN COMPONENT TYPE
                End If
            End If
            Next i
        End With

End Sub
望笑 2025-01-02 19:59:31

OP在这里...我设法解决了这个奇怪的问题,但我还没有找到真正的解决方案。这就是我所做的。

  1. 发布问题后我的第一次尝试是这样的(剧透:它几乎有效):

    继续将删除与导入分开,但使用相同的过程。这意味着我有 3 个循环 - 一个用于存储模块名称列表(作为纯字符串),另一个用于删除模块,另一个用于从文件导入模块(基于存储在上述列表中的名称) 。

    问题:当删除循环结束时,某些模块仍在项目中。为什么?我无法解释。我会将其标记为愚蠢的问题。 1。然后,我尝试将每个模块的 Remove 调用放置在一个循环内,该循环不断尝试删除该单个模块,直到在项目中找不到它为止。对于某个模块,这陷入了无限循环 - 我不知道该特定模块有什么特别之处。

    我最终发现,只有在 Excel 找到一些时间来理清思路后,这些模块才真正被删除。这不适用于 Application.Wait()。当前运行的 VBA 代码实际上需要结束才能发生这种情况。奇怪。

  2. 第二次解决方法尝试(剧透:再次,它几乎有效):

    为了在删除后给 Excel 所需的喘息时间,我将删除循环放置在按钮单击处理程序中(没有“调用删除直到它消失”循环),并将导入循环放置在另一个按钮的单击处理程序中。当然,我需要模块名称列表,因此我将其设为全局字符串数组。它是在删除循环之前的单击处理程序中创建的,并且应该由导入循环访问。应该有用吧?

    问题:当导入循环开始时(在另一个单击处理程序内),上述字符串数组为空。当删除循环结束时它肯定就在那里 - 我用 Debug.Print 打印了它。我猜想它是通过删除而被取消分配的(??)。这将是一个愚蠢的问题。 2.如果没有包含模块名称的字符串数组,导入循环不会执行任何操作,因此此解决方法失败。

  3. 最终的、功能性的解决方法。这个有效。

    我采用了第 2 号解决方法,并且没有将模块名称存储在字符串数组中,而是将它们存储在辅助表的一行中(我将此表称为“Devel”)。

就是这样。如果有人可以解释愚蠢的问题不。 1 号和愚蠢的问题号。 2、我求你了,就这么做吧。他们可能没那么愚蠢——我仍处于 VBA 的起步阶段,但我对其他(理智和现代)语言的编程有扎实的了解。

我可以添加代码来说明愚蠢的问题。 2,但是这个答案已经很长了。如果我所做的不清楚,我会将其放在这里。

OP here... I managed to work around this weird issue, but I haven't found a true solution. Here's what I did.

  1. My first attempt after posting the question was this (spoiler: it almost worked):

    Keep removing separate from importing, but in the same procedure. This means that I had 3 loops - one to store a list of the module names (as plain strings), another to remove the modules, and another to import the modules from files (based on the names that were stored in the aforementioned list).

    The problem: some modules were still in the project when the removal loop ended. Why? I cannot explain. I'll mark this as stupid problem no. 1. I then tried placing the Remove call for every module inside a loop that kept trying to remove that single module until it couldn't find it in the project. This got stuck in an infinite loop for a certain module - I can't tell what's so special about that particular one.

    I eventually figured out that the modules were only truly removed after Excel finds some time to clear its thoughts. This didn't work with Application.Wait(). The currently running VBA code actually needed to end for this to happen. Weird.

  2. Second work-around attempt (spoiler: again, it almost worked):

    To give Excel the required time to breathe after removals, I placed the removing loop inside a button click handler (without the "call Remove until it's gone" loop), and the importing loop in the click handler of another button. Of course, I needed the list of module names, so I made it a global array of strings. It was created in the click handler, before the removal loop, and it was supposed to be accessed by the importing loop. Should have worked, right?

    The problem: The aforementioned string array was empty when the importing loop started (inside the other click handler). It was definitely there when the removal loop ended - I printed it with Debug.Print. I guess it got de-allocated by the removals (??). This would be stupid problem no. 2. Without the string array containing the module names, the importing loop did nothing, so this work-around failed.

  3. Final, functional workaround. This one works.

    I took Work-around number 2 and, instead of storing the module names in a string array, I stored them in a row of an auxiliary sheet (I called this sheet "Devel").

This was it. If anyone can explain stupid problem no. 1 and stupid problem no. 2, I beg you, do so. They're probably not that stupid - I'm still at the beginning with VBA, but I have solid knowledge of programming in other (sane and modern) languages.

I could add the code to illustrate stupid problem no. 2, but this answer is already long. If what I did was not clear, I will place it here.

冷情妓 2025-01-02 19:59:31

为了避免导入时重复,我使用以下策略修改了脚本:

  • 重命名现有模块
  • 导入模块
  • 删除重命名的模块

我在导入过程中不再有重复。


Sub SaveCodeModules()

'This code Exports all VBA modules
Dim i As Integer, name As String

With ThisWorkbook.VBProject
For i = .VBComponents.Count To 1 Step -1

    name = .VBComponents(i).CodeModule.name

    If .VBComponents(i).Type = 1 Then
        ' Standard Module
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".module"
    ElseIf .VBComponents(i).Type = 2 Then
        ' Class
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".classe"
    ElseIf .VBComponents(i).Type = 3 Then
        ' Form
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".form"
    Else
        ' DO NOTHING
    End If
Next i
End With

End Sub

Sub ImportCodeModules()

Dim i As Integer
Dim delname As String
Dim modulename As String

With ThisWorkbook.VBProject
For i = .VBComponents.Count To 1 Step -1

    modulename = .VBComponents(i).CodeModule.name

    If modulename <> "VersionControl" Then

        delname = modulename & "_to_delete"

        If .VBComponents(i).Type = 1 Then
            ' Standard Module
            .VBComponents(modulename).name = delname
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".module"
            .VBComponents.Remove .VBComponents(delname)

        ElseIf .VBComponents(i).Type = 2 Then
            ' Class
            .VBComponents(modulename).name = delname
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".classe"
            .VBComponents.Remove .VBComponents(delname)

        ElseIf .VBComponents(i).Type = 3 Then
            ' Form
            .VBComponents.Remove .VBComponents(modulename)
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".form"
        Else
            ' DO NOTHING
        End If

    End If
Next i

End With

End Sub

要粘贴到新模块“VersionControl”中的代码

To avoid duplicate when importing, I modified the script with following strategy :

  • Rename existing module
  • Import module
  • Delete renamed module

I don't have anymore duplicate during import.


Sub SaveCodeModules()

'This code Exports all VBA modules
Dim i As Integer, name As String

With ThisWorkbook.VBProject
For i = .VBComponents.Count To 1 Step -1

    name = .VBComponents(i).CodeModule.name

    If .VBComponents(i).Type = 1 Then
        ' Standard Module
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".module"
    ElseIf .VBComponents(i).Type = 2 Then
        ' Class
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".classe"
    ElseIf .VBComponents(i).Type = 3 Then
        ' Form
        .VBComponents(i).Export Application.ThisWorkbook.Path & "\trunk\" & name & ".form"
    Else
        ' DO NOTHING
    End If
Next i
End With

End Sub

Sub ImportCodeModules()

Dim i As Integer
Dim delname As String
Dim modulename As String

With ThisWorkbook.VBProject
For i = .VBComponents.Count To 1 Step -1

    modulename = .VBComponents(i).CodeModule.name

    If modulename <> "VersionControl" Then

        delname = modulename & "_to_delete"

        If .VBComponents(i).Type = 1 Then
            ' Standard Module
            .VBComponents(modulename).name = delname
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".module"
            .VBComponents.Remove .VBComponents(delname)

        ElseIf .VBComponents(i).Type = 2 Then
            ' Class
            .VBComponents(modulename).name = delname
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".classe"
            .VBComponents.Remove .VBComponents(delname)

        ElseIf .VBComponents(i).Type = 3 Then
            ' Form
            .VBComponents.Remove .VBComponents(modulename)
            .VBComponents.Import Application.ThisWorkbook.Path & "\trunk\" & modulename & ".form"
        Else
            ' DO NOTHING
        End If

    End If
Next i

End With

End Sub

Code to be pasted in a new module "VersionControl"

百善笑为先 2025-01-02 19:59:31

我已经为这个问题苦苦挣扎了好几天。我构建了一个与此类似的原始版本控制系统,但没有使用数组。版本控制模块在 Workbook_Open 上导入,然后调用启动过程来导入版本控制模块中列出的所有模块。一切工作都很好,除了 Excel 开始创建重复的版本控制模块,因为它会在删除现有模块完成之前导入新模块。我通过将删除附加到前一个模块来解决这个问题。那么问题是仍然有两个同名的过程。 Chip Pearson 有一些用于以编程方式删除过程的代码,因此我从旧版本控制模块中删除了启动代码。尽管如此,我还是遇到了一个问题,即在调用启动过程时该过程尚未被删除。我终于在另一个堆栈溢出线程上找到了一个解决方案,它非常简单,让我想把头伸进墙里。我所要做的就是通过使用

Application.OnTime Now + TimeValue("00:00:01"), "StartUp"    

Everything Works Perfect Now 来改变我调用启动程序的方式。不过,我可能会回去删除现在多余的模块重命名并删除第二个过程,看看这是否可以解决我原来的问题。这是解决方案的另一个线程...

Excel VBA 代码模块的源代码控制

I've been struggling with this issue for days now. I built a crude version control system similar to this, though not using arrays. The version control module is imported on Workbook_Open and then the startup procedure is called to import all of the modules listed in the version control module. Everything works great except Excel started creating duplicate version control modules because it would import the new module before the deletion of the existing one finished. I worked around that by appending Delete to the previous module. The problem then being that there were still two procedures with the same name. Chip Pearson has some code for deleting a procedure programmatically, so I deleted the startup code from the older version control module. Still, I ran into an issue where the procedure had not been deleted by the time the startup procedure was called. I finally found a solution on another stack overflow thread that is so simple it makes me want to put my head through a wall. All I had to do was change the way I call my startup procedure by using

Application.OnTime Now + TimeValue("00:00:01"), "StartUp"    

Everything works perfectly now. Though, I will probably go back and delete out the now redundant renaming of the module and deleting the second procedure and see if this alone solves my original problem. Here is the other thread with the solution...

Source control of Excel VBA code modules

岁月苍老的讽刺 2025-01-02 19:59:31

不确定它是否对某人有帮助......
在 xlsm 容器中(如果将其作为 zip 文件打开),您可以找到一个名为 vbaproject.txt 的文件。您可以覆盖它以“更新”VBProject 的全部内容(所有标准模块、类模块、用户窗体、表模块和本工作簿模块)。
通过这种方法,您可以在工作簿的副本中创建“新”代码等,并最终覆盖目标工作簿中的 vbproject 文件。这也许可以避免导出/导入模块的需要以及重复的痛苦。 (抱歉,由于时间不够,没有发布代码)

Not sure if it helps somebody ...
In an xlsm container (if you open it as a zip-file) you can find a file called like vbaproject. You can overwrite this in order to "update" the whole content of the VBProject (all standardmodules, classmodules, userforms, table-modules and thisworkbook-module).
With this aproach you can create the "new" code etc. in a copy of your workbook and finally overwrite the vbproject file in the destination workbook. This maybe avoid the need to export / import modules and suffering of duplicates. (Sorry for posting no code due to lack of time)

℡寂寞咖啡 2025-01-02 19:59:31

重命名、导入和删除解决方法在我的情况下不起作用。看起来(但这纯粹是猜测)Excel 可能会将编译的对象保存在其 .XLMS 文件中,并且当重新打开该文件时,这些对象会在 ThisWorkbook_open 函数发生之前重新加载到内存中。这会导致某些模块的重命名(或删除)失败或延迟(即使尝试使用 DoEvents 调用强制重命名(或删除))。我发现的唯一解决方法是使用 .XLS 二进制格式。由于一些模糊的原因(我怀疑编译的对象没有捆绑在文件中),它对我有用。

您必须知道,在导入代码运行时,您将无法重新导入正在/已使用或引用的任何模块(重命名将失败,并出现错误 32813/模块的删除将被延迟,直到您将尝试导入,在模块名称末尾添加烦人的“1”)。但对于任何其他模块,它应该可以工作。

如果需要管理所有源代码,更好的解决方案是使用某些脚本或工具从头开始“构建”工作簿,或者切换到更适合的编程语言(即不在 Office 套件中的语言)软件;)我还没有尝试过,但你可以看看这里:源代码控制Excel VBA 代码模块

The rename, import and delete workaround didn't work in my case. It seems (but this is pure speculation) that Excel might save the compiled objects in its .XLMS file, and when this file is re-opened these objects are reloaded in memory before the ThisWorkbook_open function occurs. And this leads the renaming (or removal) of certain modules to fail or be delayed (even when trying to force it with the DoEvents call). The only workaround I found is to use the .XLS binary format. For some obscure reason (I suspect the compiled objects are not bundled in the file), it works for me.

You have to know that you won't be able to re-import any module being/having been used or referenced at the time your import code runs (renaming will fail with error 32813/removal of the module will be delayed until after you will try to import, adding annoying '1's at the end of your module names). But for any other module, it should work.

If all of your source code needs to be managed, a better solution would be to "build" your workbook from scratch using some script or tool, or switch to a better suited programming language (i.e. one that doesn't live inside an Office suite software ;) I haven't tried it but you could look here: Source control of Excel VBA code modules.

南街女流氓 2025-01-02 19:59:31

我在这个问题上花了相当长的时间。关键是,任何被删除的 VBComponent 实际上都不会在执行它的进程结束之前被删除。因为重命名是立即完成的,所以这是选择新导入组件的方法。

顺便说一句:对于版本控制,我使用 Github,它易于使用且非常完美,特别是当仅导出更改的组件时 - 我所做的。
感兴趣的人可以查看公共 Github 存储库 Excel-VB-Components -管理服务或相关帖子以编程方式更新或同步 Excel VB-Project 组件的 VBA 代码

I've spent quite some time on this issue. The point is that any VBComponent deleted is in fact not deleted before the process which did it has ended. Because rename is done immediately this is the method of choice to get the new imported component out of the way.

By the way: For the versioning I use Github which is easy to use and just perfect, specifically when only changed components are exported - what I do.
Those interested may have a look at the public Github repo Excel-VB-Components-Management-Services or at the related post Programmatically updating or synchronizing VBA code of Excel VB-Project Components

疾风者 2025-01-02 19:59:31

与这个问题的标题相关的另一种情况:

我在循环中添加组件(来自python):

for file in files_to_import:
    project.VBComponents.Import(file)

这有时会损坏工作簿,有时不会。
它看起来就像这样简单:

for file in files_to_import:
    project.VBComponents.Import(file)
    print(project.VBComponents.Count)

帮助“刷新”vbproject 并解决问题

Another situation related to the title of this question:

I was adding components in a loop (from python):

for file in files_to_import:
    project.VBComponents.Import(file)

This sometimes corrupted the workbook, sometimes did not.
It appears something as simple as this:

for file in files_to_import:
    project.VBComponents.Import(file)
    print(project.VBComponents.Count)

helps "flush" the vbproject and fix the issue ????

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文