Luați în considerare o sarcină care nu face aproape nimic: deschide un registru de lucru lunar, scrie data de astăzi într-o celulă și îl salvează înapoi. Rulați această operațiune destul de des printr-un serviciu și veți primi în cele din urmă o plângere. Macrocomenzile au dispărut sau cursurile de schimb legate afișează acum #REF!, iar echipa de operațiuni este convinsă că codul dvs. le-a șters. Acesta nu a șters nimic. Ceea ce s-a întâmplă de obicei este că un registru de lucru cu macrocomenzi activate a fost salvat cu o extensie simplă .xlsx, iar Excel a aplicat regulile de tip de conținut ECMA-376: un pachet al cărui tip de conținut declară că nu conține VBA nu poate încărca un proiect VBA, indiferent dacă acei octeți se află fizic acolo. Fișierul nu s-a defectat, ci a fost redenumit într-o stare în care Excel este obligat să ignore o parte din el
Macrocomenzile și legăturile externe către alte registre de lucru sunt cele două elemente pe care automatizarea le pierde cel mai des, din același motiv de bază. Ambele se află în afara grilei de celule pe care o modifică codul de editare, astfel încât codul care procesează datele doar sub formă de rânduri și coloane le va elimina fără a lansa vreun ordin de ștergere. HotXLS este o bibliotecă nativă pentru Delphi și C++Builder care citește și scrie fișiere XLS și XLSX fără a necesita instalarea Excel și tratează ambele elemente ca pe sarcini utile pe care le transportă în mod deliberat, nu ca pe date pe care le copiază din întâmplare. În continuare, vom vedea ce necesită fiecare element din calea de salvare și unde se termină garanțiile oferite
De ce aceste două elemente se comportă diferit la o rescriere
Un proiect VBA este un fișier binar opac. Într-un pachet OOXML, acesta este fișierul vbaProject.bin; într-un fișier vechi BIFF, este un spațiu de stocare OLE. Există exact două moduri de a-l pierde: programul de scriere nu îl copiază niciodată în datele de ieșire sau datele de ieșire primesc un tip de fișier care îl interzice. Oricare dintre aceste eșecuri este total și silențios — proiectul este prezent sau nu este
O legătură externă nu este deloc un blob. Este un grafic mic de relații: o cale țintă sau un URL care trimite la un alt registru de lucru, lista numelor de foi pe care le expune acea țintă și o memorie cache opțională a ultimelor valori înregistrate în acele foi, astfel încât Excel să poată afișa ceva când ținta este offline. Aceste trei secțiuni au durate de viață diferite la o rescriere, iar o bibliotecă poate conserva fidel unele dintre ele, în timp ce pe altele le elimină în mod silențios. Această asimetrie merită definită cu precizie, deoarece nimic din codul de editare a celulelor nu o va evidenția
Transferul unui proiect VBA printr-o rescriere XLSX
Pe partea XLSX, clasa TXLSXWorkbook păstrează conținutul macrocomenzilor intact. Proprietatea VbaProject stochează octeții bruți ai fișierului vbaProject.bin într-un format AnsiString, iar un șir gol indică absența macrocomenzilor. În jurul acesteia se află trei operațiuni: HasVbaProject verifică prezența unui proiect, ClearVbaProject îl elimină în mod deliberat, iar LoadVbaProjectFromFile introduce un proiect extras dintr-un șablon. Acest ultim apel este mai util decât pare, deoarece permite registrelor de lucru generate să preia un proiect standard de macrocomenzi fără a trece un fișier șablon complet prin linia de procesare
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;
Linia de salvare este locul în care se concentrează întreaga problemă. Un registru de lucru care conține un proiect VBA trebuie salvat cu semantica macrocomenzilor activate, iar HotXLS o aplică atunci când numele țintă se termină în .xlsm. Salvați-l ca .xlsx și Excel va respinge macrocomenzile, chiar dacă octeții sunt fizic prezenți în pachet și s-ar dezarhiva corect. Extensia nu este un element decorativ; ea selectează tipul de conținut care indică programului Excel că un proiect VBA are permisiunea să existe. De cele mai multe ori trebuie doar să transferați conținutul. Când doriți să îl citiți, de exemplu pentru a lista numele modulelor într-un raport de audit, proprietatea ParsedVBAProject expune un model de modul analizat, în timp ce VbaProject păstrează octeții originali neatinși
Reutilizarea macrocomenzilor din registrele de lucru vechi XLS
Structura BIFF reflectă acest set de instrumente cu un pas suplimentar. Metoda HasVBAProject verifică un fișier încărcat, SaveVBAProjectToFile scrie spațiul de stocare al proiectului pe disc, iar LoadVBAProjectFromFile îl citește înapoi într-un alt registru de lucru. Această trecere printr-un fișier simplifică o sarcină comună de modernizare: extragerea macrocomenzilor dintr-un model din era 2003 și integrarea lor în datele de ieșire XLS proaspăt generate, fără a fi nevoie de șablonul original la rulare
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;
Modelul de memorie reprezintă capcana în acest caz și funcționează invers față de clasa XLSX. Clasa TXLSWorkbook este gestionată prin interfața cu contorizare a referințelor IXLSWorkbook, așa că nu o eliberați niciodată manual; clasa XLSX TXLSXWorkbook este un obiect simplu pe care trebuie să îl încadrați în try..finally și să îl eliberați. Combinarea celor două convenții într-o singură unitate poate duce la blocaje din cauza eliberării duble. O altă limită care trebuie respectată: mențineți extracția și injectarea în cadrul aceluiași format de fișier. Spațiul de stocare al proiectului BIFF și fișierul OOXML vbaProject.bin sunt înrudite, dar nu reprezintă același container, iar o linie de procesare care trebuie să emită macrocomenzi în ambele formate ar trebui să mențină un șablon de macrocomenzi separat pentru fiecare
Legăturile externe: harta supraviețuiește, valorile din cache nu
Pentru registrele de lucru XLSX, HotXLS expune legăturile externe prin intermediul colecției ExternalLinks. Fiecare TXLSXExternalLink conține o proprietate Target — calea sau URL-ul registrului de lucru de la distanță — plus o lista SheetNames care specifică foile pe care le referențiază. Ambele supraviețuiesc intacte unui ciclu de deschidere și salvare, putând de asemenea să construiți o legătură de la zero:
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;
Limita se află cu un nivel mai jos decât lista de ținte. HotXLS efectuează procesul complet pentru structura legăturilor, adică ținta și numele foilor, însă nu analizează și nu rescrie valorile celulelor din cache pe care OOXML le păstrează în elementul sheetDataSet al legăturii. Aceeași memorie cache este cea care permite programului Excel să afișeze ultima valoare cunoscută atunci când fișierul sursă este offline, iar un registru generat este livrat fără ea. Consecința îl afectează pe destinatar, nu pe dvs. Deschideți un astfel de fișier în care ținta este inaccesibilă — un laptop deconectat de la VPN sau o partajare redenumită — iar formulele care depind de legătură vor returna #REF! sau se vor bloca în spatele unei solicitări de actualizare. Așadar, din aceasta rezultă două reguli: Nu promiteți că un registru generat va afișa offline valorile sale legate extern; Și interpretați o valoare diferită de zero a ExternalLinks.Count ca pe o precondiție de livrare, nu ca pe o caracteristică — fiecare țintă trebuie să fie accesibilă din locația în care va fi deschis efectiv fișierul
Ce conservă cititorul XLS octet cu octet
Pentru structurile pe care nu le modelează, partea BIFF are o abordare diferită: le lasă exact așa cum le-a găsit. Memoriile cache și vizualizările pivot (familia de înregistrări SX*), definițiile QueryTable, conexiunile de date externe, vizualizările personalizate, imaginile de antet și înregistrările de temă trec toate printr-un ciclu de deschidere și salvare ca blocuri de înregistrări brute, neanalizate și nemodificate. Referințele externe în sine trec prin înregistrările subiacente EXTERNSHEET și SupBook. Nu există o interfață API de creare tipizată pentru acestea pe partea XLS, însă o legătură existentă supraviețuiește editării fără a fi afectată
Păstrarea octet cu octet reprezintă o garanție reală cu riscuri asociate. Deoarece nimic nu citește o structură conservată, editările dvs. nu o pot corupe. Din același motiv, nimic nu o actualizează. Introduceți rânduri într-o regiune spre care indică o memorie cache pivot sau un tabel de interogare conservat, iar structura își va păstra coordonatele originale, în timp ce datele de dedesubt se decalează. Fișierul este în continuare un XML sau un BIFF valid, însă semnificația s-a modificat în mod silențios și nu se va declanșa nicio eroare care să vă anunțe. Structura recomandată este să păstrați editările generate pe foi care nu conțin structuri conservate, fiind aceeași disciplină care protejează foile blocate și configurate pentru imprimare prezentată în articolul nostru despre protecția foilor de calcul și configurarea paginii
Verificarea fișierului pe care l-ați scris în realitate
Ambele moduri de eșec sunt silențioase la scriere, așa că verificarea esențială se face prin redeschiderea rezultatului, nu prin încrederea în codul care l-a generat. Trei verificări acoperă aproape totul: redeschideți fișierul și confirmați că HasVbaProject returnează în continuare true ori de câte ori se așteptau macrocomenzi, ceea ce identifică un conținut pierdut și o extensie greșită într-un singur test; citiți valoarea ExternalLinks.Count și comparați-o cu valoarea de dinaintea rescrierii; deschideți fișierul o dată în Excel cu macrocomenzile dezactivate, deoarece validarea tipului de conținut realizată de Excel este mai strictă decât a oricărei biblioteci, iar Excel este programul după care clienții dvs. vor evalua fișierul
Nimic din toate acestea nu necesită o analiză completă la import. Când registrele de lucru sosesc în volum mare și trebuie doar să triați care dintre ele conțin elemente controlate, verificarea rapidă prezentată în articolul nostru despre listarea foilor și inspectarea rapidă a registrelor vă permite să direcționați fișierele cu macrocomenzi și legături într-o linie de procesare mai strictă înainte de rularea primei rescrieri
Întrebări frecvente
Câteva întrebări apar suficient de des pentru a primi un răspuns direct. HotXLS nu execută niciodată macrocomenzile pe care le conservă: nu există un runtime VBA în bibliotecă, ci doar mecanismele pentru a stoca, copia, extrage și injecta proiectul ca date. Pe un server, aceasta este o proprietate de securitate care merită menționată, deoarece o macrocomandă periculoasă care trece prin linia de procesare rămâne inactivă până când o aplicație Excel de desktop deschide fișierul și un utilizator activează conținutul. Conversia unui fișier .xlsm în .xlsx cu păstrarea macrocomenzilor nu este posibilă, aceasta fiind o regulă a formatului, nu o limitare a bibliotecii: tipul de conținut .xlsx declară un registru de lucru fără macrocomenzi, așa că singurele opțiuni corecte sunt păstrarea formatului .xlsm sau apelarea ClearVbaProject și livrarea unui fișier care nu conține deloc macrocomenzi. Redenumirea silențioasă este singura opțiune care nu mulțumește pe nimeni. Iar când celulele legate afișează #REF! după o rescriere, cauza este lipsa memoriei cache a valorilor menționată mai sus: noul fișier conține ținta, dar nu și valorile stocate în cache, astfel încât Excel trebuie să rezolve sursa la deschidere, iar o cale inaccesibilă sau relativă la mediu împiedică acest lucru. Fie garantați că ținta este accesibilă, fie scrieți valorile calculate în celule înainte de livrare și eliminați complet dependența
Editarea registrelor de lucru generate de alții reprezintă în mare parte sarcina de a conserva elemente pe care nu le-ați scris și nu le înțelegeți pe deplin. Facilitățile pentru procese complete privind macrocomenzile VBA și legăturile externe descrise aici sunt livrate cu HotXLS Component pentru Delphi și C++Builder, alături de proprietățile de audit care vă permit să detectați conținutul controlat în momentul în care fișierul este recepționat