【问题标题】:Writing a macro that writes a macro to another Excel-file编写将宏写入另一个 Excel 文件的宏
【发布时间】:2015-05-12 13:48:37
【问题描述】:

我有一些 VBA 代码需要复制到很多工作表中(它是事件处理,所以它位于工作表中而不是模块中)。

问题:是否可以编写一个宏,让我选择所有需要修改的工作簿,然后自动将代码写入所有选定工作簿的每个工作表?

【问题讨论】:

    标签: vba


    【解决方案1】:

    没有直接的方法可以将模块从一个项目复制到另一个项目。要完成此任务,您必须从源 VBProject 导出模块,然后将该文件导入目标 VBProject。下面的代码将执行此操作。

    函数声明为:

    Function CopyModule(ModuleName As String, _
                        FromVBProject As VBIDE.VBProject, _
                        ToVBProject As VBIDE.VBProject, _
                        OverwriteExisting As Boolean) As Boolean
    

    ModuleName 是您要从一个项目复制到另一个项目的模块的名称。

    FromVBProject 是包含要复制的模块的VBProject。这是来源VBProject。

    ToVBProject 是模块要复制到的VBProject。这是目的地VBProject。

    OverwriteExisting 表示如果ModuleName 已经存在于ToVBProject 中,该怎么办。如果这是True,则现有的VBComponent 将从ToVBProject 中删除。如果这是False 并且VBComponent 已经存在,则该函数什么都不做并返回False。

    如果成功,该函数返回True,如果发生错误,则返回False。如果满足以下任一条件,该函数将返回 False:

    FromVBProject is nothing.
    ToVBProject is nothing.
    ModuleName is blank.
    FromVBProject is locked.
    ToVBProject is locked.
    ModuleName does not exist in FromVBProject.
    ModuleName exists in ToVBProject and OverwriteExisting is False.
    

    完整代码如下:

    Function CopyModule(ModuleName As String, _
        FromVBProject As VBIDE.VBProject, _
        ToVBProject As VBIDE.VBProject, _
        OverwriteExisting As Boolean) As Boolean
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        ' CopyModule
        ' This function copies a module from one VBProject to
        ' another. It returns True if successful or  False
        ' if an error occurs.
        '
        ' Parameters:
        ' --------------------------------
        ' FromVBProject         The VBProject that contains the module
        '                       to be copied.
        '
        ' ToVBProject           The VBProject into which the module is
        '                       to be copied.
        '
        ' ModuleName            The name of the module to copy.
        '
        ' OverwriteExisting     If True, the VBComponent named ModuleName
        '                       in ToVBProject will be removed before
        '                       importing the module. If False and
        '                       a VBComponent named ModuleName exists
        '                       in ToVBProject, the code will return
        '                       False.
        '
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
        Dim VBComp As VBIDE.VBComponent
        Dim FName As String
        Dim CompName As String
        Dim S As String
        Dim SlashPos As Long
        Dim ExtPos As Long
        Dim TempVBComp As VBIDE.VBComponent
    
        '''''''''''''''''''''''''''''''''''''''''''''
        ' Do some housekeeping validation.
        '''''''''''''''''''''''''''''''''''''''''''''
        If FromVBProject Is Nothing Then
            CopyModule = False
            Exit Function
        End If
    
        If Trim(ModuleName) = vbNullString Then
            CopyModule = False
            Exit Function
        End If
    
        If ToVBProject Is Nothing Then
            CopyModule = False
            Exit Function
        End If
    
        If FromVBProject.Protection = vbext_pp_locked Then
            CopyModule = False
            Exit Function
        End If
    
        If ToVBProject.Protection = vbext_pp_locked Then
            CopyModule = False
            Exit Function
        End If
    
        On Error Resume Next
        Set VBComp = FromVBProject.VBComponents(ModuleName)
        If Err.Number <> 0 Then
            CopyModule = False
            Exit Function
        End If
    
        ''''''''''''''''''''''''''''''''''''''''''''''''''''
        ' FName is the name of the temporary file to be
        ' used in the Export/Import code.
        ''''''''''''''''''''''''''''''''''''''''''''''''''''
        FName = Environ("Temp") & "\" & ModuleName & ".bas"
        If OverwriteExisting = True Then
            ''''''''''''''''''''''''''''''''''''''
            ' If OverwriteExisting is True, Kill
            ' the existing temp file and remove
            ' the existing VBComponent from the
            ' ToVBProject.
            ''''''''''''''''''''''''''''''''''''''
            If Dir(FName, vbNormal + vbHidden + vbSystem) <> vbNullString Then
                Err.Clear
                Kill FName
                If Err.Number <> 0 Then
                    CopyModule = False
                    Exit Function
                End If
            End If
            With ToVBProject.VBComponents
                .Remove .Item(ModuleName)
            End With
        Else
            '''''''''''''''''''''''''''''''''''''''''
            ' OverwriteExisting is False. If there is
            ' already a VBComponent named ModuleName,
            ' exit with a return code of False.
            ''''''''''''''''''''''''''''''''''''''''''
            Err.Clear
            Set VBComp = ToVBProject.VBComponents(ModuleName)
            If Err.Number <> 0 Then
                If Err.Number = 9 Then
                    ' module doesn't exist. ignore error.
                Else
                    ' other error. get out with return value of False
                    CopyModule = False
                    Exit Function
                End If
            End If
        End If
    
        ''''''''''''''''''''''''''''''''''''''''''''''''''''
        ' Do the Export and Import operation using FName
        ' and then Kill FName.
        ''''''''''''''''''''''''''''''''''''''''''''''''''''
        FromVBProject.VBComponents(ModuleName).Export Filename:=FName
    
        '''''''''''''''''''''''''''''''''''''
        ' Extract the module name from the
        ' export file name.
        '''''''''''''''''''''''''''''''''''''
        SlashPos = InStrRev(FName, "\")
        ExtPos = InStrRev(FName, ".")
        CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1)
    
        ''''''''''''''''''''''''''''''''''''''''''''''
        ' Document modules (SheetX and ThisWorkbook)
        ' cannot be removed. So, if we are working with
        ' a document object, delete all code in that
        ' component and add the lines of FName
        ' back in to the 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
                ' VBComp is destination module
                Set TempVBComp = ToVBProject.VBComponents.Import(FName)
                ' TempVBComp is source module
                With VBComp.CodeModule
                    .DeleteLines 1, .CountOfLines
                    S = TempVBComp.CodeModule.Lines(1, TempVBComp.CodeModule.CountOfLines)
                    .InsertLines 1, S
                End With
                On Error GoTo 0
                ToVBProject.VBComponents.Remove TempVBComp
            End If
        End If
        Kill FName
        CopyModule = True
    End Function
    

    【讨论】:

      【解决方案2】:

      您需要查看 VBComponents 来完成此类任务

      您首先需要激活名为“Microsoft Visual Basic for Applications Extensibility”的引用

      试试下面的代码:

      Sub Test_InsertCode()
      
          Dim Commands As String
          Commands = Chr(13) & _
                      "Private Sub TestNewCode()" & Chr(13) & _
                      "    MsgBox ""You Win !!""" & Chr(13) & _
                      "End Sub"
      
          Dim VBComps As VBComponents
          Set VBComps = ThisWorkbook.VBProject.VBComponents
      
          Dim VBComp As VBComponent
          Dim VBCodeMod As CodeModule
      
          Dim oSheet As Worksheet
          For Each oSheet In ThisWorkbook.Worksheets
              Set VBComp = VBComps(oSheet.CodeName)
              Set VBCodeMod = VBComp.CodeModule
              InsertCode VBCodeMod, Commands
          Next oSheet
      
          'Here's a quick example of how to insert code in a new Module
          Set VBComp = VBComps.Add(vbext_ct_StdModule)
          InsertCode VBComp.CodeModule, Commands
      
      End Sub
      
      Private Function InsertCode(VBCodeMod As CodeModule, Commands As String)
      
          Dim LineNum As Long
          With VBCodeMod
              LineNum = .CountOfLines + 1
              .InsertLines LineNum, Commands
          End With
      
      End Function
      

      注意。当您在中断模式下运行它时,(或逐行?)它会在复制代码后立即生成一个错误。你需要一次运行它..

      此代码适用于 Excel 2003,在更高版本上运行时可能存在一些我不知道的安全问题。

      【讨论】:

      • 如果将“ThisWorkbook”更改为“ActiveWorkbook”,则可以将代码添加到任何打开的工作簿中。
      【解决方案3】:

      这不会解决工作表中的事件部分,但这是将模块从一个工作簿移动到另一个工作簿的简单解决方案。

      注意 - 您确实需要打开“Microsoft Visual Basic for Applications Extensibility”引用,如上所述。

      简而言之,代码可以正常工作(无需所有内务验证)。显然,您可以获得更高级和防错/处理,但这是基础。该函数将模块从您的 FromVBProject 导出到文件目录,然后导入到您的 ToVBProject。

      Function CopyModule (ModuleName as String, FromVBProject as VBIDE.VBProject, _  
                           ToVBProject as VBIDE.VBProject, _ 
                           FileLocation as String) as Boolean
      Dim fileDirectory as String
      
      fileDirectory = filelocation & ModuleName & ".bas"
      FromVBProject.VBComponents.Item(ModuleName).Export fileDirectory
      ToVBProject.Import fileDirectory
      
      Kill fileDirectory
      
      CopyModule = True
      
      End Function
      
      Sub CopyModuleToOtherWorkbook()
      
      Dim destinationWorkbook as Workbook
      Set destinationWorkbook = Workbooks("destiationWorkbook.xlsm")
      
      CopyModule "TestModule", ThisWorkbook.VBProject, destinationWorkbook.VBProject, "C:\my documents\macros\"   
      
      'Assuming you want to save the workbook you just copied the module to
       destinationWorkbook.SaveAs C:\my documents\macros\ & desintationWorkbook.Name, xlOpenXMLWorkbookMacroEnabled
      
       End sub
      

      【讨论】:

      • 因为答案顺序可以而且确实会发生变化,我建议删除对其他答案的引用,并直接解释为什么这种尝试不起作用。解释您的答案的功能也会有所帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-26
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多