Je geeft een afgeronde workbook aan een collega en vraagt hem om te filteren, niet om hem opnieuw in te richten. Dus je beschermt het werkblad. In oudere HotXLS-builds schreef dat gebaar één ding in het bestand: <sheetProtection sheet="1" objects="1" scenarios="1"/>, elke keer hard-coded. Het werkblad ging op slot, de wachtwoordhash werd toegevoegd en de gebruiker kon helemaal niets meer, zelfs niet sorteren en filteren wat je juist open had willen laten. Excel's eigen dialoog Bescherm werkblad heeft daar vijftien selectievakjes voor, en de engine kon er geen van uitdrukken. Die kloof sluit het beveiligingsmodel uit v2.91.0
HotXLS is een native VCL spreadsheetcomponent voor Delphi en C++Builder die XLS en XLSX leest en schrijft zonder Excel geïnstalleerd te hebben. Dit artikel gaat over de XLSX-kant van worksheetprotectie: de nieuwe TXLSXSheetProtectionOption-enum, de AllowOption-property die elke permissie omschakelt, en de ene OOXML-encoderegel waar iedereen over struikelt die een <sheetProtection>-element handmatig schrijft
Wat worksheetprotectie werkelijk afschermt
Eerst de grens, omdat die bepaalt hoeveel je van dit alles moet vertrouwen. Worksheetprotectie in het OOXML-spreadsheetformaat (ECMA-376) is een interactiebeleid, geen encryptie. Het vertelt een conformerende applicatie welke bewerkingen geweigerd moeten worden zolang het blad beschermd is. De celwaarden staan nog steeds als platte tekst in xl/worksheets/sheetN.xml; unzip de .xlsx en ze liggen er gewoon. Het optionele wachtwoord wordt opgeslagen als een korte legacy hash, niet als een sleutel die iets versleutelt. Wie de file hernoemt, het onderdeel opent en de <sheetProtection>-regel verwijdert, leest en bewerkt alles
Protectie zegt dus: "voorkom dat mijn collega per ongeluk een formule overschrijft", niet: "houd deze data geheim voor iemand met motivatie." Dat zijn verschillende problemen met verschillende gereedschappen. Als je vertrouwelijkheid nodig hebt, wil je workbook-level encryptie zoals besproken in AES-beveiligde XLSX-uitvoer, die het pakket echt versleutelt. Sheetprotectie en workbookencryptie kun je combineren, maar alleen de tweede is een slot. Houd die lijn helder en de rest van deze pagina is alleen plumbing
De vijftien opties en de AllowOption-property
Elk werkblad draagt nu een set TXLSXSheetProtectionOption-waarden die beschrijven wat de gebruiker nog mag doen terwijl het blad beschermd is. De leden mappen één op één op de OOXML-attributen en op de selectievakjes in het Excel-dialoogvenster:
xlsxSpoEditObjects,xlsxSpoEditScenarios- tekenobjecten en what-if-scenario's bewerkenxlsxSpoFormatCells,xlsxSpoFormatColumns,xlsxSpoFormatRows- cellen, kolommen en rijen opmakenxlsxSpoInsertColumns,xlsxSpoInsertRows,xlsxSpoInsertHyperlinks- kolommen, rijen en links invoegenxlsxSpoDeleteColumns,xlsxSpoDeleteRows- kolommen en rijen verwijderenxlsxSpoSelectLockedCells,xlsxSpoSelectUnlockedCells- de selectie verplaatsen naar vergrendelde of ontgrendelde cellenxlsxSpoSort,xlsxSpoAutoFilter,xlsxSpoPivotTables- bereiken sorteren, AutoFilter-dropdowns gebruiken, met PivotTables werken
Je leest en schrijft de afzonderlijke bits via de geïndexeerde AllowOption-property op TXLSXWorksheet. AllowOption[Opt] = True betekent dat de handeling is toegestaan; met False verbied je die. De volledige set is ook in één keer bereikbaar via SheetProtectionOptions, een TXLSXSheetProtectionOptions (een gewone Pascal set of), zodat je hem kunt opslaan, herstellen of in één keer vervangen
De standaard is belangrijk en opzettelijk: een pas aangemaakte worksheet start met elke optie toegestaan. De constructor vult SheetProtectionOptions met het volledige bereik, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Je beperkt dat vanaf daar door de acties eruit te laten die je wilt verbieden, in plaats van een permissieset vanaf nul op te bouwen. Die keuze zorgt ervoor dat de encoderegel hieronder precies aansluit op Excel's gedrag
Een blad beschermen maar sorteren en filteren open laten
Hier is de gebruikelijke situatie van begin tot eind: bescherm een afgerapporteerd rapport zodat de lay-out niet opnieuw kan worden opgebouwd, maar laat de lezer het wel sorteren en filteren. Let op dat Protect en de opties onafhankelijk zijn. Protect zet het blad in de beschermde toestand en bewaart de optionele wachtwoordhash; het raakt de optie-set niet aan. Je past AllowOption apart aan, en de toggles werken zodra het blad beschermd en opgeslagen is
Twee dingen uit dat fragment zijn belangrijk. De regels voor Sort en AutoFilter worden expliciet geschreven, ook al staan beide standaard op True; dat is documentatie voor de volgende maintainer, geen functionele noodzaak. En omdat de defaults permissief zijn, veranderen alleen de regels die een optie op False zetten het uitvoerbestand. Dat is geen toeval van deze API, maar de OOXML-wireformat die zichtbaar wordt, en dat is het volgende onderdeel
De encoderegel: weglaten betekent toestaan, attr=0 betekent verbieden
Dit is het ene contra-intuïtieve feit in de hele feature, en het is waar handmatig geschreven <sheetProtection> meestal fout gaat. In OOXML is elk per-actie-attribuut een verbied-vlag, en de afwezigheid ervan betekent toestemming. Een attribuut dat ontbreekt betekent dat de actie is toegestaan. Een attribuut dat als "0" is geschreven betekent dat de actie verboden is zolang het werkblad beschermd is. Er bestaat geen formatCells="1" in een goed gevormd bestand om te betekenen dat opmaak is toegestaan; je laat het attribuut gewoon weg. Het standaardgedrag voor een afwezig attribuut is de OOXML-boolean default true, en deze attributen zijn zo genoemd dat true betekent dat de betreffende bewerking is toegestaan
De HotXLS-writer spiegelt dat exact. Hij schrijft sheet="1" om protectie aan te zetten en loopt daarna door de option-set, waarbij hij alleen attr="0" schrijft voor de opties die je op False hebt gezet. Toegestane acties leveren niets op in de uitvoer. Dus de workbook uit de vorige sectie serialiseert naar iets als dit, met alleen de verboden acties plus de wachtwoordhash:
Als je uit de oude hard-coded string kwam en verwachtte dat elk attribuut expliciet zou verschijnen, lijkt dit kaal, bijna fout. Het is correct. Een bestand dat sort="1" en autoFilter="1" zou noemen, zou voor een conformerende reader hetzelfde betekenen, maar Excel schrijft zelf de minimale forbid-only-vorm en dat houden maakt diffs klein en round-trips saai. De objects- en scenarios-attributen volgen dezelfde regel: ze zijn standaard toegestaan, dus verschijnen alleen als "0" wanneer je ze verbiedt, het omgekeerde van de oude objects="1" scenarios="1" die altijd werd uitgegeven
Protectie teruglezen: round-trip-getrouwheid
Een permissiemodel dat je wel kunt schrijven maar niet lezen is een eenrichtingsdeur, en het gebruikelijke symptoom is een load-edit-save-cyclus die permissies stilletjes verruimt. HotXLS sluit dat. Wanneer ParseWorksheetXml een <sheetProtection>-element tegenkomt, zet het het blad op beschermd, vangt het de wachtwoordhash op als die er is, en decodeert daarna elk per-actie-attribuut terug naar AllowOption met dezelfde conventie in omgekeerde richting: een aanwezig attribuut dat gelijk is aan "0" verbiedt de actie; een afwezig attribuut laat de optie op de toegestane default staan
Laad het bestand dat de writer produceerde en je krijgt Sort en AutoFilter terug als True, FormatCells als False - de set die je hebt opgeslagen, intact. Die symmetrie is het hele punt: bewerk één cel in een beschermd, gedeeltelijk toegestaan blad en sla opnieuw op, en de veertien permissies die je niet aanraakte blijven behouden in plaats van terug te vallen naar de oude alles-of-niets-default
Praktische notities en grenzen
Een paar dingen zijn goed om te weten voordat je dit in een rapportpipeline hangt:
- Het wachtwoord is bewust zwak. XLSX-werkbladprotectie bewaart een legacy hash van 16 bit, dezelfde die Excel al decennia gebruikt, hier behouden voor interoperabiliteit. Het remt per ongeluk bewerken af; het weerstaat geen aanvaller. Zie het niet als geheimhouder. Voor echte bescherming encrypt je de workbook
- Opties instellen vóór protectie is prima.
AllowOptionkan worden toegewezen ongeacht of het blad al beschermd is; de toggles beschrijven alleen wat protectie toestaat zodraProtectactief is.UnProtectwist de beschermde toestand en de hash, maar laat je option-set staan voor de volgende keer - Locked-cell-semantiek blijft gelden. Protectie blokkeert alleen bewerkingen op cellen waarvan het
Locked-attribuut is gezet, de standaard van de workbook. Een invoergebied bewerkbaar laten is werk van de celstijl, niet van een protectieoptie; de twee lagen combineren zoals in Excel - Dit is de XLSX-engine. Het option-model spiegelt de oudere
Allow*-properties van de XLS-engine, maar de enum- en propertynamen hier (xlsxSpo*,AllowOption) horen bijTXLSXWorksheetinlxHandleX. Als je op dezelfde sheets ook de afdruklay-out stuurt, behandelt de walkthrough over protectie en page setup hoe deze instellingen naast afdrukbereiken en kopteksten staan, en data validatie, AutoFilter en tabellen past goed bij het openlaten vanxlsxSpoAutoFilterop een vergrendeld rapport
Het fijnmazige protectiemodel en de rest van de XLSX lees-/schrijfengine worden meegeleverd met de HotXLS Component voor Delphi en C++Builder; de productpagina bevat de volledige worksheet-API inclusief de complete referentie van de protection options
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;
// Protect with a password. This only sets the protected state + hash;
// the option set is left at its all-permitted default.
sh.Protect('HotXLS-2026');
// Narrow: keep sort + AutoFilter, forbid reshaping and reformatting.
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;// Conceptual output for the snippet above (attributes elided for brevity):
// <sheetProtection sheet="1"
// formatCells="0" formatColumns="0" formatRows="0"
// insertRows="0" deleteRows="0"
// password="...4-hex..."/>
// Note what is NOT there: no sort, no autoFilter, no selectLockedCells.
// Their absence is exactly what tells Excel those actions stay allowed.var
wb: TXLSXWorkbook;
sh: TXLSXWorksheet;
begin
wb := TXLSXWorkbook.Create;
try
wb.LoadFromFile('protection.xlsx');
sh := wb.Sheets[1]; // XLSX sheets are 1-based
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;