Kuvittele tehtävä, joka ei tee juuri mitään: avaa kuukausittaisen työkirjan, kirjoittaa tämän päivän päivämäärän yhteen soluun ja tallentaa sen takaisin. Kun ajat tämän palvelun läpi riittävän monta kertaa, saat lopulta valituksen: makrot ovat kadonneet tai linkitetyt valuuttakurssit näyttävät nyt virhettä #REF!, ja ylläpito on vakuuttunut siitä, että koodisi poisti ne. Koodi ei poistanut mitään. Yleensä on käynyt niin, että makroja sisältävä työkirja tallennettiin tavallisella .xlsx-tiedostopäätteellä, ja Excel noudatti ECMA-376-sisältötyyppisääntöjä: paketti, jonka sisältötyyppi ei ilmoita VBA-tukea, ei voi ladata VBA-projektia — riippumatta siitä, ovatko tavut fyysisesti tallessa tiedostossa. Tiedosto ei rikkoutunut, mutta se nimettiin uudelleen tilaan, jossa Excelin on pakko ohittaa osa siitä
Makrot ja ulkoiset työkirjalinkit ovat ne kaksi asiaa, jotka automaatio hukkaa kaikkein herkimmin, ja vieläpä samasta syystä. Molemmat sijaitsevat soluverkoston ulkopuolella, johon muokkauskoodi todellisuudessa koskee, joten riveille ja sarakkeille rakennettu koodi pudottaa ne pois ilman nimenomaista poistokomentoa. HotXLS on natiivi Delphin ja C++Builderin kirjasto, joka lukee ja kirjoittaa XLS- ja XLSX-tiedostoja ilman asennettua Exceliä. Se käsittelee molempia resursseja hyötykuormina, joita se kantaa tarkoituksellisesti, eikä vain tietoina, jotka se sattuu kopioimaan. Seuraavassa käsitellään sitä, mitä kumpikin tarvitsee tallennuspolultasi ja mihin takuut päättyvät
Miksi nämä kaksi resurssia käyttäytyvät eri tavalla uudelleenkirjoituksessa
VBA-projekti on yksi suljettu binääritiedosto. OOXML-paketissa se on tiedosto vbaProject.bin; perinteisessä BIFF-tiedostossa se on OLE-säilytystila. On olemassa tarkalleen kaksi tapaa kadottaa se: kirjoittaja ei koskaan kopioi sitä tulosteeseen, tai tuloste saa tiedostotyypin, joka kieltää sen. Molemmat epäonnistumiset ovat täydellisiä ja hiljaisia. Projekti joko on mukana tai ei ole
Ulkoinen linkki ei ole lainkaan binääriblobi. Se on pieni suhdekaavio: kohdepolku tai URL, joka osoittaa toiseen työkirjaan, luettelo kyseisen kohteen paljastamista sivujen nimistä sekä valinnainen välimuisti viimeksi nähdyistä arvoista näillä sivuilla, jotta Excel voi näyttää jotain silloin, kun kohde on offline-tilassa. Näillä kolmella osalla on erilaiset elinkaaret uudelleenkirjoituksessa, ja kirjasto voi uskollisesti säilyttää osan ja samalla hiljaa pudottaa toiset pois. Tähän epäsymmetriaan kannattaa paneutua tarkasti, sillä mikään solumuokkauskoodissa ei tuo sitä esiin
VBA-projektin kuljettaminen XLSX-uudelleenkirjoituksen läpi
XLSX-puolella TXLSXWorkbook säilyttää makrohyötykuorman sanatarkasti. Ominaisuus VbaProject pitää sisällään raa'at vbaProject.bin-tavut AnsiString-muodossa, ja tyhjä merkkijono kertoo mallille, ettei makroja ole. Sen ympärillä on kolme toimintoa: HasVbaProject kertoo onko projekti läsnä, ClearVbaProject poistaa sen tarkoituksella ja LoadVbaProjectFromFile syöttää mallista uutetun projektin. Viimeinen kutsu on arvokkaampi kuin miltä se näyttää. Se antaa luotujen työkirjojen ottaa käyttöön vakiomuotoisen makroprojektin ilman, että koko mallitiedostoa tarvitsee vetää putken läpi
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;
Tallennusrivi on kohta, jossa koko ongelma kulminoituu. VBA-projektia sisältävä työkirja on kirjoitettava makrot sallivalla semantiikalla, ja HotXLS soveltaa sitä silloin, kun kohdenimi päättyy päätteeseen .xlsm. Jos annat sille sen sijaan päätteen .xlsx, Excel kieltäytyy suorittamasta makroja, vaikka tavut olisivat fyysisesti mukana paketissa ja purkautuisivat hienosti. Tiedostopääte ei ole pelkkä koriste; se valitsee sisältötyypin, joka kertoo Excelille, että VBA-projekti saa olla olemassa. Useimmiten sinun tarvitsee vain kuljettaa hyötykuorma mukana. Kun haluat lukea sitä — esimerkiksi listata moduulien nimet auditointiraporttia varten — ParsedVBAProject paljastaa jäsennetyn moduulimallin samalla kun VbaProject säilyy alkuperäisinä koskemattomina tavuina
Makrojen uudelleenkäyttö vanhoista XLS-työkirjoista
BIFF-rajapinta peilaa tätä työkalusarjaa yhdellä lisävaiheella. HasVBAProject tutkii ladattua tiedostoa, SaveVBAProjectToFile kirjoittaa projektin tallennustilan levylle ja LoadVBAProjectFromFile lukee sen takaisin toiseen työkirjaan. Mutka tiedoston kautta tekee yleisestä modernisointitehtävästä suoraviivaisen: nosta makrot pois vuoden 2003 aikaisesta mallista ja istuta ne tuoreeseen luotuun XLS-tulosteeseen ilman, että alkuperäistä mallia tarvitaan suoritusaikana
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;
Muistimalli on tässä sudenkuoppa, ja se toimii päinvastoin kuin XLSX-luokassa. TXLSWorkbook-oliota hallitaan viitelasketun IXLSWorkbook-rajapinnan kautta, joten et koskaan vapauta sitä käsin. XLSX-luokan TXLSXWorkbook taas on tavallinen olio, joka sinun on käärittävä try..finally-rakenteeseen ja vapautettava itse. Jos sekoitat nämä kaksi käytäntöä samassa yksikössä, seuraa kaksoisvapautuksesta (double-free) johtuvia kaatumisia. Vielä yksi raja, jota kannattaa kunnioittaa: pidä uuttaminen ja syöttäminen saman tiedostomuodon sisällä. BIFF-projekti ja OOXML-tiedosto vbaProject.bin ovat serkuksia, eivät sama säiliö, ja putkessa, jonka on tuotettava makroja molemmissa muodoissa, tulisi pitää erillinen makromalli kummallekin
Ulkoiset linkit: kartta säilyy, välimuistiin tallennetut arvot eivät
XLSX-työkirjoissa HotXLS tuo ulkoiset linkit näkyviin ExternalLinks-kokoelman kautta. Kukin TXLSXExternalLink kantaa mukanaan Target-tietoa, eli etätyökirjan polkua tai URL-osoitetta, sekä SheetNames-luetteloa, joka nimeää sen viittaamat sivut. Molemmat säilyvät ehjinä avaus- ja tallennussyklin läpi, ja voit myös rakentaa linkin alusta alkaen:
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;
Rajoitus sijaitsee yhtä tasoa syvemmällä kuin kohdeluettelo. HotXLS kuljettaa linkkikartan (eli kohteen ja sivujen nimet) edestakaisin, mutta se ei jäsennä tai kirjoita uudelleen välimuistiin tallennettuja soluarvoja, joita OOXML säilyttää linkin sheetDataSet-elementissä. Tuo välimuisti antaa Excelin näyttää viimeisimmän tunnetun numeron silloin, kun lähdetiedosto on offline-tilassa, ja luotu työkirja toimitetaan ilman sitä. Seuraukset kohtaavat vastaanottajan, eivät sinua. Jos avaat tällaisen tiedoston paikassa, jossa kohde on saavuttamattomissa — kuten kannettavalla tietokoneella VPN-verkon ulkopuolella tai uudelleennimetyssä jaossa — linkistä riippuvat kaavat ratkeavat virheeseen #REF! tai jumiutuvat päivityskehotteen taakse. Tästä seuraa kaksi sääntöä: Älä lupaa, että luotu työkirja näyttää ulkoisesti linkitetyt arvot offline-tilassa. Ja lue nollasta poikkeava ExternalLinks.Count toimituksen esiehdoksi eikä pelkäksi ominaisuudeksi — jokaisen kohteen on oltava saavutettavissa sieltä käsin, missä tiedosto todellisuudessa avataan
Mitä XLS-lukija säilyttää tavulleen samanlaisena
Rakenneosille, joita se ei mallinna, BIFF-puolella on toisenlainen vastaus: jätä ne juuri sellaisiksi kuin ne löytyivät. Pivot-välimuistit ja pivot-näkymät (SX*-tietueperhe), QueryTable-määritelmät, ulkoiset tietoyhteydet, mukautetut näkymät, ylätunnisteen kuvat ja teematiedot kulkevat kaikki avaus- ja tallennussyklin läpi raakoina tietuelohkoina, jäsentämättöminä ja muuttamattomina. Ulkoiset viittaukset itsessään kulkevat edestakaisin taustalla olevien EXTERNSHEET- ja SupBook-tietueiden kautta. Niille ei ole tyypitettyä luonti-API:a XLS-puolella, mutta olemassa oleva linkki säilyy muokkauksessa koskemattomana
Tavulleen tarkka säilyttäminen on aito takuu, jolla on terävä reuna. Koska mikään ei lue säilytettyä rakennetta, muokkauksesi eivät voi korruptoida sitä. Samasta syystä mikään ei myöskään päivitä sitä. Jos lisäät rivejä alueelle, johon säilytetty pivot-välimuisti tai kyselytaulukko osoittaa, rakenne säilyttää alkuperäiset koordinaattinsa samalla kun sen alla oleva tieto siirtyy. Tiedosto on edelleen kelvollinen XML- tai BIFF-tiedosto, mutta merkitys on hiljaa siirtynyt pois kohdallaan eikä mikään virhe ilmoita siitä. Turvallisin tapa on pitää luodut muokkaukset sivuilla, jotka eivät sisällä säilytettyjä rakenteita. Tämä on sama sääntö, joka suojaa lukittuja ja tulostusmääritettyjä sivuja, joita käsitellään artikkelissamme laskentataulukon suojauksesta ja sivunasetuksista
Itse kirjoittamasi tiedoston varmistaminen
Molemmat epäonnistumistilat ovat hiljaisia kirjoitusvaiheessa, joten merkitsevä varmistus tehdään avaamalla tuloste uudelleen sen sijaan, että luotettaisiin koodiin, joka sen tuotti. Kolme tarkistusta kattaa lähes kaiken. Avaa tiedosto uudelleen ja varmista, että HasVbaProject palauttaa edelleen arvon tosi aina kun makroja odotettiin. Tämä paljastaa pudonneen hyötykuorman ja väärän tiedostopäätteen yhdellä testillä. Lue ExternalLinks.Count ja vertaa sitä määrään ennen uudelleenkirjoitusta. Avaa tiedosto kerran Excelissä makrot poissa käytöstä, sillä Excelin sisältötyyppien tarkistus on tiukempi kuin minkään kirjaston, ja Excel on ohjelma, jolla asiakkaasi tiedostoa arvioivat
Mikään tästä ei vaadi täyttä jäsentämistä sisäänluvun yhteydessä. Kun työkirjoja saapuu suuria määriä ja haluat vain luokitella mitkä niistä sisältävät hallittua sisältöä, kevyt tutkimus, jota käsitellään artikkelissamme sivuluetteloista ja työkirjojen kevyestä tarkastuksesta, antaa sinun ohjata makroja sisältävät ja linkitetyt tiedostot tiukempaan putkeen ennen kuin ensimmäinenkään uudelleenkirjoitus alkaa
Muutamaan kysymykseen vastataan tässä suoraan. HotXLS ei koskaan suorita säilyttämiään makroja: kirjastossa ei ole VBA-ajonaikaista ympäristöä, vain koneisto projektin tallentamiseen, kopioimiseen, uuttamiseen ja syöttämiseen datana. Palvelimella tämä on mainitsemisen arvoinen tietoturvaominaisuus, sillä putken läpi kulkeva haitallinen makro pysyy toimettomana, kunnes työpöytä-Excel avaa tiedoston ja käyttäjä sallii sisällön. Tiedoston .xlsm muuntaminen tiedostoksi .xlsx makrot säilyttäen ei ole mahdollista, ja tämä on formaatin sääntö eikä kirjaston rajoitus: .xlsx-sisältötyyppi ilmoittaa työkirjan olevan makroton, joten ainoat rehelliset vaihtoehdot ovat pysyä .xlsm-muodossa tai kutsua ClearVbaProject-metodia ja toimittaa tiedosto, jossa niitä ei todellisuudessa ole. Hiljainen nimeäminen on vaihtoehto, joka ei tyydytä ketään. Ja kun linkitetyt solut näyttävät uudelleenkirjoituksen jälkeen virhettä #REF!, syynä on edellä käsitelty puuttuva arvojen välimuisti: uusi tiedosto kantaa kohteen mutta ei välimuistiin tallennettuja numeroita, joten Excelin on selvitettävä lähde avaushetkellä, ja saavuttamaton tai ympäristöriippuvainen polku estää sen. Joko takaa kohteen saavutettavuus tai kirjoita lasketut arvot soluihin ennen toimitusta ja pudota riippuvuus kokonaan pois
Muiden ihmisten työkirjojen muokkaaminen on pääasiassa sellaisten asioiden säilyttämistä, joita et ole kirjoittanut etkä täysin ymmärrä. Tässä kuvatut VBA- ja ulkoisten linkkien round-trip-ominaisuudet toimitetaan HotXLS Component -kirjastossa Delphille ja C++Builderille, yhdessä auditointiominaisuuksien kanssa, joiden avulla voit havaita hallitun sisällön heti tiedoston saapuessa