Du giver en færdig projektmappe til en kollega og beder dem filtrere den, ikke omskrive den. Så beskytter du arket. I ældre HotXLS-builds skrev den gestus én ting ind i filen: <sheetProtection sheet="1" objects="1" scenarios="1"/>, hard-coded, hver gang. Arket låste, password-hashen blev lagt på, og brugeren kunne ikke gøre noget som helst, ikke engang de sorterings- og filterhandlinger, du faktisk ville lade stå åbne. Excels egen dialogboks "Protect Sheet" har femten afkrydsningsfelter af netop denne grund, og motoren kunne ikke udtrykke nogen af dem. Det hul er, hvad v2.91.0-beskyttelsesmodellen lukker
HotXLS er en native VCL spreadsheet-komponent til Delphi og C++Builder, som læser og skriver XLS og XLSX uden at Excel er installeret. Denne artikel handler om XLSX-siden af arkbeskyttelse: den nye TXLSXSheetProtectionOption-enum, AllowOption-egenskaben, der slår hver enkelt tilladelse til og fra, og den ene OOXML-kodningsregel, der snubler alle, der skriver et <sheetProtection>-element i hånden
Hvad arkbeskyttelse faktisk beskytter
Først grænsen, fordi den afgør, hvor meget du bør stole på noget af dette. Arkbeskyttelse i OOXML-regnearksformatet (ECMA-376) er en interaktionspolitik, ikke kryptering. Den fortæller et konformt program, hvilke redigeringer det skal afvise, mens arket er beskyttet. Celleværdierne ligger stadig i xl/worksheets/sheetN.xml i klartekst; udpak .xlsx-filen, og de er lige der. Den valgfrie adgangskode gemmes som en kort, forældet hash, ikke en nøgle, der forvrænger noget. Enhver, der omdøber filen, åbner delen og fjerner linjen <sheetProtection>, kan læse og redigere alt
Så svarer beskyttelse på "forhindr min kollega i ved et uheld at smadre en formel," ikke "hold disse data hemmelige for nogen, der er motiveret." Det er to forskellige problemer med to forskellige værktøjer. Har du brug for fortrolighed, skal du bruge krypteringen på projektmappeniveau, der er beskrevet i AES-beskyttet XLSX-output, som rent faktisk krypterer pakken. Arkbeskyttelse og projektmappekryptering kombineres uden problemer, men kun den anden er en lås. Hold den skillelinje klar, så er resten af denne side bare rørføring
De femten valg og AllowOption-egenskaben
Hvert regneark har nu et sæt TXLSXSheetProtectionOption-værdier, der beskriver, hvad brugeren stadig må gøre, mens arket er beskyttet. Medlemmerne svarer én til én til OOXML-attributterne og til afkrydsningsfelterne i Excel-dialogen:
xlsxSpoEditObjects,xlsxSpoEditScenarios— rediger tegneobjekter og hvad-nu-hvis-scenarierxlsxSpoFormatCells,xlsxSpoFormatColumns,xlsxSpoFormatRows— omformatér celler, kolonner, rækkerxlsxSpoInsertColumns,xlsxSpoInsertRows,xlsxSpoInsertHyperlinks— indsæt kolonner, rækker, linksxlsxSpoDeleteColumns,xlsxSpoDeleteRows— slet kolonner, rækkerxlsxSpoSelectLockedCells,xlsxSpoSelectUnlockedCells— flyt markeringen hen på låste eller ulåste cellerxlsxSpoSort,xlsxSpoAutoFilter,xlsxSpoPivotTables— sortér områder, brug AutoFilter-rullelister, arbejd med pivottabeller
Du læser og skriver individuelle bits gennem den indekserede AllowOption-egenskab på TXLSXWorksheet. AllowOption[Opt] = True betyder, at handlingen er tilladt; sætter du den til False, forbydes den. Hele sættet kan også nås på én gang gennem SheetProtectionOptions, en TXLSXSheetProtectionOptions (et almindeligt Pascal set of), så du kan gemme det, gendanne det eller udskifte det som helhed
Standardværdien betyder noget, og den er bevidst: et nyoprettet regneark starter med hver eneste indstilling tilladt. Konstruktøren fylder SheetProtectionOptions med hele intervallet, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Du indsnævrer derfra ved at udelukke de handlinger, du vil forbyde, i stedet for at bygge et tilladelsessæt op fra bunden. Det valg er, hvad der får writerens kodningsregel, nedenfor, til at stemme overens med Excels adfærd
Beskyt et ark, men lad sortering og filtrering være åben
Her er det almindelige tilfælde fra ende til anden: beskyt en færdig rapport, så layoutet ikke kan omformes, men lad læseren sortere og filtrere den. Bemærk, at Protect og indstillingerne er uafhængige. Protect slår arket over i den beskyttede tilstand og gemmer den valgfrie adgangskode-hash; den rører ikke ved indstillingssættet. Du justerer AllowOption separat, og skifterne træder i kraft, så snart arket er beskyttet og gemt
var
wb: TXLSXWorkbook;
sh: TXLSXWorksheet;
begin
wb := TXLSXWorkbook.Create;
try
sh := wb.Sheets.Add('Protected');
sh.Cells[1, 1].Value := 'Region'; sh.Cells[1, 2].Value := 'Units';
sh.Cells[2, 1].Value := 'North'; sh.Cells[2, 2].Value := 120;
sh.Cells[3, 1].Value := 'South'; sh.Cells[3, 2].Value := 98;
// Beskyt med en adgangskode. Dette sætter kun den beskyttede tilstand + hash;
// indstillingssættet efterlades i sin standard, hvor alt er tilladt.
sh.Protect('HotXLS-2026');
// Indsnævr: behold sort + AutoFilter, forbyd omformning og omformatering.
sh.AllowOption[xlsxSpoSort] := True;
sh.AllowOption[xlsxSpoAutoFilter] := True;
sh.AllowOption[xlsxSpoFormatCells] := False;
sh.AllowOption[xlsxSpoFormatColumns] := False;
sh.AllowOption[xlsxSpoFormatRows] := False;
sh.AllowOption[xlsxSpoInsertRows] := False;
sh.AllowOption[xlsxSpoDeleteRows] := False;
if wb.SaveAs('protection.xlsx') <> 1 then
Writeln('SaveAs failed');
finally
wb.Free;
end;
end;
To ting at læse ud af det udsnit. Linjerne med Sort og AutoFilter skrives eksplicit, selvom begge som standard er True; det er dokumentation til den næste vedligeholder, ikke et funktionelt krav. Og fordi standarderne er tilladende, er det kun linjerne, der sætter en indstilling til False, der ændrer outputfilen. Det er ikke et tilfælde ved denne API, det er OOXML-wireformatet, der skinner igennem, hvilket er næste afsnit
Kodningsreglen: udeladelse betyder tilladelse, attr=0 betyder forbud
Det er den ene kontraintuitive kendsgerning i hele funktionen, og det er der, hvor håndskrevet <sheetProtection> normalt går galt. I OOXML er hver pr.-handling-attribut et forbud-flag, og dets fravær er tilladelse. En attribut, der mangler, betyder, at handlingen er tilladt. En attribut skrevet som "0" betyder, at handlingen er forbudt, mens arket er beskyttet. Der findes ikke noget formatCells="1" i en velformet fil for at betyde "formatering er tilladt"; du udelader simpelthen attributten. (Standarden for en manglende attribut er OOXML's boolske standard true, og disse attributter er navngivet, så "true" betyder, at den tilsvarende redigering er tilladt.)
HotXLS-writeren spejler det nøjagtigt. Den udsender sheet="1" for at slå beskyttelse til, gennemgår derefter indstillingssættet og skriver attr="0" kun for de indstillinger, du har sat til False. Tilladte handlinger bidrager med intet til outputtet. Så projektmappen fra det foregående afsnit serialiseres til noget i stil med dette, som kun indeholder de forbudte handlinger plus adgangskode-hashen:
// Konceptuelt output for udsnittet ovenfor (attributter udeladt for kortheds skyld):
// <sheetProtection sheet="1"
// formatCells="0" formatColumns="0" formatRows="0"
// insertRows="0" deleteRows="0"
// password="...4-hex..."/>
// Bemærk, hvad der IKKE er der: intet sort, intet autoFilter, intet selectLockedCells.
// Deres fravær er netop det, der fortæller Excel, at de handlinger forbliver tilladt.
Kommer du fra den gamle hard-codede streng og forventede at se hver attribut stavet ud, ser dette sparsomt ud, næsten forkert. Det er korrekt. En fil, der listede sort="1" og autoFilter="1", ville betyde det samme for en konform læser, men Excel selv skriver den minimale forbud-kun-form, og at matche den holder diffs små og round-trips kedelige. Attributterne objects og scenarios følger den identiske regel: de er som standard tilladt, så de optræder kun som "0", når du forbyder dem, hvilket er det modsatte af det gamle objects="1" scenarios="1", der blev udsendt betingelsesløst
Læs beskyttelsen tilbage: round-trip-fidelitet
En tilladelsesmodel, du kan skrive, men ikke læse, er en envejsdør, og det sædvanlige symptom er en indlæs-redigér-gem-cyklus, der stille udvider tilladelserne. HotXLS lukker det hul. Når ParseWorksheetXml støder på et <sheetProtection>-element, sætter den arket til beskyttet, indfanger adgangskode-hashen, hvis den er til stede, og afkoder derefter hver pr.-handling-attribut tilbage til AllowOption ved brug af den samme konvention omvendt: en attribut, der er til stede og lig med "0", forbyder handlingen; en manglende attribut lader indstillingen stå ved sin tilladte standard
var
wb: TXLSXWorkbook;
sh: TXLSXWorksheet;
begin
wb := TXLSXWorkbook.Create;
try
wb.Open('protection.xlsx');
sh := wb.Sheets[1]; // XLSX-ark er 1-baserede
if sh.IsProtected then
begin
Writeln('Protected; password hash present: ',
sh.SheetProtectHash <> '');
Writeln('Sort allowed: ', sh.AllowOption[xlsxSpoSort]);
Writeln('AutoFilter allowed: ', sh.AllowOption[xlsxSpoAutoFilter]);
Writeln('FormatCells allowed:', sh.AllowOption[xlsxSpoFormatCells]);
end;
finally
wb.Free;
end;
end;
Indlæs filen, writeren producerede, og du får Sort og AutoFilter tilbage som True, FormatCells som False — det sæt, du gemte, intakt. Den symmetri er hele pointen: rediger én celle i et beskyttet, delvist tilladt ark og gem igen, og de fjorten tilladelser, du ikke rørte, overlever i stedet for at falde tilbage til den gamle alt-eller-intet-standard
Praktiske noter og begrænsninger
Nogle få ting værd at vide, før du kobler dette ind i en rapporteringspipeline:
- Adgangskoden er svag med vilje. XLSX-arkbeskyttelse gemmer en 16-bit forældet hash (den samme, Excel har brugt i årtier), bevaret her af hensyn til interoperabilitet. Den afskrækker utilsigtede redigeringer; den modstår ikke en angriber. Behandl den ikke som en hemmelighedsholder. For reel beskyttelse skal du kryptere projektmappen
- Det er fint at sætte indstillinger, før du beskytter.
AllowOptionkan tildeles, uanset om arket i øjeblikket er beskyttet eller ej; skifterne beskriver blot, hvad beskyttelsen vil tillade, nårProtecter i kraft.UnProtectrydder den beskyttede tilstand og hashen, men lader dit indstillingssæt stå til næste gang - Semantikken for låste celler gælder stadig. Beskyttelse blokerer kun redigeringer i celler, hvis
Locked-attribut er sat (projektmappens standard). At lade et inputområde være redigerbart er celletypografiens opgave, ikke en beskyttelsesindstilling; de to lag kombineres på samme måde, som de gør i Excel - Dette er XLSX-motoren. Indstillingsmodellen spejler XLS-motorens ældre
Allow*-egenskaber, men enum- og egenskabsnavnene her (xlsxSpo*,AllowOption) hører tilTXLSXWorksheetilxHandleX. Styrer du også printlayout på de samme ark, dækker gennemgangen af beskyttelse og sideopsætning, hvordan disse indstillinger passer sammen med printområder og sidehoveder, og datavalidering, AutoFilter og tabeller passer naturligt sammen med at ladexlsxSpoAutoFilterstå åben på en låst rapport
Den finkornede beskyttelsesmodel og resten af XLSX-læse-/skrivemotoren følger med i HotXLS-Delphi-komponenten til Delphi og C++Builder; produktsiden indeholder den fulde regneark-API, inklusive den komplette beskyttelsesindstillings-reference