Zamislite posao koji ne radi skoro ništa: otvori mesečnu radnu svesku, upiše današnji datum u jednu ćeliju i sačuva je nazad. Pustite to kroz servis dovoljno često i pritužba ipak stigne. Makroi su nestali, ili povezani devizni kursevi sada pokazuju #REF!, a operativni tim je ubeđen da ih je vaš kod obrisao. Ništa nije obrisao. Obično se desilo to da je radna sveska sa makroima izašla pod običnim .xlsx imenom, a Excel je poslušao pravila tipova sadržaja iz ECMA-376: paket čiji tip sadržaja ne objavljuje VBA ne može da učita VBA projekat, bez obzira na to što bajtovi sede tu. Fajl se nije pokvario. Preimenovan je u stanje u kom je Excel dužan da zanemari deo njega
Makroi i spoljne veze ka radnim sveskama su dve stvari koje automatizacija najpouzdanije gubi, i to iz istog dubljeg razloga. Oba žive izvan mreže ćelija koju kod za uređivanje zapravo dira, pa će ih kod koji razmišlja u redovima i kolonama ispustiti a da nikada ne izda naredbu brisanja. HotXLS je izvorna biblioteka za Delphi i C++Builder koja čita i piše XLS i XLSX bez instaliranog Excela, i oba resursa tretira kao sadržaj koji namerno prenosi, a ne kao podatke koje uzgred kopira. Sledi šta svaki od njih traži od vaše putanje čuvanja i gde jemstva prestaju
Zašto se ova dva resursa različito ponašaju pri prepisivanju
VBA projekat je jedan neprozirni binarni zapis. U OOXML paketu to je fajl vbaProject.bin; u nasleđenom BIFF fajlu to je OLE skladište. Postoje tačno dva načina da se izgubi: upisivač ga nikada ne prekopira u izlaz, ili izlaz dobije tip fajla koji ga zabranjuje. Oba otkaza su potpuna i nečujna. Projekat ili postoji ili ne postoji
Spoljna veza uopšte nije jedan blok. Ona je mali graf odnosa: ciljna putanja ili URL koji pokazuje na drugu radnu svesku, spisak imena listova koje taj cilj izlaže i opcioni keš vrednosti poslednje viđenih u tim listovima da bi Excel imao šta da pokaže kada je cilj nedostupan. Ta tri dela imaju različit vek pri prepisivanju, pa biblioteka može verno da sačuva neke, a druge tiho ispusti. Ta nesimetrija je deo oko kog vredi biti precizan, jer je ništa u kodu za uređivanje ćelija neće izneti na površinu
Prenošenje VBA projekta kroz XLSX prepisivanje
Na XLSX strani, TXLSXWorkbook čuva sadržaj makroa doslovno. Svojstvo VbaProject drži sirove bajtove fajla vbaProject.bin unutar tipa AnsiString, a prazan string je način na koji model kaže da makroa nema. Oko njega stoje tri operacije: HasVbaProject odgovara da li projekat postoji, ClearVbaProject ga namerno uklanja, a LoadVbaProjectFromFile ubacuje onaj izvučen iz šablona. Taj poslednji poziv vredi više nego što izgleda. On omogućava generisanim radnim sveskama da preuzmu standardni projekat makroa bez vučenja celog fajla šablona kroz lanac
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');
// Nastavak .xlsm nije ukras: on bira tip sadržaja sa
// omogućenim makroima unutar paketa.
Book.SaveAs('monthly-report.xlsm');
finally
Book.Free;
end;
end;
Linija sa čuvanjem je mesto gde se ceo problem prelama. Radna sveska koja drži VBA projekat mora da se upiše sa semantikom omogućenih makroa, a HotXLS je primenjuje kada se ciljno ime završava na .xlsm. Predajte mu .xlsx i Excel odbija makroe, iako su bajtovi fizički prisutni u paketu i uredno bi se deserijalizovali. Nastavak nije ukras; on bira tip sadržaja koji Excelu govori da VBA projekat sme da postoji. Najčešće vam treba samo da sadržaj prenesete. Kada treba da uđete u njega, recimo da nabrojite imena modula za izveštaj revizije, ParsedVBAProject izlaže parsiran model modula dok VbaProject ostaje netaknuti izvorni niz bajtova
Ponovna upotreba makroa iz nasleđenih XLS radnih sveski
BIFF fasada preslikava taj skup alata uz jedan dodatni korak. HasVBAProject ispituje učitani fajl, SaveVBAProjectToFile upisuje skladište projekta na disk, a LoadVBAProjectFromFile ga učitava nazad u drugu radnu svesku. Zaobilazak preko fajla čini uobičajen posao modernizacije jednostavnim: podignite makroe iz modela iz 2003. godine i posadite ih u sveže generisan XLS izlaz, bez potrebe za izvornim šablonom u vreme izvršavanja
var
Src, Dst: IXLSWorkbook; // reference na interfejs: bez ručnog 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;
Model memorije je ovde zamka, i ide suprotno od XLSX klase. TXLSWorkbook se drži kroz interfejs IXLSWorkbook sa brojanjem referenci, pa ga nikada ne oslobađate ručno; XLSX TXLSXWorkbook je običan objekat koji morate obaviti u try..finally i osloboditi. Pomešajte te dve konvencije u jednom modulu i slede rušenja zbog dvostrukog oslobađanja. Još jedna granica koju vredi poštovati: držite izvlačenje i ubacivanje unutar jednog formata fajla. BIFF skladište projekta i OOXML vbaProject.bin su rođaci, a ne isti kontejner, pa lanac koji makroe mora da emituje u oba formata treba da drži odvojen šablon makroa za svaki
Spoljne veze: mapa preživljava, keširane vrednosti ne
Za XLSX radne sveske, HotXLS izlaže spoljne veze kroz zbirku ExternalLinks. Svaka TXLSXExternalLink nosi Target, putanju ili URL udaljene radne sveske, plus listu SheetNames koja imenuje listove na koje se poziva. Oboje preživljava ciklus otvaranja i čuvanja netaknuto, a vezu možete i sagraditi od nule:
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;
Granica leži jedan nivo dublje od liste ciljeva. HotXLS provlači mapu veze kroz ciklus, dakle cilj i imena listova, ali ne parsira niti prepisuje keširane vrednosti ćelija koje OOXML drži u elementu sheetDataSet te veze. Taj keš je ono što Excelu omogućava da pokaže poslednji poznat broj kada je izvorni fajl nedostupan, a generisana radna sveska stiže bez njega. Posledica pada na primaoca, ne na vas. Otvorite takav fajl tamo gde je cilj nedostupan, na laptopu van VPN-a ili na deljenom mestu koje je preimenovano, i formule koje zavise od veze razrešavaju se u #REF! ili zastanu iza upita za ažuriranje. Iz toga proizlaze dva pravila. Ne obećavajte da će generisana radna sveska prikazati svoje spolja povezane vrednosti van mreže. I čitajte ExternalLinks.Count različit od nule kao preduslov isporuke, a ne kao funkciju: svaki cilj mora da bude dostupan odande gde će fajl zaista biti otvoren
Šta XLS čitač čuva bajt u bajt
Za strukture koje ne modeluje, BIFF strana ima drugačiji odgovor: ostavi ih tačno onakvima kakve su nađene. Pivot kešovi i pivot prikazi (porodica zapisa SX*), definicije QueryTable objekata, spoljne veze ka podacima, prilagođeni prikazi, slike u zaglavlju i zapisi teme, svi prolaze kroz ciklus otvaranja i čuvanja kao sirovi blokovi zapisa, neparsirani i neizmenjeni. Same spoljne reference kruže kroz osnovne zapise EXTERNSHEET i SupBook. Za njih na XLS strani nema tipiziranog API-ja za stvaranje, ali postojeća veza preživljava uređivanje netaknuta
Čuvanje bajt u bajt je pravo jemstvo sa oštrom ivicom. Pošto očuvanu strukturu niko ne čita, vaše izmene ne mogu da je pokvare. Iz istog razloga je niko ni ne ažurira. Umetnite redove kroz oblast na koju pokazuje očuvan pivot keš ili tabela upita, i struktura zadržava svoje prvobitne koordinate dok se podaci ispod pomeraju. Fajl je i dalje ispravan XML ili BIFF; značenje je tiho izašlo iz poravnanja, a nijedna greška se ne javlja da vam to kaže. Odbranjiv raspored je da generisane izmene držite na listovima bez očuvanih struktura, što je ista disciplina koja štiti zaključane i za štampu podešene listove u našem članku o zaštiti radnog lista i podešavanju stranice
Provera fajla koji ste zaista upisali
Oba režima otkaza nečujna su u trenutku upisa, pa se tvrdnja koja se računa iznosi ponovnim otvaranjem izlaza, a ne poverenjem u kod koji ga je napravio. Tri provere pokrivaju gotovo sve. Ponovo otvorite fajl i potvrdite da HasVbaProject i dalje vraća tačno kad god su se makroi očekivali, čime jednim testom hvatate i ispušten sadržaj i pogrešan nastavak. Pročitajte ExternalLinks.Count i uporedite ga sa brojem od pre prepisivanja. Pa jednom otvorite fajl u Excelu sa onemogućenim makroima, jer je Excelova provera tipa sadržaja stroža od provere bilo koje biblioteke, a Excel je program po kom će vaši kupci suditi o fajlu
Ništa od toga ne traži pun parsing na ulazu. Kada radne sveske stižu u velikom broju, a vama treba samo da razvrstate koje nose upravljan sadržaj, lako ispitivanje iz našeg članka o listanju listova i lakom pregledu radnih sveski omogućava vam da fajlove sa makroima i vezama usmerite u stroži lanac pre nego što se prvo prepisivanje uopšte pokrene
Nekoliko pitanja se javlja dovoljno često da zaslužuje neposredan odgovor. HotXLS nikada ne izvršava makroe koje čuva: u biblioteci nema VBA izvršnog okruženja, samo mašinerija da se projekat kao podatak sačuva, kopira, izvuče i ubaci. Na serveru je to bezbednosno svojstvo koje vredi izreći, jer neprijateljski makro koji prolazi kroz lanac ostaje bezopasan dok Excel na radnoj stanici ne otvori fajl i korisnik ne dozvoli sadržaj. Pretvaranje .xlsm u .xlsx uz zadržavanje makroa nije moguće, a to je pravilo formata, a ne ograničenje biblioteke: tip sadržaja .xlsx objavljuje radnu svesku bez makroa, pa su jedini pošteni ishodi ostanak na .xlsm ili poziv ClearVbaProject uz isporuku fajla koji ih zaista nema. Tiho preimenovanje je jedini izbor koji ne zadovoljava nikoga. A kada povezane ćelije posle prepisivanja pokažu #REF!, uzrok je keš vrednosti koji nedostaje, o kom je bilo reči: novi fajl nosi cilj, ali ne i keširane brojeve, pa Excel mora da razreši izvor pri otvaranju, a nedostupna ili od okruženja zavisna putanja to obara. Ili jemčite da je cilj dostupan ili pre isporuke upišite izračunate vrednosti u ćelije pa zavisnost potpuno uklonite
Uređivanje tuđih radnih sveski uglavnom je posao čuvanja stvari koje niste napisali i ne razumete do kraja. Mogućnosti kruženja VBA projekata i spoljnih veza opisane ovde stižu uz HotXLS Delphi Component za Delphi i C++Builder, zajedno sa svojstvima za reviziju koja vam omogućavaju da upravljan sadržaj otkrijete čim fajl stigne