"Después de que su servicio actualizó el libro mensual, nuestras macros desaparecieron". Ese ticket de soporte casi nunca tiene que ver con el código de las macros. En algún punto de la canalización, un libro habilitado para macros se guardó con una extensión simple .xlsx, y Excel, siguiendo las reglas de tipos de contenido de ECMA-376, se negó a cargar un proyecto VBA desde un paquete cuyo tipo de contenido dice que no contiene ninguno. Ninguna llamada de API borró nada; lo hizo el nombre del archivo.
Los proyectos de macros y los vínculos externos a libros son los dos activos que la automatización bien intencionada destruye con más frecuencia, porque ambos viven fuera de la cuadrícula de celdas que el código de edición realmente toca. HotXLS, una biblioteca nativa para Delphi y C++Builder que lee y escribe archivos XLS y XLSX sin Excel, trata ambos como cargas de primera clase: puede conservarlos durante una reescritura, inyectarlos, extraerlos y avisar que existen. Este artículo delimita con precisión qué sobrevive, qué no y dónde están los límites honestos.
Dos cargas, dos formas distintas de perderlas
Un proyecto VBA es un binario opaco único: vbaProject.bin dentro de un paquete OOXML, o un almacenamiento OLE dentro de un archivo BIFF. Se pierde de una de dos maneras: el escritor no lo copia a la salida, o la salida se guarda con un tipo de archivo que no lo permite. Un vínculo externo es la estructura opuesta: no es un bloque, sino una red de relaciones; una ruta o URL de destino, la lista de nombres de hojas en el libro remoto y, opcionalmente, una caché de los últimos valores de celdas vistos que permite que Excel muestre algo cuando el destino no está disponible.
El código de edición que solo piensa en celdas no conservará ninguno de los dos por accidente. Las garantías de conservación deben venir del escritor de archivos de la biblioteca, por eso conviene saber exactamente qué vuelve a escribir HotXLS para cada caso.
Conservar un proyecto VBA durante una reescritura XLSX
En el lado XLSX, TXLSXWorkbook almacena la carga de macros de forma literal: la propiedad VbaProject contiene los bytes sin procesar de vbaProject.bin en un contenedor AnsiString, y una cadena vacía significa que no hay macros. HasVbaProject comprueba la presencia, ClearVbaProject lo elimina de forma deliberada y LoadVbaProjectFromFile inyecta un proyecto extraído de una plantilla, una forma limpia de dar a los libros generados un conjunto estándar de macros sin mantener cerca un archivo de plantilla completo:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Data');
Sheet.Cells[1, 1].Value := 'Refreshed ' + DateTimeToStr(Now);
Book.LoadVbaProjectFromFile('macros\vbaProject.bin');
if not Book.HasVbaProject then
raise Exception.Create('VBA payload failed to load');
// The .xlsm extension is not cosmetic: it selects the
// macro-enabled content type inside the package.
Book.SaveAs('monthly-report.xlsm');
finally
Book.Free;
end;
end;
La línea de guardado contiene la regla que produce el ticket de soporte del primer párrafo: un libro que contiene un proyecto VBA debe guardarse con semántica habilitada para macros, que HotXLS aplica cuando el destino es .xlsm. Guarde el mismo contenido como .xlsx y Excel se negará a cargar las macros, aunque los bytes físicamente pudieran caber en el paquete. Cuando necesite mirar dentro de la carga en vez de solo transportarla, por ejemplo para listar nombres de módulos en un informe de auditoría, la propiedad ParsedVBAProject expone el modelo de módulos analizado, mientras que VbaProject sigue siendo los bytes originales intactos.
Reutilizar macros de libros XLS heredados
La fachada BIFF tiene el conjunto simétrico de herramientas: HasVBAProject inspecciona un archivo cargado, SaveVBAProjectToFile extrae el almacenamiento del proyecto al disco y LoadVBAProjectFromFile lo inyecta en otro libro. Eso permite una tarea común de modernización: cosechar las macros desde un archivo modelo de la era 2003 e implantarlas en una salida XLS recién generada:
var
Src, Dst: IXLSWorkbook; // interface references: no manual Free
begin
Src := TXLSWorkbook.Create;
if Src.Open('legacy-model.xls') <= 0 then
raise Exception.Create('Cannot open legacy model');
if Src.HasVBAProject then
Src.SaveVBAProjectToFile('extracted-vba.bin');
Dst := TXLSWorkbook.Create;
Dst.Sheets.Add.Name := 'Report2026';
Dst.LoadVBAProjectFromFile('extracted-vba.bin');
Dst.SaveAs('report-with-macros.xls');
end;
Observe el modelo de memoria: TXLSWorkbook se mantiene mediante la interfaz con conteo de referencias IXLSWorkbook y no debe liberarse manualmente, lo contrario de la clase XLSX. Mezclar ambas convenciones en una misma unidad es una fuente confiable de bloqueos por doble liberación. Mantenga la extracción y la inyección dentro del mismo formato de archivo; el almacenamiento de proyecto BIFF y el vbaProject.bin de OOXML están relacionados, pero no son contenedores intercambiables, y una canalización que necesita macros en ambos formatos debe mantener una plantilla de macros por formato.
Vínculos externos: el mapa sobrevive, los valores en caché no
Para libros XLSX, HotXLS modela los vínculos externos mediante la colección ExternalLinks. Cada TXLSXExternalLink lleva el Target, una ruta o URL al libro remoto, y la lista SheetNames que describe sus hojas. Ambos hacen el ciclo de abrir y guardar con fidelidad, y los vínculos pueden crearse por código:
var
Link: TXLSXExternalLink;
begin
Link := Book.ExternalLinks.Add('\\fileserver\finance\fx-rates-2026.xlsx');
Link.SheetNames.Add('FX');
if Book.ExternalLinks.Count > 0 then
Writeln(Format('%d external link(s): delivery requires reachable targets',
[Book.ExternalLinks.Count]));
end;
Este es el límite que el diseño de su canalización debe respetar: HotXLS conserva de ida y vuelta el mapa del vínculo, es decir, destino y nombres de hojas, pero no analiza ni escribe los valores de celdas en caché que OOXML almacena en el elemento sheetDataSet del vínculo. La consecuencia práctica aparece en la máquina del destinatario, no en la suya. Cuando Excel abre un libro sin caché de vínculo y con un destino inaccesible, por ejemplo una laptop fuera de la VPN o un recurso compartido renombrado, las fórmulas que dependen del vínculo se degradan a errores #REF! o quedan detenidas detrás de un aviso de actualización. Nunca prometa que un libro generado mostrará valores vinculados externamente sin conexión, y trate un ExternalLinks.Count distinto de cero como una condición previa de entrega: los destinos deben ser accesibles desde el lugar donde se abra el archivo.
Qué conserva byte por byte el lector XLS
El lado BIFF usa una estrategia distinta para las estructuras que HotXLS no modela. Las cachés y vistas de tablas dinámicas, la familia de registros SX*, las definiciones QueryTable, las conexiones de datos externas, las vistas personalizadas, las imágenes de encabezado y los registros de tema se conservan durante un ciclo de abrir y guardar como bloques de registros sin procesar: sin analizar, sin modificar, intactos. Las referencias externas también hacen el ciclo de ida y vuelta mediante los registros subyacentes EXTERNSHEET y SupBook, aunque en este lado no hay una API tipada de creación.
La conservación sin procesar es una garantía real, pero funciona en ambos sentidos. Sus ediciones no pueden corromper una caché de tabla dinámica porque nada la toca; del mismo modo, nada la actualiza. Inserte filas a través de una región a la que apunta una estructura conservada y la estructura mantendrá sus coordenadas originales mientras los datos se mueven: el archivo sigue siendo válido, pero la semántica se deteriora en silencio. La convención de diseño segura es limitar las ediciones generadas a hojas que no contengan estructuras conservadas, la misma disciplina recomendada para hojas protegidas y configuradas para impresión en nuestro artículo sobre protección de hojas y configuración de página.
Comprobaciones de aceptación antes de entregar un libro gobernado
Como ambos modos de falla son silenciosos, la única verificación confiable es volver a abrir el archivo que realmente escribió. Tres comprobaciones detectan casi todo. Vuelva a abrir la salida y confirme que HasVbaProject siga respondiendo true cuando se esperaban macros; esto detecta tanto una carga descartada como una extensión incorrecta en una sola prueba. Compare ExternalLinks.Count antes y después de la reescritura. Y abra el archivo una vez en Excel con las macros deshabilitadas: la validación de tipos de contenido de Excel es más estricta que la de cualquier biblioteca y es el árbitro que usarán sus clientes.
Para recepción de alto volumen, no necesita un análisis completo solo para clasificar qué archivos contienen contenido gobernado: las técnicas ligeras de sondeo en nuestro artículo sobre listado de hojas e inspección ligera de libros permiten enviar libros con macros y vínculos a una canalización más estricta antes de cualquier reescritura.
Preguntas frecuentes
¿HotXLS ejecuta alguna vez las macros que conserva?
No. La biblioteca no tiene un entorno de ejecución VBA; almacena, copia, extrae e inyecta el proyecto como datos. Eso es una característica de seguridad en servidores: una macro maliciosa que pasa por una canalización HotXLS son bytes inertes hasta que una copia de escritorio de Excel abre el archivo y el usuario habilita el contenido.
¿Puedo convertir un .xlsm a .xlsx y conservar las macros?
No, y esa es una regla del formato de archivo, no de la biblioteca. El tipo de contenido .xlsx declara un libro sin macros, así que las únicas conversiones honestas son conservar .xlsm o llamar a ClearVbaProject y entregar un archivo realmente sin macros. Elija explícitamente; el comportamiento predeterminado de renombrar es lo peor de ambos mundos.
¿Por qué las celdas vinculadas muestran #REF! después de que mi servicio reescribe el libro?
El archivo reescrito conserva el destino del vínculo, pero no valores en caché, así que Excel debe resolver el destino al abrir. Si la ruta era relativa al entorno del autor original, o el recurso compartido no está disponible, la resolución falla. Garantice la accesibilidad del destino o elimine la dependencia escribiendo valores calculados en las celdas antes de la entrega.
Conservar lo que no se entiende es gran parte del trabajo al editar libros de otras personas. Las capacidades de ida y vuelta para VBA y vínculos descritas aquí se incluyen en HotXLS Component, junto con las propiedades de auditoría que se usan para detectar contenido gobernado durante la recepción.