Excel VBA项目已生成多个工作簿对象。

11

我负责一个非常庞大的Excel 2010电子表格,其中链接到各种外部数据源,包括Bloomberg,有65个带有vba模块的工作表,并引用其他vba插件。

我注意到VBA项目已经获得了多个Workbook对象。

有标准的ThisWorkbook。然而,一些工作表也被Excel转换为Workbook对象,使原始的工作表成为前一个副本,减去代码。

这似乎不是任何人行动的结果。事实上,我认为有多个Workbook对象是不可能的!

例如,我有一个名为wksInputs的工作表,现在已经变成了Workbook对象,而原始的wksInputs现在被称为wksInputs1。

example

我无法删除wksInputs Workbook对象。

请问有人能帮忙解释这里发生了什么,以及我如何能够解决问题...?

非常感谢。


如何将我的“声望”提高到10,或者绕过这个限制? - Alex Berry
不行 - 我们的防火墙屏蔽了所有媒体共享和个人网络存储站点...考虑到我工作的地方,我想这可能是最好的,尽管在这种情况下显然是一个巨大的障碍! - Alex Berry
@AlexBerry,请上传到imgur(或类似的服务),并将链接放入您的问题中(不要作为图像)。然后,一些友好的编辑应该能够将链接转换为您的问题中的图像。 - SeanC
3
这些问题可能是由COM插件引起的。尝试进入“开发人员”>“COM插件”,将其取消勾选,然后查看是否解决了问题。 - Doug Glancy
1
我已经通过我的iPad将一张图片保存到了我的公共Dropbox文件夹中。请尝试使用此链接:链接 - Alex Berry
显示剩余9条评论
8个回答

3

这是我的解决方案,它可以持续地工作,您不需要手动复制工作表和代码到空白工作簿中。我已经在多个无法启动且出现“自动化错误 - 灾难性故障”的损坏工作簿上测试了此方法。

注意:原始的损坏文件保存为.xlsm

  1. 打开一个空白的Excel工作簿
  2. 开发人员选项卡 > 宏安全性 > 禁用所有未经通知的宏
  3. 关闭Excel
  4. 双击损坏的文件,例如,MyFile.xlsm
  5. 文件 > 另存为... > MyFile.xlsb(不是 .xlsm),选择.xlsb格式即可解决问题
  6. 开发人员选项卡 > 宏安全性 > 启用所有宏(或您喜欢的任何安全级别)
  7. 关闭Excel
  8. 双击MyFile.xlsb

现在文件已修复! 如果需要,您可以将MyFile.xlsb文件重新保存为.xlsm。根据我的经验,.xlsm 文件很容易损坏,所以我会养成一直使用 .xlsb 格式的习惯。

希望有人会发现这个有用 :)


1
我也一样。我在尝试之后仍然有额外的工作簿。 - oddacorn
对我没用。 :-( - Razor
这对我来说没有起作用。 - undefined

2
我遇到了一个相同的问题,文件中有多个工作簿对象,在打开时会生成“自动化错误 - 灾难性失败”错误。
我将*.xlsm文件保存为*.xlsb文件。当我重新打开*.xlsb文件时,所有工作簿对象仍然在文件中。我合理地认为文件中的错误最终会导致问题,并将其复制到新文件中。
然而,当我关闭*.xlsb文件并重新打开原始的*.xlsm文件时,所有对象都消失了,文件不再生成“自动化错误 - 灾难性失败”错误。
我承认这很奇怪,但问题仍然存在于*.xlsb文件中,但原始的*.xlsm文件(我正在尝试保存的文件)没有问题。
可能只是一次性问题,但值得一试...

对我没用。 :-( - Razor
这对我没有起作用。 - undefined

2
您可以通过执行"将文件转换为.zip并解压缩的技巧"来引入此行为,然后用具有不同表结构的不同项目的vbaProject.bin文件(宏代码文件)替换vbaProject.bin文件。不知道这是否是发帖者遇到的情况,但这就是我遇到的情况。

这也是我故意做的,不知道有没有一种方法可以避免遇到“ThisWorkbook1”的问题。 - David Rogers

1
当我把一个工作表作为参数传递给子程序时,我的代码出现了问题,如下所示:

Call BuildCodeStrings(Sheet2, sAccount)
Sub BuildCodeStrings(wsSource As Worksheet, s As String)

为了解决这个问题,我创建了一个新的工作簿,将原始工作簿中所有合法工作表中的数据复制到同名的工作表中。然后将所有代码从原始工作簿复制到新工作簿中。
然后我改变了子程序调用方式:

Call BuildCodeStrings("IC Accounts", sAccounts)
Sub BuildCodeStrings(sSource As String, s As String)

并在我的子程序BuildCodeString中添加了一行代码:

Set wsSource = ThisWorkbook.Sheets(sSource)

我不知道是什么原因导致了这个问题,但这个解决方法对我有效。

1

我曾经在 PowerPoint (2007) 中遇到了同样的问题,其中“Slide1”为空,无法删除。@Scoox 的答案指引我找到了一个解决方案:

  1. 导出所有 VBA 模块为文本 (.bas) 文件
  2. 将 .pptm(或 .xlsm)文件另存为 .pptx(或 .xlsx)
  3. 关闭 PowerPoint(或 Excel)
  4. 打开此 .pptx/.xlsx 文件并将其另存为 .pptm/.xlsm
  5. 导入原始 VBA 文本 (.bas) 文件
  6. 手动重新关联所有按钮到原始宏函数
  7. 添加任何原始文件中具有的外部 参考资料
  8. 保存并测试是否一切正常

这对我有效,我相信它也适用于 Excel。


非常感谢! 我一直听到像“创建一个新的Excel文件并将所有工作表/对象/代码导入新的工作簿”这样的回复…… 听起来太麻烦了…… 我使用了您的方法,实际上不需要重新连接任何按钮,它就可以正常工作!!!它还消除了我的重复ThisWorkbook对象和所有幽灵工作表! - Cameron Critchlow

0

在使用Office365时遇到了同样的问题,发现我在一个公共常量和函数参数中使用了相同的名称。在将函数参数名称更改后,问题就没有再次出现。


0

我的错误是当我将一个工作表传递给函数,并在for循环中稍后使用该变量名称作为循环变量时引起的(因为我是个不好的和懒惰的程序员)。模块中有Option Explicit,所以我认为它不知道如何处理这些引用。

作为重整工作簿的替代方案:

  1. 将所有工作表复制到新工作簿中
  2. 将所有模块、窗体和类也复制到新工作簿中
  3. 将其另存为.xlsm文件
  4. 将新旧两个文件名都改为.zip
  5. 将文件“xl/vbaProject.bin”从新文件复制到旧文件中
  6. 将文件名改回.xlsm

这听起来像你只是无脑地复制了一切,但这意味着您不必检查链接、命名范围、条件格式或数据验证,以确保每样东西都正确地复制过来。


0
也许还有人需要这个...我成功编写了解决方案...基本上它会在你的桌面上创建一个VBA和Excel的副本。

:)

参考资料:

  1. Microsoft Visual Basic for Applications Extensibility 5.3

  2. Microsoft Scripting Runtime

  3. Microsoft VBScript Regular Expressions 5.5

  4. Microsoft Windows Common Controls 6.0

     Sub CopiarHojasANuevoLibro()
         ' Desactivar actualizaciones de pantalla, alertas, eventos e interacción con el usuario
         ' Disable screen updates, alerts, events and user interaction
         Application.ScreenUpdating = False
         Application.DisplayAlerts = False
         Application.EnableEvents = False
         Application.Interactive = False
    
         ' Exportar los módulos de código al archivo
         ' Export code modules to file
         Call ExportModules
    
         ' Crear un nuevo libro de Excel
         ' Create a new Excel workbook
         Dim wbNuevo As Workbook
         Set wbNuevo = Workbooks.Add
    
         ' Renombrar la primera hoja del nuevo libro
         ' Rename the first sheet of the new workbook
         wbNuevo.Sheets(1).Name = "zzzzzzzzz"
    
         ' Copiar cada hoja del libro actual al nuevo libro
         ' Copy each sheet from the current workbook to the new workbook
         Dim ws As Worksheet
         For Each ws In ThisWorkbook.Worksheets
             ws.Copy After:=wbNuevo.Sheets(wbNuevo.Sheets.Count)
         Next ws
    
         ' Eliminar la primera hoja del nuevo libro
         ' Delete the first sheet of the new workbook
         wbNuevo.Sheets(1).Delete
    
         ' Activar el nuevo libro y realizar la importación de los módulos de código
         ' Activate the new workbook and import the code modules
         wbNuevo.Activate
         Call ImportModules
    
         ' Definir la ruta y el nombre del archivo de destino
         ' Define the path and name of the destination file
         Dim rutaArchivo As String
         rutaArchivo = "C:\Users\" & CStr(Environ$("Username")) & "\Desktop\CodeSaver " & Format(Date, "DD-MM-YYYY") & ".xlsm"
    
         ' Eliminar el archivo existente si existe
         ' Delete existing file if it exists
         On Error Resume Next
         Kill rutaArchivo
         On Error GoTo 0
    
         ' Guardar el libro activo en la ubicación especificada con el formato de archivo xlOpenXMLWorkbookMacroEnabled
         ' Save the active workbook to the specified location in the file format xlOpenXMLWorkbookMacroEnabled
         ActiveWorkbook.SaveAs Filename:=rutaArchivo, FileFormat:=xlOpenXMLWorkbookMacroEnabled
    
         ' Cerrar el libro activo guardando los cambios
         ' Close the active workbook saving changes
         ActiveWorkbook.Close SaveChanges:=True
    
         ' Restaurar las configuraciones originales de la aplicación
         ' Restore original application settings
         Application.ScreenUpdating = True
         Application.DisplayAlerts = True
         Application.EnableEvents = True
         Application.Interactive = True
    
         ' Activar el libro original
         ' Activate the original workbook
    
         ThisWorkbook.Activate End Sub
    
     Public Sub ExportModules()
         ' Variables para exportar módulos de código
         ' Variables to export code modules
         Dim bExport As Boolean
         Dim wkbSource As Excel.Workbook
         Dim szSourceWorkbook As String
         Dim szExportPath As String
         Dim szFileName As String
         Dim cmpComponent As VBIDE.VBComponent
    
         ' Comprobar si la carpeta de destino existe
         ' Check if the destination folder exists
    
         If FolderWithVBAProjectFiles = "Error" Then
             MsgBox "Export Folder Not exist"
             Exit Sub
         End If
    
         ' Eliminar los archivos existentes en la carpeta de destino
         ' Delete existing files in the destination folder
    
         On Error Resume Next
         Kill FolderWithVBAProjectFiles & "\*.*"
         On Error GoTo 0
    
         ' Obtener el nombre del libro de origen y establecer una referencia al libro de origen
         ' Get the name of the source workbook and set a reference to the source workbook
         szSourceWorkbook = ThisWorkbook.Name
         Set wkbSource = Application.Workbooks(szSourceWorkbook)
    
         ' Comprobar si el proyecto VBA del libro de origen está protegido
         ' Check if the source workbook VBA project is protected
         If wkbSource.VBProject.Protection = 1 Then
             MsgBox "The VBA in this workbook Is protected," & _
                    "not possible To export the code"
             Exit Sub
         End If
    
         ' Establecer la ruta de exportación como la carpeta de destino
         ' Set the export path as the destination folder
         szExportPath = FolderWithVBAProjectFiles & "\"
    
         ' Iterar a través de los componentes de VBA del libro de origen
         ' Iterate through the VBA components of the source workbook
         For Each cmpComponent In wkbSource.VBProject.VBComponents
             bExport = True
             szFileName = cmpComponent.Name
    
             ' Asignar la extensión de archivo adecuada según el tipo de componente
             ' Assign the appropriate file extension based on the component type
             Select Case cmpComponent.Type
                 Case vbext_ct_ClassModule
                     szFileName = szFileName & ".cls"
                 Case vbext_ct_MSForm
                     szFileName = szFileName & ".frm"
                 Case vbext_ct_StdModule
                     szFileName = szFileName & ".bas"
                 Case vbext_ct_Document
                     ' No exportar componentes de tipo Document
                     ' Do not export components of type Document
                     bExport = False
             End Select
    
             ' Exportar el componente si está marcado para exportación
             ' Export the component if it is marked for export
             If bExport Then
                 cmpComponent.Export szExportPath & szFileName
             End If
         Next cmpComponent
    
         Debug.Print "Export Is ready" End Sub
    
     Public Sub ImportModules()
         ' Variables para importar módulos de código
         ' Variables to import code modules
         Dim wkbTarget As Excel.Workbook
         Dim objFSO As Scripting.FileSystemObject
         Dim objFile As Scripting.file
         Dim szTargetWorkbook As String
         Dim szImportPath As String
         Dim szFileName As String
         Dim cmpComponents As VBIDE.VBComponents
    
         ' Comprobar si el libro activo es el mismo que el libro de origen
         ' Check if the active workbook is the same as the source workbook
         If ActiveWorkbook.Name = ThisWorkbook.Name Then
             MsgBox "Select another destination workbook" & _
                    "Not possible To import in this workbook "
             Exit Sub
         End If
    
         ' Comprobar si la carpeta de origen existe
         ' Check if the source folder exists
         If FolderWithVBAProjectFiles = "Error" Then
             MsgBox "Import Folder Not exist"
             Exit Sub
         End If
    
         ' Obtener el nombre del libro de destino y establecer una referencia al libro de destino
         ' Get the name of the destination workbook and set a reference to the destination workbook
         szTargetWorkbook = ActiveWorkbook.Name
         Set wkbTarget = Application.Workbooks(szTargetWorkbook)
    
         ' Comprobar si el proyecto VBA del libro de destino está protegido
         ' Check if the target workbook VBA project is protected
         If wkbTarget.VBProject.Protection = 1 Then
             MsgBox "The VBA in this workbook Is protected," & _
                    "not possible To Import the code"
             Exit Sub
         End If
    
         ' Establecer la ruta de importación como la carpeta de origen
         ' Set the import path as the source folder
         szImportPath = FolderWithVBAProjectFiles & "\"
    
         ' Crear un objeto FileSystemObject para trabajar con archivos
         ' Create a FileSystemObject to work with files
         Set objFSO = New Scripting.FileSystemObject
    
         ' Comprobar si hay archivos para importar en la carpeta de origen
         ' Check if there are files to import in the source folder
         If objFSO.GetFolder(szImportPath).Files.Count = 0 Then
             MsgBox "There are no files To import"
             Exit Sub
         End If
    
         ' Eliminar los módulos de código y formularios de usuario existentes en el libro de destino
         ' Delete existing code modules and userforms in the target workbook
         Call DeleteVBAModulesAndUserForms
    
         ' Obtener una referencia a los componentes de VBA del libro de destino
         ' Get a reference to the VBA components of the target workbook
         Set cmpComponents = wkbTarget.VBProject.VBComponents
    
         ' Iterar a través de los archivos en la carpeta de origen
         ' Iterate through the files in the source folder
         For Each objFile In objFSO.GetFolder(szImportPath).Files
             ' Importar el archivo si tiene una extensión válida
             ' Import the file if it has a valid extension
             If (objFSO.GetExtensionName(objFile.Name) = "cls") Or _
                (objFSO.GetExtensionName(objFile.Name) = "frm") Or _
                (objFSO.GetExtensionName(objFile.Name) = "bas") Then
                 cmpComponents.Import objFile.Path
             End If
         Next objFile
    
         Debug.Print "Import Is ready" End Sub
    
     Function FolderWithVBAProjectFiles() As String
         ' Función para obtener la carpeta de destino de los archivos VBA
         ' Function to get the destination folder of the VBA files
         Dim wshShell As Object
         Dim fso As Object
         Dim SpecialPath As String
    
         ' Crear objetos Shell y FileSystemObject
         ' Create Shell and FileSystemObject objects
         Set wshShell = CreateObject("WScript.Shell")
         Set fso = CreateObject("scripting.filesystemobject")
    
         ' Obtener la ruta de la carpeta "Mis documentos"
         ' Get the path of the "My Documents" folder
         SpecialPath = wshShell.SpecialFolders("MyDocuments")
    
         ' Agregar una barra diagonal si no está presente al final de la ruta
         ' Add a forward slash if not present at the end of the path
         If Right(SpecialPath, 1) <> "\" Then
             SpecialPath = SpecialPath & "\"
         End If
    
         ' Crear la carpeta "VBAProjectFiles" si no existe
         ' Create the folder "VBAProjectFiles" if it doesn't exist
    
         If fso.FolderExists(SpecialPath & "VBAProjectFiles") = False Then
             On Error Resume Next
             MkDir SpecialPath & "VBAProjectFiles"
             On Error GoTo 0
         End If
    
         ' Devolver la ruta de la carpeta "VBAProjectFiles" si existe, o "Error" si no existe
         ' Return the path of the "VBAProjectFiles" folder if it exists, or "Error" if it doesn't
         If fso.FolderExists(SpecialPath & "VBAProjectFiles") = True Then
             FolderWithVBAProjectFiles = SpecialPath & "VBAProjectFiles"
         Else
             FolderWithVBAProjectFiles = "Error"
         End If End Function
    
     Function DeleteVBAModulesAndUserForms()
         ' Función para eliminar los módulos de código y formularios de usuario existentes
         ' Function to remove existing code modules and userforms
         Dim VBProj As VBIDE.VBProject
         Dim vbComp As VBIDE.VBComponent
    
         ' Obtener una referencia al proyecto VBA del libro activo
         ' Get a reference to the VBA project of the active workbook
         Set VBProj = ActiveWorkbook.VBProject
    
         ' Iterar a través de los componentes de VBA en el proyecto
         ' Iterate through the VBA components in the project
    
         For Each vbComp In VBProj.VBComponents
             ' Eliminar el componente si no es de tipo Document
             ' Delete the component if it is not of type Document
             If vbComp.Type = vbext_ct_Document Then
             Else
                 VBProj.VBComponents.Remove vbComp
             End If
         Next vbComp End Function
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接