Hola a todos:
El post surge fruto de una consulta, se trataría de actualizar en varios archivos el mismo módulo (estándar o de hoja) pero desde otro archivo, evitando así que una aplicación distribuida entre varios usuarios, cuando es necesaria una actualización de código, se tengan que abrir manualmente cada uno de los archivos.
Veamos un ejemplo, imaginad que tenéis en una carpeta los siguientes archivos:
En cada uno de estos archivos en el módulo de hoja «Hoja1» tenemos un determinado código, pero como hemos encontrado algunos errores, tenemos que actualizar este código en cada uno de ellos. Dado que no queremos hacerlo manualmente, lo vamos a programar.
En nuestro archivo, que contiene los siguientes módulos:
En el módulo CODIGO_A_COPIAR vamos a escribir el código que necesitamos exportar a los libros que tenemos en la carpeta. En este caso es un sencillo «Hola Mundo» en un msgbox.
En el módulo ACTUALIZAR tenemos el código que va a permitir realizar todo esto.
Veamos cómo funciona y luego os dejo la rutina comentada.
En primer lugar seleccionamos los archivos:
Ahora vamos a indicar el nombre del módulo:
En este punto es importante tener en cuente que debemos escribir correctamente el nombre del módulo, Por ejemplo es Hoja1 y no «HOJA1» o «hoja1», el uso de las mayúsculas o minúsculas es importante. El nombre ha de ser el mismo que el que aparezca en el módulo de los archivos que vamos a actualizar.
Una vez que aceptamos, vamos a pasar nuestro mensaje «Hola Mundo» al módulo de hoja «Hoja1» de los cuatro archivos seleccionados.
El código a utilizar sería el siguiente:
Option Explicit
Sub ACTUALIZAR_MODULO()
'Declaramos variables
Dim nArchivos, CodigoCopiar, CodigoPegar
Dim Hojadestino As String, NombreLibro As String
Dim FSO As Variant, i As Long, lineas As Long
'Desactivamos actualización de pantalla
Application.ScreenUpdating = False
'Seleccionamos uno o varios archivos
nArchivos = Application.GetOpenFilename(filefilter:="Excel (*.xls*),*.xls", _
Title:="SELECCIONAR ARCHIVO", MultiSelect:=True)
'si no seleccionamos nada, salimos del proceso
If Not IsArray(nArchivos) Then
Exit Sub
Else
'Mostramos inputbox para que el usuario indique el nombre del modulo:estandar o de hoja. Si está vacío, salimos del proceso, si está mal escrito mostramos error
Hojadestino = InputBox("INDICA EL NOMBRE DEL MÓDULO O LA HOJA DONDE SE ENCUENTRA EL CÓDIGO A REEMPLAZAR:" & Chr(13) & Chr(13) & "(VERIFICA EL USO DE MAYÚSCULAS O MINÚSCULAS)", "ARCHIVO SELECCIONADO")
If Hojadestino = Empty Then Exit Sub
'Recorremos mediante un array los archivos seleccionados
For i = LBound(nArchivos) To UBound(nArchivos)
'Abrimos cada archivo
Workbooks.Open Filename:=(nArchivos(i))
'obtenemos el nombre de cada archivo
Set FSO = CreateObject("Scripting.FileSystemObject")
NombreLibro = FSO.GetFileName(nArchivos(i))
'Borramos el código que queremos actualizar en los archivos seleccionados, el módulo ha de llamarse igual en todos.
With ActiveWorkbook
On Error GoTo etiqueta
.VBProject.VBComponents(Hojadestino).CodeModule.DeleteLines 1, .VBProject.VBComponents(Hojadestino).CodeModule.CountOfLines
End With
'seleccionamos y copiamos el código de nuestro libro y que está en el módulo CODIGO A COPIAR
Set CodigoCopiar = ThisWorkbook.VBProject.VBComponents("CODIGO_A_COPIAR").CodeModule
'Pegamos en cada archivo y módulo seleccionado el código que hemos copiado
Set CodigoPegar = Workbooks(NombreLibro).VBProject.VBComponents(Hojadestino).CodeModule
lineas = CodigoCopiar.CountOfLines
CodigoPegar.AddFromString CodigoCopiar.Lines(1, lineas)
'cerramos cada libro que hemos seleccionado y abierto
Workbooks(NombreLibro).Close savechanges:=True
Next i
End If
Exit Sub
'Si hay un error mostramos mensaje.
etiqueta:
MsgBox ("VERIFICA QUE HAS ESCRITO CORRECTAMENTE EL NOMBRE DEL MÓDULO DE LA HOJA, LAS MAYÚSCULAS O MINÚSCULAS SE DEBEN TENER EN CUENTA" _
& Chr(13) & Chr(13) & "POR EJEMPLO: HOJA1 EN LUGAR DE Hoja1, DONDE LO CORRECTO EN Hoja1"), vbCritical
End Sub
Y eso es todo. Sin embargo, me gustaría comentar varias cosas:
La primera: para que el código funcione correctamente, debéis activar la siguiente referencia: Microsoft Visual Basic for Applications Extensibility 5.3
La segunda: Antes de comenzar con el ejercicio, para que la macro funcione es necesario realizar unas modificaciones en el centro de confianza de nuestro programa de Excel. Para hacerlo, debéis entrar en Archivo > Opciones y pulsar en Centro de Confianza:
A continuación se mostrará esta otra pantalla:
Elegimos la opción Configuración de macros y activamos la casilla que pone: Confiar en el acceso al modelo de objetos de proyectos de VBA, y aceptamos.
Es importante que realicemos este paso, si no lo hacemos la macro que os voy a mostrar generará un error y no se ejecutará.
Esto lo debéis hacer tanto para este archivo como para los que vamos a actualizar.
Para finalizar, me gustaría recordar que estamos trabajando con código que borra código, por lo tanto, antes de ejecutarlo en firme, haced varias pruebas con archivos que se pueden borrar o eliminar.
Y eso es todo, os dejo el archivo de prueba, espero que os sea de utilidad.
Descarga el archivo de ejemplo pulsando en: ACTUALIZAR UN MODULO DE VBA EN VARIOS ARCHIVOS DESDE OTRO ARCHIVO
¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.
¡¡Muchas gracias!!
Mediante la suscripción al blog, la realización comentarios o el uso del formulario de contacto estás dando tu consentimiento expreso al tratamiento de los datos personales proporcionados según lo dispuesto en la ley vigente (LOPD). Tienes más información al respecto en esta página del blog: Política de Privacidad y Cookies
Hola,
gracias por tu aporte, es genial. solo un duda, los excels que se modifican (NombreLibro) los módulos estan protegidos, he encontrado algun código que funciona con sendkeys, però lo realiza con tu excel y no con el (NombreLibro). Como se puede hacer referencia al (NombreLibro) y que ejecute una macro que desbloquea el passworb vba?
Gracias
Hola Oriol:
Efectivamente, Excel no está preparado para poder cambiar o modificar la contraseña de un proyecto de VBA, se han ideado métodos con sendkeys, pero a mi particularmente no se parecen fiables. Para este código en particular no he visto posibilidad de desactivar las contraseñas (quizás tenga que estudiarlo en profundidad) y me temo que no será viable.
Siento no poder ayudarte.
Saludos.
Gracias.
Otra opción que tenia pensado era llamar a una macro. siguiendo la estructura de tu còdigo,
(…)
NombreLibro = FSO.GetFileName(nArchivos(i))
‘Borramos el código que queremos actualizar en los archivos seleccionados, el módulo ha de llamarse igual en todos.
With ActiveWorkbook
On Error GoTo etiqueta
(aquí és donde tengo la duda y cuando lo ejecuto me da error, he puesto las tres lineas que he provado, una sola cada vez. Però no puedo ejecutar la macroTestUnprotect, que està alojada en el módulo6 del libro que se abre, el què hace referència a «NombreLibro» ). Si ejecuto la Macro TestUnprotect solo con el archivo si que funciona. Lo que passa és que la macro se ejecuta solo sobre tu excel (actualitzación) y no el què yo he seleccionado.
‘ NombreLibro.Application.Run («‘» & NombreLibro & «‘!Módulo6.TestUnprotect»)
‘ Workbooks(NombreLibro).Application.Run Módulo6.TestUnprotect
‘ ActiveWorkbook.RunTestUnprotect xlTestUnprotect
.VBProject.VBComponents(Hojadestino).CodeModule.DeleteLines 1, VBProject.VBComponents(Hojadestino).CodeModule.CountOfLines
End With
Con ese código pudiese actualizarse los datos un libro de otra hoja de calculo con los datos capturados en un formulario? , y/o cargar los datos de un formulario con datos de otra hoja?
Saludos
No, para lo que indicas es necesario otro tipo de programación, Saludos
No me funciona, deberia poner el nombre de la hoja? o el nombre del modulo? de todas formas en ambos caso me da error
Si se trata de un módulo de hoja, debes indicar la hoja. Si se trata de un módulo estándar debes indicar el módulo.
Debería funcionarte sin problema.
Saludos.