VbComponents.Remove并不总是删除模块

时间:2013-11-05 22:18:51

标签: vba excel-vba excel

我试图使用Chip Pearson的代码通过从另一个项目导入来覆盖现有的VBA代码模块。原始代码here

我要看的特定部分是:

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

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

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

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

我在各种论坛上看过几篇不同的帖子,并没有令人满意的解决方案。目前,我正在使用将.Remove调用更改为:

的解决方法
    With ToVBProject.VBComponents
        .Item(ModuleName).name = ModuleName & "_remove"
        .Remove .Item(ModuleName & "_remove")
    End With

因此,通过更改名称,ModuleName似乎不再存在,因此会发生.import来电。当然,这假设没有名为ModuleName & "_remove"的模块实际存在。

有更好的解决方案吗?

8 个答案:

答案 0 :(得分:6)

我尝试重命名,发现它导致了工作表模块和ThisWorkbook的问题。所以我稍微修改了它,只重命名非文档模块。这看起来干净利落。

        If .Item(ModuleName).Type <> vbext_ct_Document Then
            .Item(ModuleName).Name = ModuleName & "_OLD"
            .Remove .Item(ModuleName & "_OLD")
        Else
            .Remove .Item(ModuleName)
        End If

答案 1 :(得分:1)

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

答案 2 :(得分:1)

我花了很多时间去删除/替换代码模块,以便找出哪些触发器起作用而不起作用。

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

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

Application.EnableEvents = False
....Open "workbook-fullname" ' selected in a file dialog
Application.EnableEvents = False
当之前手动打开目标工作簿(并因此作为打开的工作簿列表进行选择)时,

Code Module Management将无效,因为没有阻止执行任何VBA代码(请参阅{{3}为了实现这一目标,可以实现这一目标。当然,当Workbook_Open执行代码时,这只是一个问题。

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

删除/替换此工作簿中的代码模块&#39; *)

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

请参阅here进行清理,删除,传输,导出,导入,甚至同步,以减少繁琐,节省和可靠。即使选择错误的&#39;目标&#39;由于撤消功能,转移或删除的工作簿不是戏剧性的。

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

答案 3 :(得分:1)

我已经为这个问题苦苦挣扎了好几个月,终于有了Rob Bovey(http://www.apps-pro.com/)的帮助。

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

Application.OnTime Now(), "Your_Procedure_Part2"

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

答案 4 :(得分:1)

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

由于要等到过程结束才删除模块,所以可能的解决方案是实际上让过程结束,然后通过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

答案 5 :(得分:0)

我之前遇到过这样的事情。 &#39; DoEvents&#39;命令经常有帮助。你有没试过?

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

只要记住在循环中加入一些内容,这样在经过这么多循环之后它就会放弃。陷入无限循环可能会令人讨厌。

答案 6 :(得分: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工作,而且任何模块都可以导入任何其他Workbook。我应该补充一点,我将带有宏的工作簿保留在专用文件夹中-至少用于代码工作。

答案 7 :(得分:0)

我在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