14

我正在尝试使用 Chip Pearson 的代码从另一个项目的导入覆盖现有的 VBA 代码模块。原始代码在这里

我正在查看的特定部分是:

With ToVBProject.VBComponents
    .Remove .Item(ModuleName)
End With

但是这个VBComponents.Remove调用有时只会在 VBA 执行停止后才真正生效——也就是说,删除操作直到所有语句都完成后才会生效,或者如果代码遇到断点然后我停止调试。这是一个问题,因为以下代码用于导入新模块或用新模块替换现有模块的代码:

    Set VBComp = Nothing
    Set VBComp = ToVBProject.VBComponents(CompName)

    If VBComp Is Nothing Then
        ToVBProject.VBComponents.import filename:=FName
    Else
        If VBComp.Type = vbext_ct_Document Then
            'delete the module's code,
            'import a temp module,
            'copy over the temp module code,
            'delete the temp module
        End If
    End If

据调试器所知,模块删除尚未生效,因此尚未生效VBCompNothing所以.import不会被调用。

即使我注释掉if VBComp.Type = vbext_ct_document thenandend if以便新模块的代码将覆盖现有的,无论VBComp.Type它是什么,一旦代码完成执行,模块仍将最终被删除,并且不会发生替换它的导入。

奇怪的是,并非所有模块都会发生这种情况。VBComponents.Remove有些实际上在通话后被实时删除。

我在各个论坛上看到了几个关于此的不同帖子,但没有令人满意的解决方案。现在我正在使用将.Remove调用更改为的解决方法:

    With ToVBProject.VBComponents
        .Item(ModuleName).name = ModuleName & "_remove"
        .Remove .Item(ModuleName & "_remove")
    End With

这样通过更改名称,ModuleName似乎不再存在,因此.import将发生调用。当然,这是假设ModuleName & "_remove"实际上不存在名为的模块。

有更好的解决方案吗?

4

9 回答 9

10

我尝试了重命名,发现它导致工作表模块和 ThisWorkbook 出现问题。所以我稍微修改了一下,只重命名了非文档模块。这似乎很干净。

        If .Item(ModuleName).Type <> vbext_ct_Document Then
            .Item(ModuleName).Name = ModuleName & "_OLD"
            .Remove .Item(ModuleName & "_OLD")
        Else
            .Remove .Item(ModuleName)
        End If
于 2014-05-30T14:34:38.277 回答
3

自从提出这个问题以来已经有一段时间了,但我想我想出了一些以前没有提到过的东西。

由于在过程结束之前不会删除模块,因此可能的解决方案是实际让过程结束,然后通过调用导入过程Application.onTime

所以,例如

Private Sub ImportModules()
  With ThisWorkbook.VBProject.VBComponents
    .Remove .Item(ModuleName)
    Application.onTime Now + TimeValue("00:00:01"), tmpImportModules
  End With
End Sub

Public Sub tmpImportModules()
  With ThisWorkbook.VBProject.VBComponents
    .Import filename:=FName
  End With
End Sub

于 2020-04-20T10:13:13.997 回答
2

如果您在工作ThisWorkbook表中有代码和方法引用,那么 Excel 可能会挂在模块上而不是删除它们。Application.run("foo")诀窍是使用而不是直接调用来隐藏来自 Excel的调用,例如foo().
这在 Excel 2010 中对我有用

于 2015-03-17T11:30:57.887 回答
2

我花了无数时间来删除/替换代码模块,以找出哪些触发器有效,哪些无效。

删除/替换另一个工作簿中的代码模块

这是迄今为止最不麻烦的方法,这就是我使用Code Module Management实现它的原因。其中,对于任何尚未打开的工作簿,可以在文件对话框中选择,工作簿的打开方式为:

Application.EnableEvents = False
....Open "workbook-fullname" ' selected in a file dialog
Application.EnableEvents = False

当目标工作簿之前已手动打开(因此显示为打开的工作簿列表以供选择)时,代码模块管理将不起作用,因为没有阻止执行任何 VBA 代码(请参阅此处了解可以实现的方法)。当然,这只是 Workbook_Open 执行代码时的问题。

我的结论:一旦执行了宏(子过程、函数等),VBA 代码的副本就会驻留在内存中。因此,在删除代码模块的过程完成之前,任何删除都不会发生。因此,导入会认为代码模块仍然存在并导入具有相同名称且带有数字后缀的代码模块,以使其名称唯一。当然,当......

删除/替换“ThisWorkbook”中的代码模块*)

到目前为止,我还没有找到任何方法来实现这一点——除了一个没有在任何其他代码模块中声明的类模块,这是我偶然意识到的!. 因此,我试图在Remove之前暂时注释掉所有声明。圆满成功!删除导入工作正常。但是,当我最终尝试取消注释之前未注释的声明代码行时,Excel 总是崩溃(在这两种情况下,.DeleteLines.InsertLines.ReplaceLine)。由于我还没有找到解决方案,所以我放弃了尝试——至少目前是这样。

请参阅代码模块管理 ,以使清理、删除、传输、导出、导入甚至同步变得不那么繁琐、节省和可靠。由于撤消功能,即使选择错误的“目标”工作簿进行转移或删除也不是什么戏剧性的事情。

*) ActiveWorkbookThisWorkbook之间的区别在这里很重要。ThisWorkbook是执行 VBA 代码的工作簿,而ActiveWorkbook可能是另一个工作簿。因为通常两者都是相同的,所以不注意差异并不重要。

于 2015-11-26T15:53:04.560 回答
1

我已经为这个问题苦苦挣扎了好几个月,感谢 Rob Bovey ( http://www.apps-pro.com/ ) 终于找到了解决方案。

诀窍是使用该Application.OnTime函数在删除代码模块后使用要运行的代码调用第二个过程。

Application.OnTime Now(), "Your_Procedure_Part2"

这似乎模仿了 VBA 代码停止和重新启动。调用过程中此行之后的任何代码都不会运行。

于 2020-01-13T01:24:23.893 回答
1

我在使用 PowerPoint 时遇到了同样的问题,但我想该解决方案可以适用于任何实现 VBA 的 Microsoft Office 应用程序。

Remove在单独的过程中完成后,我不再遇到问题:

Public Sub RemoveVBComponent(ioVBComponents As VBComponents, ioVBComponent As VBComponent)
    Call ioVBComponents.Remove(ioVBComponent)
End Sub

我这样称呼:

With ToVBProject
    Call RemoveVBComponent(.VBComponents,.VBComponents.Item(ModuleName))
End With
于 2020-10-01T20:18:51.693 回答
0

我以前遇到过这样的事情。“DoEvents”命令通常会有所帮助。你试过了吗?

其他时候,我将命令放在 do while 循环中,并使用布尔值不断检查相关命令是否成功。有时需要在循环中包含 DoEvents 命令。

只要记住在循环中放一些东西,这样在经过这么多循环后它就会放弃。陷入无限循环可能很烦人。

于 2014-03-12T15:53:54.983 回答
0

正如 Chip Pearson 所说,管理工作簿中的组件而不发生冲突的唯一方法是使用另一个工作簿中的代码。我已将所需的所有内容放入用作加载项的 CompMan.xlam 工作簿中。它允许我从工作簿中导出所有模块,只要它由简单的代码行保存:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
#If DevTest Then
   mCompMan.ExportAll ThisWorkbook
#End If
End Sub

这样,我再也不会丢失任何 VBA 工作,而且任何模块都可用于导入任何其他工作簿。我应该补充一点,我将带有宏的工作簿保存在专用文件夹中 - 至少用于代码工作。

于 2020-01-29T19:45:55.947 回答
-1

我也有同样的问题。就我而言, .remove 在模块中的程序运行时不起作用。

所以我做了一个独立于其他vb组件的更新模块。

于 2021-12-08T18:06:52.633 回答