我试图使用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 then
和end if
注释掉,以便新模块的代码将覆盖现有代码,无论它是VBComp.Type
,模块仍然会一旦代码完成执行,最终会被删除,并且不会导致替换它。
奇怪的是,并非所有模块都会发生这种情况;有些实际上会在VBComponents.Remove
电话后实时删除。
我在各种论坛上看过几篇不同的帖子,并没有令人满意的解决方案。目前,我正在使用将.Remove
调用更改为:
With ToVBProject.VBComponents
.Item(ModuleName).name = ModuleName & "_remove"
.Remove .Item(ModuleName & "_remove")
End With
因此,通过更改名称,ModuleName
似乎不再存在,因此会发生.import
来电。当然,这假设没有名为ModuleName & "_remove"
的模块实际存在。
有更好的解决方案吗?
答案 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