如果在源WB中找不到VB组件,请删除它们

时间:2018-08-17 21:27:12

标签: excel vba excel-vba module components

我正在编写一个过程,以从另一个启用宏的Excel工作簿(源)更新一个启用宏的Excel工作簿(目标)中的组件。最终结果是使目标组件(工作表,用户表单,模块等)与源组件匹配。

到目前为止,我已经成功(1)从源代码中添加了在目标位置中找不到的组件,(2)用较新的版本替换了工作表,(3)全局更新了所有模块,类模块和用户表单中的代码,以及(4)更新了各个工作表中的其他单元格公式和值。

我一直在努力的目的是删除目标源中找不到的组件。我一直在尝试各种方法,并相信我已经接近了,但是无法克服实际VBComponents.Remove行中的各种错误。这是我的代码:

    Sub UpdateDest()
    'Purpose:
    'Sources: (1) https://www.excel-easy.com/vba/examples/import-sheets.html
    '         (2) https://stackoverflow.com/questions/16174469/unprotect-vbDestProject-from-vb-code
    '         (3) https://stackoverflow.com/questions/18497527/copy-vba-code-from-a-sheet-in-one-workbook-to-another

    '=== Declare Variables
        Dim booCompFound As Boolean
        Dim cmSrc As CodeModule, cmDest As CodeModule
        Dim xlWBDest As Excel.Workbook, xlWSDest As Excel.Worksheet
        Dim xlWBSrc As Excel.Workbook, xlWSSrc As Excel.Worksheet
        Dim i As Integer, j As Integer
        Dim lngVBUnlocked As Long
        Dim vbDestComp As Object, vbDestComps As Object, vbDestProj As Object, vbDestMod As Object
        Dim vbSrcComp As Object, vbSrcComps As Object, vbSrcProj As Object, vbSrcMod As Object
        Dim modModule As Object
        Dim strDestName As String, strDestPath As String, strSrcName As String, strSrcPath As String
        Dim strUpdName As String, strUpdPath As String

        'On Error GoTo ErrorHandler
    '=== Initialize Variables and Prepare for Execution
        Application.ScreenUpdating = True
        Application.DisplayAlerts = True
        strUpdPath = ThisWorkbook.Path & "\"

    '=== (Code execution)
        '--- Select Dest and source workbooks for the update, and remove workbook, worksheet and VBA Project protection from both
        strSrcPath = Application.GetOpenFilename(Title:="Select SOURCE workbook for the update", FileFilter:="Excel Files *.xls* (*.xls*),")
        If strSrcPath = "" Then
            MsgBox "No source workbook was selected.", vbExclamation, "Sorry!"
            Exit Sub
        Else
            Set xlWBSrc = Workbooks.Open(strSrcPath)
            UnprotectAll xlWBSrc
            'For Each xlWSSrc In xlWBSrc.Worksheets
            '    xlWSSrc.Visible = xlSheetVisible
            'Next xlWSSrc
            Set vbSrcProj = xlWBSrc.VBProject
            lngVBUnlocked = UnlockProject(vbSrcProj, "FMD090")
            Debug.Print lngVBUnlocked
            If lngVBUnlocked <> 0 And lngVBUnlocked <> 2 Then
                MsgBox "The source VB Project could not be unlocked.", vbExclamation, "Error!"
                Exit Sub
            Else
                Set vbSrcComps = vbSrcProj.VBComponents
            End If
        End If
        strDestPath = Application.GetOpenFilename(Title:="Select DESTINATION workbook to update", FileFilter:="Excel Files *.xls* (*.xls*),")
        If strDestPath = "" Then
            MsgBox "No destination workbook was selected.", vbExclamation, "Sorry!"
            Exit Sub
        Else
            Set xlWBDest = Workbooks.Open(strDestPath)
            UnprotectAll xlWBDest
            'For Each xlWSDest In xlWBDest.Worksheets
            '    xlWSDest.Visible = xlSheetVisible
            'Next xlWSDest
            Set vbDestProj = xlWBDest.VBProject
            lngVBUnlocked = UnlockProject(vbDestProj, "FMD090")
            Debug.Print lngVBUnlocked
            If lngVBUnlocked <> 0 And lngVBUnlocked <> 2 Then
                MsgBox "The destination VB Project could not be unlocked.", vbExclamation, "Error!"
                Exit Sub
            Else
                Set vbDestComps = vbDestProj.VBComponents
            End If
        End If

        '--- Add components from source that are not found in destination
        For Each vbSrcComp In vbSrcComps

            Debug.Print vbSrcComp.Name
            booCompFound = False
            For Each vbDestComp In vbDestComps

                If vbSrcComp.Name = vbDestComp.Name Then
                    booCompFound = True
                    Exit For
                End If

            Next vbDestComp
            If booCompFound = False Then
                Application.EnableEvents = False
                vbSrcComp.Export strSrcPath & vbSrcComp.Name
                vbDestComps.Import strSrcPath & vbSrcComp.Name
                Kill strSrcPath & vbSrcComp.Name
                Application.EnableEvents = True
            End If

        Next vbSrcComp

        '--- Delete components in destination that are not found in source
        Set vbDestComps = vbDestProj.VBComponents
        For i = vbDestComps.Count To 1 Step -1
        'For Each vbDestComp In vbDestComps

            booCompFound = False
            For Each vbSrcComp In vbSrcComps

                Debug.Print "Src: "; vbSrcComp.Name; " Dest: "; vbDestComps(i).Name
                If vbDestComps(i).Name = vbSrcComp.Name Then
                    booCompFound = True
                    Exit For
                End If

            Next vbSrcComp
            If booCompFound = False Then
                Application.EnableEvents = False

    '>>> PROBLEM LINE
                vbDestProj.VBComponents.Remove vbDestComps(i)
    '<<<

                Application.EnableEvents = True
            End If

        'Next vbDestComp
        Next i

        '--- Replace worksheet(s) with newer versions
        strUpdName = "Lists_WS_3_1.xlsx"
        If Dir(strUpdPath & strUpdName) <> "" Then
            Application.EnableEvents = False
            Set xlWBSrc = Workbooks.Open(strUpdPath & strUpdName)
            xlWBDest.Worksheets("Lists").Visible = xlSheetVisible
            Application.DisplayAlerts = False
            xlWBDest.Worksheets("Lists").Name = "Lists_Old"
            xlWBSrc.Worksheets("Lists").Copy After:=xlWBDest.Worksheets("FYMILES")
            xlWBDest.Worksheets("Lists_Old").Delete
            xlWBSrc.Close
            Application.EnableEvents = True
        Else
            MsgBox "The file " & strUpdName & " is missing.", vbExclamation, "File Missing!"
            Exit Sub
        End If

        '--- Globally update code in modules, class modules and user forms
        For Each vbSrcComp In vbSrcComps

            Set cmSrc = vbSrcComp.CodeModule
            Debug.Print vbSrcComp.Name
            Set cmDest = vbDestComps(vbSrcComp.Name).CodeModule
            If cmSrc.CountOfLines > 0 Then
                Application.EnableEvents = False
                cmDest.DeleteLines 1, cmDest.CountOfLines  'Delete all lines in Dest component
                cmDest.AddFromString cmSrc.Lines(1, cmSrc.CountOfLines)  'Copy all lines from source component to Dest component
                Application.EnableEvents = True
            End If

        Next vbSrcComp

        '--- Update miscellaneous cell formulas and values
        Application.EnableEvents = False
        xlWBDest.Sheets("Inventory Data and July").Range("E2").Formula = "=TEXT(Lists!$O$5, " & Chr(34) & "000" & Chr(34) & ")"
        Application.EnableEvents = True

    '=== Error Handling
    ErrorHandler:
        Application.EnableEvents = True

    '=== Release Variables and Cleanup
        Application.ScreenUpdating = True
        Application.DisplayAlerts = True

    End Sub

问题代码位于'>>>问题行之后大约2/3秒。尝试删除Sheet18代码模块时,此代码行会产生运行时错误5,无效的过程调用或参数。

在运行期间,原始的Sheet16(列表)被删除,并替换为Excel编号为Sheet18的新“列表”工作表。经过一个周末的沉思,我相信问题出在组件命名上。为了解决这个问题,代码引用了组件名称,但是新表的VB属性是(Name)=(Sheet18)和Name = Lists(请注意括号)。

我现在已经尝试在每次操作后保存工作簿,而不会对错误或错误发生在结构的哪一部分进行任何更改。

目前,我正在遍历目标组件集合,并尝试在Source中找不到Destination中的组件时删除它。注释掉了原来的正向循环的残余部分,该残余部分也不起作用。我尝试了许多变体,或者得到了无效的过程调用,或者在对象中找不到属性或方法。

我已经花了一天时间玩这个。请看一下,帮我看看灯光!

我正在运行Excel 2016

1 个答案:

答案 0 :(得分:1)

在@ Comintern的评论之后,我添加了测试以确保Remove方法仅应用于非文档模块。这是用于删除模块的重写代码块:

    '--- Delete non-document components in destination that are not found in source
    Set vbDestComps = vbDestProj.VBComponents
    For Each vbDestComp In vbDestComps

        If vbDestComp.Type >= 1 And vbDestComp.Type <= 3 Then
            booCompFound = False
            For Each vbSrcComp In vbSrcComps

                Debug.Print "Src: "; vbSrcComp.Name; " Dest: "; vbDestComp.Name; " Type: "; vbDestComp.Type
                If vbDestComp.Name = vbSrcComp.Name Then
                    booCompFound = True
                    Exit For
                End If

            Next vbSrcComp
            If booCompFound = False Then
                Application.EnableEvents = False
                vbDestProj.VBComponents.Remove vbDestComp
                Application.EnableEvents = True
            End If
        End If

    Next vbDestComp