Technischer Artikel

XLSX-Blattschutz in Delphi: 15 Zulassen-Optionen

Sie übergeben eine fertige Arbeitsmappe an einen Kollegen und bitten ihn, sie zu filtern und nicht neu zu schreiben. Also schützen Sie das Arbeitsblatt. In älteren HotXLS-Builds hat diese Aktion eine einzige Sache in die Datei geschrieben: <sheetProtection sheet="1" objects="1" scenarios="1"/>, hartcodiert, jedes Mal. Das Blatt wurde gesperrt, der Passwort-Hash angehängt, und der Benutzer konnte überhaupt nichts tun, nicht einmal das Sortieren und Filtern, das Sie eigentlich offen lassen wollten. Der Excel-eigene Dialog „Blatt schützen“ hat genau aus diesem Grund fünfzehn Kontrollkästchen, und die Engine konnte keines davon ausdrücken. Diese Lücke schließt das Schutzmodell von v2.91.0

HotXLS ist eine native VCL-Tabellenkalkulationskomponente für Delphi und C++Builder, die XLS- und XLSX-Dateien ohne installiertes Excel liest und schreibt. In diesem Artikel geht es um die XLSX-Seite des Blattschutzes: das neue Enum TXLSXSheetProtectionOption, die Eigenschaft AllowOption, die jede Berechtigung umschaltet, und die eine OOXML-Codierungsregel, über die jeder stolpert, der ein <sheetProtection>-Element manuell schreibt

Was der Blattschutz tatsächlich schützt

Zuerst die Grenze, denn sie entscheidet darüber, wie sehr Sie dem Ganzen vertrauen sollten. Der Blattschutz im OOXML-Tabellenkalkulationsformat (ECMA-376) ist eine Interaktionsrichtlinie, keine Verschlüsselung. Er teilt einer konformen Anwendung mit, welche Bearbeitungen abzulehnen sind, während das Blatt geschützt ist. Die Zellwerte befinden sich weiterhin im Klartext in xl/worksheets/sheetN.xml; entpacken Sie die .xlsx und sie sind direkt dort. Das optionale Passwort wird als kurzer Legacy-Hash gespeichert, nicht als Schlüssel, der irgendetwas verschlüsselt. Jeder, der die Datei umbenennt, das XML öffnet und die Zeile <sheetProtection> entfernt, kann alles lesen und bearbeiten

Der Schutz beantwortet also die Frage „Wie hindere ich meinen Kollegen daran, versehentlich eine Formel zu überschreiben?“, nicht „Wie halte ich diese Daten vor jemandem mit bösen Absichten geheim?“. Dies sind verschiedene Probleme mit unterschiedlichen Werkzeugen. Wenn Sie Vertraulichkeit benötigen, benötigen Sie die Verschlüsselung auf Arbeitsmappenebene, die in AES-geschützte XLSX-Ausgabe behandelt wird und das Paket tatsächlich verschlüsselt. Blattschutz und Arbeitsmappenverschlüsselung lassen sich sauber kombinieren, aber nur das Zweite ist ein echter Riegel. Wenn Sie diese Grenze im Kopf behalten, ist der Rest dieser Seite nur noch Formsache

Die fünfzehn Optionen und die AllowOption-Eigenschaft

Jedes Arbeitsblatt enthält nun einen Satz von TXLSXSheetProtectionOption-Werten, die beschreiben, was der Benutzer bei geschütztem Blatt noch tun darf. Die Elemente lassen sich eins zu eins auf die OOXML-Attribute und die Kontrollkästchen im Excel-Dialog abbilden:

  • xlsxSpoEditObjects, xlsxSpoEditScenarios — Zeichnungsobjekte und Was-wäre-wenn-Szenarien bearbeiten
  • xlsxSpoFormatCells, xlsxSpoFormatColumns, xlsxSpoFormatRows — Zellen, Spalten, Zeilen neu formatieren
  • xlsxSpoInsertColumns, xlsxSpoInsertRows, xlsxSpoInsertHyperlinks — Spalten, Zeilen, Hyperlinks einfügen
  • xlsxSpoDeleteColumns, xlsxSpoDeleteRows — Spalten, Zeilen löschen
  • xlsxSpoSelectLockedCells, xlsxSpoSelectUnlockedCells — die Auswahl auf gesperrte oder entsperrte Zellen verschieben
  • xlsxSpoSort, xlsxSpoAutoFilter, xlsxSpoPivotTables — Bereiche sortieren, AutoFilter-Dropdowns verwenden, mit Pivot-Tabellen arbeiten

Sie lesen und schreiben einzelne Bits über die indizierte Eigenschaft AllowOption auf TXLSXWorksheet. AllowOption[Opt] = True bedeutet, dass die Aktion zulässig ist; das Setzen auf False verbietet sie. Der gesamte Satz ist auch auf einmal über SheetProtectionOptions erreichbar, ein TXLSXSheetProtectionOptions (ein einfaches Pascal-set of), sodass Sie ihn speichern, wiederherstellen oder als Ganzes ersetzen können

Der Standardwert ist wichtig und bewusst so gewählt: Ein neu erstelltes Arbeitsblatt startet mit der Erlaubnis für jede Option. Der Konstruktor initialisiert SheetProtectionOptions mit dem gesamten Bereich, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Sie schränken diesen von dort aus ein, indem Sie die Aktionen ausschließen, die Sie verbieten möchten, anstatt ein Berechtigungsset von Grund auf neu aufzubauen. Diese Wahl sorgt dafür, dass sich die unten beschriebene Codierungsregel des Writers mit dem Verhalten von Excel deckt

Ein Arbeitsblatt schützen, aber Sortieren und Filtern freigeben

Hier ist der typische Fall von Anfang bis Ende: Schützen Sie einen fertigen Bericht, damit das Layout nicht verändert werden kann, aber lassen Sie den Leser sortieren und filtern. Beachten Sie, dass Protect und die Optionen unabhängig voneinander sind. Protect versetzt das Blatt in den geschützten Zustand und speichert den optionalen Passwort-Hash; es berührt den Optionssatz nicht. Sie passen AllowOption separat an, und die Einstellungen werden wirksam, sobald das Blatt geschützt und gespeichert ist

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;

Zwei Dinge lassen sich aus diesem Snippet ablesen. Die Zeilen für Sort und AutoFilter werden explizit geschrieben, obwohl beide standardmäßig auf True stehen; dies dient der Dokumentation für den nächsten Entwickler, nicht einer funktionalen Anforderung. Und da die Standardeinstellungen zulassend sind, sind die einzigen Zeilen, die die Ausgabedatei ändern, diejenigen, die eine Option auf False setzen. Das ist kein Zufall dieser API, sondern liegt am OOXML-Übertragungsformat, das im nächsten Abschnitt behandelt wird

Die Codierungsregel: Weglassen bedeutet Zulassen, attr=0 bedeutet Verbieten

Dies ist die einzige kontraintuitive Tatsache im gesamten Feature, und hier geht manuell geschriebenes <sheetProtection> meist schief. In OOXML ist jedes aktionsbezogene Attribut ein Verbots-Flag, und sein Fehlen bedeutet Erlaubnis. Ein fehlendes Attribut bedeutet, dass die Aktion erlaubt ist. Ein als "0" geschriebenes Attribut bedeutet, dass die Aktion verboten ist, während das Blatt geschützt ist. Es gibt kein formatCells="1" in einer wohlgeformten Datei, um auszudrücken, dass „Formatierung erlaubt ist“; Sie lassen das Attribut einfach weg. (Der Standardwert für ein fehlendes Attribut ist das OOXML-Boolean-Standardverhalten für true, und diese Attribute sind so benannt, dass „true“ bedeutet, dass die entsprechende Bearbeitung zulässig ist.)

Der Writer von HotXLS spiegelt das genau wider. Er gibt sheet="1" aus, um den Schutz einzuschalten, durchläuft dann den Optionssatz und schreibt attr="0" nur für die Optionen, die Sie auf False gesetzt haben. Zulässige Aktionen tragen nichts zur Ausgabe bei. Die Arbeitsmappe aus dem vorherigen Abschnitt serialisiert sich also zu etwas wie diesem, das nur die verbotenen Aktionen plus den Passwort-Hash enthält:

// 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.

Wenn Sie von der alten, hartcodierten Zeichenfolge kommen und erwarten, jedes Attribut ausgeschrieben zu sehen, sieht dies spärlich, fast falsch aus. Es ist jedoch korrekt. Eine Datei, die sort="1" und autoFilter="1" auflisten würde, würde für einen konformen Reader dasselbe bedeuten, aber Excel selbst schreibt die minimale Verbots-Form, und deren Einhaltung hält Diffs klein und Roundtrips unkompliziert. Die Attribute objects und scenarios folgen genau derselben Regel: Sie sind standardmäßig erlaubt, erscheinen also nur als "0", wenn Sie sie verbieten, was das Gegenteil des alten objects="1" scenarios="1" ist, das bedingungslos ausgegeben wurde

Schutz zurücklesen: Roundtrip-Treue

Ein Berechtigungsmodell, das man schreiben, aber nicht lesen kann, ist eine Einbahnstraße, und das übliche Symptom ist ein Lade-Bearbeitungs-Speicher-Zyklus, der Berechtigungen stillschweigend erweitert. HotXLS schließt diese Lücke. Wenn ParseWorksheetXml auf ein <sheetProtection>-Element stößt, setzt es das Blatt auf geschützt, erfasst den Passwort-Hash, falls vorhanden, und dekodiert dann jedes aktionsbezogene Attribut nach derselben Konvention in umgekehrter Reihenfolge zurück in AllowOption: Ein vorhandenes Attribut mit dem Wert "0" verbietet die Aktion; ein fehlendes Attribut belässt die Option bei ihrem standardmäßig zulässigen Zustand

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;

Wenn Sie die vom Writer erstellte Datei laden, erhalten Sie Sort und AutoFilter als True zurück und FormatCells als False – den Satz, den Sie gespeichert haben, intakt. Diese Symmetrie ist der entscheidende Punkt: Bearbeiten Sie eine Zelle in einem geschützten, teilweise freigegebenen Blatt und speichern Sie sie erneut. Die vierzehn Berechtigungen, die Sie nicht berührt haben, bleiben erhalten, anstatt auf den alten Alles-oder-Nichts-Standard zurückzufallen

Praktische Hinweise und Grenzen

A fwe things worth knowing before you wire this into a report pipeline:

  • Das Passwort ist konstruktionsbedingt schwach. Der XLSX-Blattschutz speichert einen 16-Bit-Legacy-Hash (denselben, den Excel seit Jahrzehnten verwendet), der hier aus Interoperabilitätsgründen beibehalten wird. Er verhindert versehentliche Bearbeitungen, hält jedoch keinem Angreifer stand. Behandeln Sie ihn nicht als Tresor. Für echten Schutz verschlüsseln Sie die Arbeitsmappe
  • Das Festlegen von Optionen vor dem Schützen ist zulässig. AllowOption kann zugewiesen werden, unabhängig davon, ob das Blatt gerade geschützt ist oder nicht; die Schalter beschreiben lediglich, was der Schutz erlaubt, sobald Protect aktiv ist. UnProtect hebt den geschützten Zustand und den Hash auf, belässt Ihren Optionssatz jedoch für das nächste Mal
  • Die Semantik gesperrter Zellen gilt weiterhin. Der Schutz blockiert nur Bearbeitungen an Zellen, deren Attribut Locked gesetzt ist (der Standardwert der Arbeitsmappe). Einen Eingabebereich editierbar zu lassen, ist Aufgabe des Zellstils, keine Schutzoption; die beiden Ebenen kombinieren sich auf dieselbe Weise wie in Excel
  • Dies ist die XLSX-Engine. Das Optionsmodell spiegelt die älteren Allow*-Eigenschaften der XLS-Engine wider, aber die Enum- und Eigenschaftsnamen hier (xlsxSpo*, AllowOption) gehören zu TXLSXWorksheet in lxHandleX. Wenn Sie auch das Drucklayout auf denselben Blättern steuern, beschreibt der [Leitfaden zu Schutz und Seiteneinstellungen](hotxls-protection-page-setup-printing.html), wie diese Einstellungen neben Druckbereichen und Kopfzeilen sitzen, und [Datenvalidierung, AutoFilter und Tabellen](hotxls-data-validation-autofilter-tables.html) lässt sich natürlich mit der Freigabe von xlsxSpoAutoFilter in einem gesperrten Bericht kombinieren

Das feinkörnige Schutzmodell und der Rest der XLSX-Lese-/Schreib-Engine werden in der HotXLS Component für Delphi und C++Builder ausgeliefert; die Produktseite enthält die vollständige Arbeitsblatt-API einschließlich der vollständigen Schutzoptionen-Referenz