Teknisk artikkel

HotXLS: Arkskydd, sideoppsett og utskrift i Delphi

Tre grupper av arkinnstillinger har ingenting med celleverdiene å gjøre og alt med hvordan filen oppfører seg når den forlater koden din. Arkbeskyttelse avgjør hvilke celler en bruker kan redigere etter at du har overlevert arbeidsboken. Sideoppsett fastsetter retning, papirstørrelse og marger. Utskriftsinnstillingene (gjentatte tittelrader, skalering og manuelle sideskift) styrer hvordan et rutenett av vilkårlig lengde havner på papir. Ingen av de tre synes når du kikker på dataene i en fremviser, og alle tre svikter stille ute i felten når de er feil. HotXLS, et nativt regnearkbibliotek for Delphi og C++Builder, eksponerer hele overflaten for .xls og .xlsx, noe som betyr at det også gjenskaper enhver kontraintuitiv Excel-regel bakt inn i den overflaten

Den første av disse reglene snubler nesten alle opp i første gang de beskytter et generert ark. Kall Protect, og plutselig kan ingen skrive i noen celle, inkludert inndatakolonnene du bygde arbeidsboken rundt. Ingenting i koden din rørte de kolonnene, og det er nettopp derfor det skjer

Hver celle fødes låst

ECMA-376 definerer locked som en del av en celles formateringspost, ikke som en egenskap ved selve beskyttelsen, og den er sann som standard. Arkbeskyttelse er bare bryteren som gjør flagget håndhevbart. Så hele rutenettet bærer et låseflagg fra det øyeblikket det eksisterer, i dvale, og kallet til Protect aktiverer dem alle på én gang. Løsningen er å sette rekkefølgen bevisst: bygg oppsettet, lås eksplisitt opp områdene brukerne må redigere, og beskytt til sist

Diagram over HotXLS beskyttelsesrekkefølgen i Delphi der hver celle fødes med locked true, inputområder låses opp med SetLocked først, og Sheet.Protect kalt sist holder de ulåste cellene redigerbare
Celler ankommer låst som standard, så lås opp inndataområdene først og kall Protect sist for å holde dem redigerbare
Book := TXLSXWorkbook.Create;
try
  Sheet := Book.Sheets.Add('Timesheet');
  // ... overskriftsrad, navnekolonne og satsformler skrives her ...
  Sheet.Range['B2:B50'].SetLocked(False);         // ansatte skriver timer her
  Sheet.Range['F2:F50'].SetFormulaHidden(True);   // hold satsberegningen privat
  Sheet.Protect('review-2026');                   // nå slår låseflaggene inn
  Book.SaveAs('timesheet.xlsx');
finally
  Book.Free;
end;

SetFormulaHidden gjør noe eget og lett å overse: mens beskyttelsen er aktiv, viser cellen fortsatt sin beregnede verdi, men formellinjen viser ingenting. Det spiller en rolle når en formel bygger inn faktureringssatser, marginer eller vektingsfaktorer du helst ikke vil gi til enhver mottaker som klikker på en sum. På XLS-fasaden uttrykkes den samme intensjonen per område gjennom IXLSRange.Locked og FormulaHidden. Arket der bærer også femten Allow*-flagg (AllowSort, AllowAutoFilter, AllowFormatCells, og resten), slik at et beskyttet ark fortsatt kan sorteres og filtreres fremfor å fryses til et forseglet utstillingseksemplar

Hva beskyttelsespassordet faktisk beskytter

Begge formatene lagrer ark- og arbeidsboksbeskyttelsespassordet som en gammeldags 4-tegns heksadesimal hash. Seksten bit betyr at utallige strenger kolliderer med et hvilket som helst gitt passord, og fjerningsverktøy er bare et søk unna. Behandle beskyttelse som et sikkerhetsbelte mot utilsiktede redigeringer, ikke som tilgangskontroll. Det er det riktige verktøyet for å hindre gjennomgangslesere fra å skrive over formelkolonnen, og det feile verktøyet for alt som involverer ordet konfidensiell

Ett nivå opp låser ProtectWorkbook på XLSX-fasaden arbeidsbokstrukturen, som hindrer tillegging, omdøping, sletting eller omorganisering av ark. Sett den når arklisten selv er en kontrakt med en nedstrøms parser som indekserer ark etter navn eller posisjon. Et omdøpt ark ødelegger importen på den andre siden like sikkert som en slettet kolonne gjør. XLS-fasaden speiler lagdelingen med TXLSWorkbook.Protect på arbeidsboknivå og per-ark Protect-kall, pluss en isProtected-egenskap for kode som trenger å inspisere en arvet fil før den endrer noe som helst

Når kravet er reell konfidensialitet, endrer mekanismen seg fullstendig. SaveAsEncrypted produserer en AES-kryptert pakke under ECMA-376 Standard Encryption-ordningen, dekket i dybden i veiledningen for AES-beskyttet XLSX-utdata, og den gamle XLS-fasaden skriver og leser RC4-krypterte .xls-filer gjennom EncryptionPassword og passord-overlastingen av Open. Forskjellen er ikke akademisk. Et beskyttet ark reiser i klartekst, så et hvilket som helst zip-verktøy kan lese celleverdiene, mens en kryptert pakke er uleselig uten passordet. En revisjonslinje som sier "lønnsfilen må beskyttes" betyr nesten alltid kryptering, uansett hvilket ordforråd den tilfeldigvis bruker

Diagram som setter HotXLS arkbeskyttelse, som lagrer en 16-bits eldre hash og lar celleverdier stå i klartekst leselig av ethvert zip-verktøy, opp mot SaveAsEncrypted AES-utdata som forblir uleselig uten passordet
Arkbeskyttelse er et sikkerhetsbelte mot uredigeringsforsøk mens klartekstverdier forblir lesbare, og bare AES-kryptering gjemmer innholdet

Sideoppsett er en del av dokumentkontrakten

Utskriftsatferd er usynlig på skjermen, og det er derfor den så ofte sendes ut i stykker. I det øyeblikket en kunde skriver ut arbeidsboken, eller eksporterer den til PDF for en revisor, blir marger, skalering og gjentatte titler til funksjonelle krav ingen har testet. På XLSX-fasaden henger disse innstillingene direkte på arket:

Sheet.PageLandscape := True;
Sheet.PaperSize := xlsxPaperA4;
Sheet.SetPageMargins(0.5, 0.5, 0.75, 0.75, 0.3, 0.3);
Sheet.CenterHeader := 'Monthly Timesheet';
Sheet.RightFooter := 'Page &P of &N';
Sheet.PrintArea := '$A$1:$F$60';     // ren referanse: intet arknavn her
Sheet.PrintTitleRows := '$1:$1';     // overskriftsraden gjentas på hver side
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0;              // vokser nedover etter hvert som dataene vokser
Sheet.PrintGridlines := False;

To av de linjene skjuler feller. Topptekst- og bunntekststrengene bruker Excels formateringskoder: &P for gjeldende side, &N for totalt antall, med &L, &C og &R for å adressere de tre seksjonene eksplisitt. Den andre fellen er PrintArea, som med hensikt tar imot en ren cellereferanse. HotXLS lagrer den ukvalifisert og setter arknavnet foran når den skriver filen, så å selv sende inn 'Timesheet!$A$1:$F$60' produserer en dobbelt kvalifisert, feilformet referanse. Den samme forsiktigheten gjelder ett lag ned: utskriftsområder og utskriftstitler lagres som de innebygde definerte navnene _xlnm.Print_Area og _xlnm.Print_Titles, så legg aldri til _xlnm.*-oppføringer gjennom DefinedNames for hånd, ellers vil de to mekanismene kjempe om samme plass

Skalering som tåler produksjonens datavolum

Kombinasjonen FitToWidth := 1 med FitToHeight := 0 leses som "tilpass alltid kolonnene til én side i bredden, ta så mange sider nedover som dataene trenger," og det er standardvalget for enhver rapport hvor antall rader varierer. Fellen er å justere en fast prosentandel eller et fit-to-page-par mot en testfil på tretti rader: mat de samme innstillingene med seks hundre produksjonsrader, og resultatet eksploderer enten til dusinvis av avkuttede sider eller krymper under lesbarhet. Skaler bredden, la lengden vokse, og gjenta overskriftsraden gjennom PrintTitleRows slik at side sytten fortsatt er lesbar på egen hånd

Diagram over HotXLS utskriftsskalering i Delphi med FitToWidth satt til 1 slik at hver side forblir ett ark bred, FitToHeight satt til 0 slik at sider vokser nedover, PrintTitleRows som gjentar topptekstbåndet, og sideskift regenerert etter ClearAllPageBreaks
FitToWidth 1 med FitToHeight 0 holder hver side ett ark bred mens gjentatte tittelrader og regenererte sideskift bevarer lesbarheten

Manuelle sideskift følger den samme regenereringsdisiplinen som alt annet i en generert arbeidsbok. AddRowBreak(BeforeRow) starter en ny side før en seksjonsgrense, men når generatoren kjøres på nytt og radene forskyver seg, havner et foreldet sideskift midt i tabellen. Kall ClearAllPageBreaks først, og legg deretter til sideskift på nytt beregnet fra generatorens egne radtellere i stedet for å lappe gamle posisjoner. På XLS-fasaden ligger de tilsvarende kontrollene på Sheet.PageSetup (retning, papirstørrelse, marger, topptekst- og bunntekststrenger, tilpass-til-sider), med RepeatRows og RepeatColumns som dekker utskriftstitlene

Å kontrollere resultatet før en kunde gjør det

Beskyttelses- og utskriftsfeil deler én egenskap: de er trivielle å verifisere for hånd og blir nesten aldri verifisert. Åpne den genererte filen i Excel og bruk nitti sekunder på den. Skriv inn i en inndatacelle og bekreft at den godtar tastetrykket; skriv inn i en låst celle og bekreft at beskyttelsesvarselet dukker opp; sjekk at en skjult formel lar formellinjen stå tom. Kjør deretter Forhåndsvisning av utskrift mot et datasett i produksjonsstørrelse, ikke et utvalg på tretti rader, og les av sideantallet, den gjentakende tittelraden og bunntekstnummereringen. Forhåndsvisningen er trinnet som betaler for seg selv, fordi utskriftsgeometrien avhenger av innstillinger uten noen skjermgjengivelse, og bortsett fra en fysisk skriver er det det eneste stedet en skaleringsfeil noensinne blir synlig

Én siste innstilling runder av gjennomgangen. FreezePane(ACol, ARow) holder overskriftsblokken synlig mens en gjennomgangsleser ruller. Det er skjermatferd fremfor utskriftsatferd, men en gjennomgangsleser vurderer hele leveransen på én gang. Og en arbeidsbok som starter livet som et designer-vedlikeholdt oppsett, får mesteparten av dette gratis: arbeidsflyten for malbasert rapportgenerering holder sideoppsettet i malen, hvor et menneske har finjustert den mot en ekte skriver, og lar koden fylle dataene og gjenanvende beskyttelsen når oppsettet har satt seg

HotXLS er et nativt Object Pascal-regnearkbibliotek for Delphi og C++Builder; den fullstendige API-referansen for beskyttelse og sideoppsett finner du på HotXLS Delphi Component-produktsiden