Teknisk artikkel

Bevaring av VBA-makroer og eksterne lenker når Delphi-kode skriver om en arbeidsbok

Tenk på en jobb som nesten ikke gjør noe: åpne en månedlig arbeidsbok, skrive dagens dato i én celle, og lagre den igjen. Kjør dette gjennom en tjeneste ofte nok, og en klage vil likevel komme. Makroene er borte, eller de koblede valutakursene viser nå #REF!, og driftsteamet er overbevist om at koden din slettet dem. Den slettet ingenting. Det som vanligvis skjedde, var at en makroaktivert arbeidsbok ble sendt ut under et vanlig .xlsx-navn, og Excel fulgte ECMA-376-reglene for innholdstyper: en pakke hvis innholdstype ikke deklarerer VBA, kan ikke laste et VBA-prosjekt, uavhengig av om bytene faktisk ligger der. Filen ble ikke ødelagt. Den wurde omdøpt til en tilstand der Excel er pålagt å ignorere deler av den

Makroer og eksterne arbeidsboklenker er de to tingene automatisering mister mest pålitelig, av samme underliggende årsak. Begge lever utenfor cellenettet som redigeringskoden faktisk berører, så kode som tenker i rader og kolonner vil utelate dem uten noen gang å utføre en sletting. HotXLS er et opprinnelig Delphi- og C++Builder-bibliotek som leser og skriver XLS og XLSX uten Excel installert, og det behandler begge deler som nyttelaster det bærer bevisst, snarere enn data det tilfeldigvis kopierer. Det som følger er hva hver av dem trenger fra lagringsbanen din, og hvor garantiene stopper

Hvorfor disse to elementene oppfører seg forskjellig under en omskriving

Et VBA-prosjekt er en ugjennomsiktig binærfil. I en OOXML-pakke er det filen vbaProject.bin; i en eldre BIFF-fil er det et OLE-lager. Det er akkurat to måter å miste det på: skriveren kopierer det aldri til utdataene, eller utdataene får en filtype som forbyr det. Begge feilene er totale og lydløse. Prosjektet er til stede eller så er det ikke

En ekstern lenke er ikke en blob i det hele tatt. Det is a small graph of relationships: a target path or URL pointing at another workbook, the list of sheet names that target exposes, and an optional cache of the values last seen in those sheets so Excel can show something when the target is offline. Disse tre delene har ulik levetid under en omskriving, og et bibliotek kan bevare noen pålitelig, mens andre droppes i det stille. Den asymmetrien er det verdt å være nøyaktig med, fordi ingenting i celle-redigeringskoden vil avdekke det

Å føre et VBA-prosjekt gjennom en XLSX-omskriving

På XLSX-siden beholder TXLSXWorkbook makronyttelasten ordrett. Egenskapen VbaProject holder de rå vbaProject.bin-bytene i en AnsiString, og en tom streng er hvordan modellen sier at det ikke finnes makroer. Rundt den sitter tre operasjoner: HasVbaProject svarer på om et prosjekt er til stede, ClearVbaProject fjerner det med vilje, og LoadVbaProjectFromFile setter inn et prosjekt som er pakket ut fra en mal. Det siste kallet er verdt mer enn det ser ut til. Det gjør at genererte arbeidsbøker kan hente et standard makroprosjekt uten å måtte dra en hel mal-fil gjennom pipelinen

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;

Gjenbruke makroer fra eldre XLS-arbeidsbøker

BIFF-fasaden speiler det verktøysettet med et ekstra trinn. HasVBAProject undersøker en lastet fil, SaveVBAProjectToFile skriver prosjektlageret til disken, og LoadVBAProjectFromFile leser ett tilbake inn i en annen arbeidsbok. Omveien gjennom en fil gjør en vanlig moderniseringsoppgave enkel: løft makroene ut av en modell fra 2003-tiden og plasser dem i ferskt genererte XLS-utdata, uten at den opprinnelige malen kreves ved kjøring

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;

Minnemodellen er fellen her, og den fungerer motsatt av XLSX-klassen. TXLSWorkbook holdes gjennom det referansetelte IXLSWorkbook-grensesnittet, så du frigjør det aldri manuelt; XLSX TXLSXWorkbook er et vanlig objekt du må pakke inn i try..finally og frigjøre. Bland de to konvensjonene i samme enhet, og krasj på grunn av dobbel frigjøring (double-free) følger. Nok en grense det er verdt å respektere: hold utpakking og innsetting innenfor ett enkelt filformat. BIFF-prosjektlageret og OOXML-filen vbaProject.bin er beslektet, men ikke samme beholder, og en pipeline som må levere makroer i begge formater bør ha en egen makromal for hver

Eksterne lenker: kartet overlever, de bufrede verdiene gjør det ikke

For XLSX-arbeidsbøker eksponerer HotXLS eksterne lenker gjennom samlingen ExternalLinks. Hver TXLSXExternalLink bærer et Target, stien eller URL-en til den eksterne arbeidsboken, pluss en SheetNames-liste som navngir arkene den refererer til. Begge overlever en åpne-og-lagre-syklus intakt, og du kan også bygge en lenke fra bunnen av

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;

Grensen sitter ett nivå dypere enn mållisten. HotXLS kjører lenkekartet tur-retur, det vil si målet og arknavnene, men tolker eller skriver ikke om de bufrede celleverdiene som OOXML beholder i lenkens sheetDataSet-element. Den bufferen er det som lar Excel vise et sist kjent tall når kildefilen er offline, og en generert arbeidsbok sendes uten dette. Konsekvensen lander på mottakeren, ikke på deg. Åpnes en slik fil der målet er utilgjengelig (en bærbar datamaskin utenfor VPN eller en delt ressurs som har blitt omdøpt), vil formlene som avhenger av lenken løses opp til #REF! eller stoppe bak en oppdateringsmelding. Så to regler følger av dette: Ikke lov at en generert arbeidsbok vil vise sine eksternt koblede verdier offline, og les en ExternalLinks.Count som er større enn null som en forutsetning for levering snarere enn en funksjon: ethvert mål må være tilgjengelig fra der filen faktisk vil bli åpnet

Hva XLS-leseren bevarer byte for byte

For strukturer den ikke modellerer, BIFF-siden har et annet svar: la dem være akkurat slik de ble funnet. Pivot-buffere og pivot-visninger (SX*-postfamilien), QueryTable-definisjoner, eksterne datatilkoblinger, tilpassede visninger, overskriftsbilder og temaposter går alle gjennom en åpne-og-lagre-syklus som rå postblokker, utolket og uendret. Eksterne referanser i seg selv går tur-retur gjennom de underliggende EXTERNSHEET- og SupBook-postene. Det finnes ikke noe type-definert opprettelses-API for dem på XLS-siden, og en eksisterende lenke overlever redigering uberørt

Bevaring byte for byte er en reell garanti med en skarp kant. Fordi ingenting leser en bevart struktur, kan ikke redigeringene dine ødelegge den. Av samme grunn er det heller ingenting som oppdaterer den. Sett inn rader gjennom et område som en bevart pivot-buffer eller querytabell peker på, og strukturen beholder sine opprinnelige koordinater mens dataene under flytter seg. Filen er fremdeles gyldig XML eller BIFF; meningen har i det stille glidd ut av justering, og ingen feil utløses for å fortelle deg det. Den forsvarlige layouten er å beholde genererte redigeringer på ark som ikke inneholder bevarte strukturer, som er den samme disiplinen som beskytter låste og utskriftskonfigurerte ark i artikkelen vår om regnearkbeskyttelse og sideoppsett

Verifisere filen du faktisk skrev

Begge feilmodusene er lydløse ved skrivetidspunktet, så bekreftelsen som betyr noe gjøres ved å åpne utdataene på nytt i stedet for å stole på koden som produserte dem. Tre sjekker dekker nesten alt. Åpne filen på nytt og bekreft at HasVbaProject fremdeles returnerer sant når det var forventet makroer, noe som fanger opp en mistet nyttelast og en feil filendelse i én enkelt test. Les ExternalLinks.Count og sammenlign det med antallet før omskrivingen. Åpne deretter filen én gang i Excel med makroer deaktivert, fordi Excels innholdstype-validering er strengere enn noe biblioteks, og Excel er programmet kundene dine vil vurdere filen etter

Ingenting av dette krever en fullstendig tolking på vei inn. Når arbeidsbøker ankommer i store mengder og du bare trenger å sortere hvilke som har regulert innhold, lar den lette undersøkelsen i artikkelen vår om ark-opplisting og lett arbeidsbok-inspeksjon deg rute makro- og lenkede filer inn i en strengere pipeline før den første omskrivingen kjører

Noen få spørsmål dukker opp ofte nok til å besvares direkte. HotXLS kjører aldri makroene det bevarer: det er ingen VBA-kjøretidsmiljø i biblioteket, bare mekanismen for å lagre, kopiere, hente ut og sette inn prosjektet som data. På en server er dette en sikkerhetsegenskap verdt å nevne, siden en fiendtlig makro som passerer gjennom pipelinen forblir inaktiv til en stasjonær Excel åpner filen og en bruker aktiverer innholdet. Å konvertere en .xlsm til .xlsx og beholde makroene er ikke mulig, og det er formatets regel snarere enn en biblioteksbegrensning: innholdstypen .xlsx deklarerer en makrofri arbeidsbok, så de eneste ærlige resultatene er å forbli .xlsm eller kalle ClearVbaProject og sende en fil som genuint ikke har noen. Den stille omdøpingen er det ene valget som ikke tilfredsstiller noen. Og når koblede celler viser #REF! etter en omskriving, er årsaken den manglende verdibufferen som ble diskutert ovenfor: den nye filen bærer målet, men ikke de bufrede tallene, så Excel må slå opp kilden ved åpningstidspunktet, og en utilgjengelig eller miljø-relativ sti hindrer det. Enten garanter at målet er tilgjengelig, eller skriv beregnede verdier inn i cellene før levering og dropp avhengigheten helt

Redigering av andres arbeidsbøker handler mest om å bevare ting du ikke har skrevet og ikke fullt ut forstår. Tur-retur-mekanismene for VBA og eksterne lenker beskrevet her leveres med HotXLS Component for Delphi og C++Builder, sammen med revisjonsegenskapene som lar deg oppdage regulert innhold i det øyeblikket en fil ankommer