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
As Chip Pearson stated, the only way to manage components in a Workbook without conflict is to use code from within another Workbook. I have put everything I need into a CompMan.xlam Workbook which I use as Add-In. It allows me to export all modules from a Workbook whenever it is saved by the simple code lines:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
#If DevTest Then
mCompMan.ExportAll ThisWorkbook
#End If
End Sub
By this I never again loose any VBA work and moreover any module is available for import into any other Workbook. I should add that I keep Workbooks with Macros in dedicated folders - at least for code work.
I had the same issue with PowerPoint, but I guess the solution could apply to any Microsoft Office application implementing VBA.
I stopped having issues after I did Remove
in a separate procedure:
Public Sub RemoveVBComponent(ioVBComponents As VBComponents, ioVBComponent As VBComponent)
Call ioVBComponents.Remove(ioVBComponent)
End Sub
that I called this way:
With ToVBProject
Call RemoveVBComponent(.VBComponents,.VBComponents.Item(ModuleName))
End With
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.
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
It's been quite a while since this question has been asked but I think I came up with something which has not been mentioned before.
Since the modules will not be deleted until the procedure ends, a possible solution is to actually let the procedure end and then call the import procedure via Application.onTime
.
So, for example
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
I have struggled with this problem for many months and have finally found a solution thanks to Rob Bovey (http://www.apps-pro.com/).
The trick is to use the Application.OnTime
function to call a second procedure with the code you want to run after deleting the code modules.
Application.OnTime Now(), "Your_Procedure_Part2"
This seems to mimic the VBA code stopping and restarting. Any code after this line in the calling procedure will not be run.