VbComponents.Remove doesn't always remove module

匿名 (未验证) 提交于 2019-12-03 08:44:33

问题:

I'm trying to use Chip Pearson's code for overwriting an existing VBA code module with an import from another project. Original code here.

The particular section I'm looking at is:

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

But this VBComponents.Remove call will sometimes only actually take effect once VBA execution has stopped--that is, the delete operation doesn't take effect until all statements are finished, or if the code hits a breakpoint and then I stop debugging. This is a problem because of the following code for either importing a new module or replacing the existing module's code with the new module:

    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 

The module deletion hasn't taken effect yet, so VBComp is not Nothing, as far as the debugger knows. So the .import won't be called.

Even if I comment out the if VBComp.Type = vbext_ct_document then and end if so that the new module's code will overwrite the existing one no matter what VBComp.Type it is, the module will still end up getting deleted once the code finishes executing, and no import will happen to replace it.

What's odd is that this doesn't happen with all modules; some actually get deleted in real time after the VBComponents.Remove call.

I've seen several different posts about this on various forums, and no satisfactory solution. For now I'm using a workaround of changing the .Remove call to:

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

so that by changing the name, ModuleName appears to no longer exist and therefore the .import call will occur. This assumes, of course, that no module named ModuleName & "_remove" actually exists.

Is there a better solution?

回答1:

I tried the renaming and found that it caused problems with the sheet modules and ThisWorkbook. So I modified it slightly to rename only the non document modules. This seems to work cleanly.

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


回答2:

If you have code and method references in the ThisWorkbook sheet then Excel might hang on to modules and not delete them. The trick is to hide calls from Excel using Application.run("foo") instead of direct calls like foo().
This worked for me in Excel 2010



回答3:

I have ran into things like this before. The 'DoEvents' command often helps. Have you given that a shot?

Other times, I have placed the command in a do while loop and used a boolean to continually check if the command in question has succeeded. Including the DoEvents command in the loop is sometimes needed.

Just remember to put something in the loop so that after so many cycles it will give up. Getting stuck in an infinite loop can be pesky.



回答4:

I've spent endless time on removing/replacing Code Modules in order to find out what triggers works versus doesn't work.

Removing/replacing Code Modules in another Workbook

This is by far the least troubling approach and that's why I've implemented it with Code Module Management. Therein, for any yet not open Workbook, enabled to be selected in a file dialog, the Workbook is opend with:

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

Code Module Management will not work when the target Workbook had been opened manually before (and thus is presented for selection as list of open Workbooks) by not having prevented any VBA-Code from being executed (see here for ways this can be achieved). Of course this is only an issue when Workbook_Open executes code.

My conclusion: Once Macros(Subprocedures, Functions, etc.) had been executed, a copy of the VBA-Code resides in memory. Thus, any Remove will not happen before the procedure which removed the Code Module has finished. Consequently an Import considers the Code Module still existing and imports a Code Module with the same name with a numeric suffix to make its name unique. And this of cource is always the case when ...

Removing/replacing Code Modules in 'ThisWorkbook' *)

Up to now I have not found any way to achieve this - except for a Class Module not declared in any of the other Code Modules, which I've realized accidentially! . Consequently I tried to temporarily comment out all declarations before Remove. Full success! Remove and Import worked fine. But when I finally tried to un-comment the previously out-commented declaration code lines, Excel allways crashed (in both cases, .DeleteLines and .InsertLines and .ReplaceLine). Since I have not found a solution for this I've given up trying - at least for the time being.

See the Code Module Management for making Cleanup, Remove, Transfer, Export, Import, and even Synchronize much less cumbersome, save and reliable. Even selecting the wrong 'target' Workbook for a transfer or a remove is no drama because of an Undo feature.

*) The difference between ActiveWorkbook and ThisWorkbook matters here. ThisWorkbook is the Workbook in which the VBA code is executed while the ActiveWorkbook may be another one. Because normally both are identicall, not paying attention on the difference doesn't matter.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!