Добавление нового и удаление старого VBA для всех книг в папке - PullRequest
0 голосов
/ 30 января 2019

У меня около 60 рабочих книг с несколькими модулями, и мне нужно удалить одну подпрограмму в одном модуле, а затем добавить код в конкретную рабочую таблицу.

В настоящее время у меня работает код каждый раз, когда вы открываете рабочую книгу с запросом на запуск и архивирование данных на другой лист, это работает.Проблема в том, что мы находимся в рабочих книгах несколько раз, поэтому каждый раз, когда мы их открываем, мы должны ответить на вопрос.

Я нашел более элегантный способ попросить архивировать, когда я перехожу к первому рабочему листу, где мы собираемся изменить данные в конце месяца.Только когда мы откроем это, нам нужно заархивировать старые данные.Иногда мы идем сюда, чтобы посмотреть на данные, но это не обычно.Теперь у меня есть новый код для конкретной рабочей таблицы, использующий команду select, которая работает.

Я пытаюсь обновить код во всех моих книгах без необходимости открывать их 1 на 1 и вносить изменения, копировать,вставить, удалить, сохранить, открыть следующий файл, повторить.

'code to remove from module named ArchiveHistoricalData  
Sub Auto_Open()
AskArchive
End Sub


'Code to add to worksheet named Data Dump
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
AskArchive
End Sub

Я хотел бы удалить первый подпункт, а затем добавить второй подпункт к определенному рабочему листу (назван одинаково во всех книгах).Тогда, если у меня будут изменения в будущем, я могу легко обновить все мои рабочие книги другими изменениями.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Размещение другого ответа, структурированного как обобщенные инструменты для удаления и / или добавления или замены любого количества процедур из любого количества файлов.Как упоминалось ранее, предполагается, что должен быть включен доверительный доступ к проекту Visual Basics.

В новом файле Excel с добавленной ссылкой на Microsoft Visual Basic для расширяемости приложения добавьте модуль с именем «Copy_Module».В вашем случае скопируйте код Worksheet_SelectionChange в модуль с именем «Copy_Module».

Его функция AddReplaceProc будет копировать любую процедуру из модуля с именем «Copy_Module» в исходной книге, в то время как функция DeleteProc удалит процедуру.

Sub test4()
Dim Wb As Workbook, ws As Worksheet
Dim Path As String, Fname As String
Dim Fno As Long

Path = "C:\Users\User\Documents\TestFolder\"
Fname = Dir(Path & "*.xlsm")

    Fno = 1
    Do While Fname <> ""
    Set Wb = Application.Workbooks.Open(Path & Fname)

        If Wb.VBProject.Protection = vbext_pp_none Then
        Set ws = ThisWorkbook.ActiveSheet
        Fno = Fno + 1
        ws.Cells(Fno, 1).Value = Fname
        'ws.Cells(Fno, 2).Value = AddReplaceProc(Wb, "ArchiveHistoricalData", "DoStuff2")
        ws.Cells(Fno, 2).Value = DeleteProc(Wb, "ArchiveHistoricalData", "Auto_Open")
        ws.Cells(Fno, 3).Value = AddReplaceProc(Wb, Wb.Worksheets("Data Dump").CodeName, "Worksheet_SelectionChange")
        Wb.Close True
        Else
        Wb.Close False
        End If

    Fname = Dir
    Loop
End Sub
Private Function DeleteProc(Wb As Workbook, CompName As String, ProcName As String) As Boolean
Dim Vbc As CodeModule, Vbcomp As VBComponent
DeleteProc = False
    For Each Vbcomp In Wb.VBProject.VBComponents
        If Vbcomp.Name = CompName Then
        Set Vbc = Vbcomp.CodeModule
            On Error GoTo XExit
            If Vbc.ProcStartLine(ProcName, 0) > 0 Then
            Vbc.DeleteLines Vbc.ProcStartLine(ProcName, 0), Vbc.ProcCountLines(ProcName, 0)
            DeleteProc = True
            Exit For
            End If
        End If
    Next Vbcomp
XExit: On Error GoTo 0
End Function
Private Function AddReplaceProc(Wb As Workbook, CompName As String, ProcName As String) As Boolean
Dim Vbc As CodeModule, Vbcomp As VBComponent
Dim VbcSrc As CodeModule, StLine As Long, EndLine As Long
Dim i As Long, X As Long
'Check for older version of the procedure and delete the same before coping new version
AddReplaceProc = DeleteProc(Wb, CompName, ProcName)
Debug.Print "Old Proc " & ProcName & " Found and Deleted : " & AddReplaceProc
AddReplaceProc = False

    For Each Vbcomp In Wb.VBProject.VBComponents
        If Vbcomp.Name = CompName Then
        Set Vbc = Vbcomp.CodeModule
        Set VbcSrc = ThisWorkbook.VBProject.VBComponents("Copy_Module").CodeModule
        StLine = VbcSrc.ProcStartLine(ProcName, 0)
        EndLine = StLine + VbcSrc.ProcCountLines(ProcName, 0) - 1
            X = 0
            For i = StLine To EndLine
            X = X + 1
            Vbc.InsertLines X, VbcSrc.Lines(i, 1)
            Next i
        AddReplaceProc = True
        Exit For
        End If
    Next Vbcomp

End Function

Надлежащая осторожность обязательна для этого типа дистанционных изменений.Всегда разумно сначала попробовать код только для копий целевых файлов и подтвердить правильность работы и т. Д.
Он работает только с файлами с незащищенными проектами VBA.Для файлов с защищенными файлами VBA см. Сообщение SO Снять защиту VBProject с кода VB .

0 голосов
/ 30 января 2019

Попробуйте код из любой книги (не в той же целевой папке) модуля.Добавьте ссылку на Microsoft Visual Basic для расширения приложений.и / или сделать vbext_pk_Proc как 0.

Sub test3()
Dim ws As Workbook
Dim Vbc As CodeModule
Dim Path As String, Fname As String

Dim Wx As Worksheet
Dim HaveAll As Boolean
Dim VbComp As VBComponent


Path = "C:\Users\User\Documents\TestFolder\"
Fname = Dir(Path & "*.xlsm")

    Do While Fname <> ""
'    Debug.Print Fname
    Set ws = Application.Workbooks.Open(Path & Fname)
    HaveAll = False

         For Each VbComp In ws.VBProject.VBComponents
            If VbComp.Name = "ArchiveHistoricalData" Then
                'used erron handler instead of iterating through all the lines for keeping code short
                On Error GoTo failex
                If VbComp.CodeModule.ProcStartLine("Auto_Open", 0) > 0 Then
                HaveAll = True
failex:         Resume failex2
failex2:        On Error GoTo 0
                Exit For
                End If
             End If
         Next VbComp


         If HaveAll Then
         HaveAll = False
         For Each Wx In ws.Worksheets
            If Wx.Name = "Data Dump" Then
            HaveAll = True
            Exit For
            End If
         Next Wx
         End If


        If HaveAll Then
        Set Vbc = ws.VBProject.VBComponents("ArchiveHistoricalData").CodeModule
        Vbc.DeleteLines Vbc.ProcStartLine("Auto_Open", vbext_pk_Proc), Vbc.ProcCountLines("Auto_Open", vbext_pk_Proc)
        Set Vbc = ws.VBProject.VBComponents(ws.Worksheets("Data Dump").CodeName).CodeModule
        Vbc.InsertLines 1, "Private Sub Worksheet_SelectionChange(ByVal Target As Range)"
        Vbc.InsertLines 2, "AskArchive"
        Vbc.InsertLines 3, "End Sub"
        ws.Close True
        Else
        ws.Close False
        End If
    Debug.Print Fname, HaveAll

    Fname = Dir
    Loop

End Sub

Однако в коде возникнет ошибка, если указанные рабочие листы, модули кода и процедуры недоступны.Пожалуйста, будьте внимательны, если не подтверждено наличие указанных рабочих листов, модулей кода и процедур во всех целевых файлах. (может использовать обработчик ошибок или проверить наличие листов, программных модулей и процедур, выполнив итерацию после открытия целевого файла и пропустить соответственно) .Также должен быть включен Trust Access To Visual Basics Project.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...