|
Antwort |
Registriert seit: 16. Jun 2003
So...es ist Geschafft. Teil eins ist fertig und hängt an diesem Beitrag drann. Natürlich incl. Beispiel-Code.
Das Tutorial zeigt euch die Grundlagen, wie ihr diesen Dialog nutzen könnt. In den Fortsetzungen werde ich (sofern gewünscht) auf spezielle Aspekte eingehen und einiges näher erleutern. Feedback ist natürlich immer erwünscht
e=mc² or energy = milk * coffee²
|
Delphi 2006 Professional |
#4
naja, immer noch besser als "runterladen" -> "entpacken" -> "irgendwo ablegen"
denn wenn es im Forum ist taucht es in der Suche auf usw... von daher macht es schon Sinn... |
Zitat |
Delphi 7 Personal |
#7
Zitat:
Jetzt wollen wir mal in die Hände spuken [...]
|
Zitat |
Delphi 10.3 Rio |
#8
So..hier nun die Online-Variante
Zugriffsrechtedialog von Windows nutzen. (Teil 1: Readonly-Anzeige der Dateirechte) 1. Einleitung Wer kenn das nicht. Man ärgert sich mal wieder, das man die Rechte an einer Datei oder einem anderen Objekt des Systems nicht vom Anwender einstellen lassen kann. Es gibt natürlich einige Dialoge anderer Hersteller, mit denen man das Einbauen kann. Aber warum Fremdware nutzen wenn Windows sowas schon hat ? Ich werde hier also eine Methode vorstellen, wie man diesen Dialog von Delphi aus nutzen kann. Ich werde die Funktion der einzelnen Methoden vorstellen. An vielen Stellen werde ich aber auf die entsprechenden Eintragungen der MSDN verweisen, da hier die Informationen zu den entsprechenden API-Funktionen wesentlich besser erklärt sind. 2. Vorbereitungen Nach langem Kampf durch die Wüste des Netzes, immer auf der Suche nach Informationen zum Thema, hab ich es dann endlich doch geschafft, den Dialog wie gewünscht anzuzeigen.Zuerstmal sollte man sich mit dem Grundlegenden Sicherheitskonzept von Windows befassen. Schließliche müssen wir es handhaben können, um dem Dialog die richtigen Informationen zu geben. Für den Einstieg in die Thematik verweise ich mal auf Luckies Tutorials. Auch MSDN bietet sehr viele Informationen zum Thema. EntsprechendeLinks findet ihr am Ende dieses Teils.Weiter brauchen wir ein Windows, das diesen Dialog natürlich zur Verfügung steht. Das ist ab Windows 2000 der Fall. Windows NT 4 hat noch eine andere Variante, die wir in einem späteren Teil besprechen. Windows 95/98/Me haben diesen Dialog nicht, das sie nur als Single-User Betriebessystem ausgelegt sind.Zur Arbeitserleichterung brauchen wir jetzt nur noch die API Deklarationen für den entsprechenden Bereich. Leider sind die von Borland bisher gelieferten ungenügend für unserer Zwecke. Aber zum Glück gibts ja das JEDI-Projekt. Dort finden wir auch eine relativ aktuelle Version der API's (Win32Api). Unter [URL =http://delphi-jedi.org]http://delphi-jedi.org[/url] finden wir unter dem Punkt "Windows 32-bit API conversions library (source)" das entsprechende Packet. Da es sich dabei um keine Komponenten handelt, können wir diese einfach per Uses aufnehemnen. Aufpassen muß man nur mit Konflikten mit den Delphi eigenen Units. Also verwendet man entweder NUR die Delphi-Units oder NUR die Jedi-Units. Damit läßt sich das meiste vermeiden. Einziger Knackpunkt, den ich bisher gefunden habe, ist der Delete-Befehl. Dieser wird in einer Jedi-Unit überlagert. Also muß ein "system." davor. 3. The Beginning Als Beispiel für diese Tutorial hab ich mir die allgemein bekannten Dateirechte ausgesucht. Mit diesen hat jeder schon mal zu tun gehabt und man braucht dafür auch kein Netzwerk. Unser Ergebnis zum Schluss soll also wie folgt aussehen: Der Dialog selbst kann alle nur erdenklichen Systemobjekte, die für Zugriffsrechte relevant sind, behandeln (Drucker, Netzwerkfreigaben, Registry-Schlüssel und einiges mehr.). Eigentlich ist das ganze ja kein Dialog im herkömmlichen sind. Es handelt sich eigentlich vielmehr um einen Reitertab, der vom System auch in Form eines eigenen Dialoges zur Verfügung gestellt wird. Wenn ich im Folgenden also vom Dialog spreche, meine ich diesen Reiter. Die Anzeige des Dialogs kann über zwei Wege erfolgen. Entweder man bindet ihn direkt als Sheet in eine entsprechende Komponente ein (das folgt in einen der nächsten Teile), oder man zeigt ihn als eigenen Dialog an. Dazu dienen zwei entsprechende API-Funktionen Für die Sheet-Variante ist das CreateSecurityPage und für die Dialog-Variante ist das EditSecurity . Beide Varianten erwarten als Parameter ein Objekt das das ISecurityInformation Interface implementiert. Zusätzlich erwartet EditSecurity noch ein Fensterhandle, das als Elternfenster agiert. CreateSecurityPage gibt als Rückgabewert ein Handle auf ein Tabsheet zurück, EditSecurity einen Wert vom Typ boolean. Damit können wir schonmal einen ersten Schritt auf den Weg machen. Wir fangen ein neues Projekt an, mit einer einfachen Form. Darauf platzieren wir einen Button und einen Fileopen-Dialog. Hinter das onClick-Ereignis des Buttons legen wir folgende Code-Zeilen an:
Delphi-Quellcode:
Wenn wir jetzt compilieren würden, würde das nicht funktionieren. Das System kenn die Klasse TFileSecurityInformation1
noch nicht. Aber das wird sich gleich ändern.
procedure TForm1.Button1Click(Sender:TObject);
var ai : TFileSecurityInformation1; begin if OpenDialog1.execute then begin ai := TFileSecurityInformation1.create(OpenDialog1.filename); EditSecurity(handle,ai); end; end; 4. Des Pudels Kern ist in unserem Fall ein Interface mit Namen ISecurityInformation . Mit Hilfe der dort definierten Methoden, steuern wir den Dialog, bzw. erhält der Dialog die Daten und Informationen, die er für die Anzeige benötigt. Und genau dieses Interface müssen wir nun in Form einer eigenen Klasse implementieren. Aber, Step by Step. Zuerst brauchen wir in unserem Projekt eine neue Unit. In diese holen wir uns erstmal per Uses die nötigen Units der Jedi-Api rein. Das sind die Units
Damit haben wir schonmal alles an Bord, war wir für unsere neue Klasse brauchen. Jetzt deklarieren wir erstmal unsere Klasse.
Delphi-Quellcode:
Damit haben wir jetzt den Rumpf, den wir brauchen. Jetzt wollen wir mal in die Hände spuken und
TYPE
TFileSecurityInformation1 = Class(TInterfacedObject,ISecurityInformation) private ffilename : Widestring; fpagetitle : Widestring; protected function GetAccessRights(pguidObjectType: LPGUID; dwFlags: DWORD; out ppAccess: PSI_ACCESS; out pcAccesses,piDefaultAccess: ULONG): HRESULT;stdcall; function GetInheritTypes(out ppInheritTypes: PSI_INHERIT_TYPE;out pcInheritTypes: ULONG): HRESULT;stdcall; function GetObjectInformation(out pObjectInfo: SI_OBJECT_INFO): HRESULT;stdcall; function GetSecurity(RequestedInformation: SECURITY_INFORMATION;out ppSecurityDescriptor: PSECURITY_DESCRIPTOR; fDefault: BOOL): HRESULT;stdcall; function MapGeneric(pguidObjectType: LPGUID; pAceFlags: PUCHAR;pMask: PACCESS_MASK): HRESULT;stdcall; function PropertySheetPageCallback(hwnd: HWND; uMsg: UINT;uPage: SI_PAGE_TYPE): HRESULT;stdcall; function SetSecurity(SecurityInformation: SECURITY_INFORMATION;pSecurityDescriptor: PSECURITY_DESCRIPTOR): HRESULT;stdcall; public Constructor Create(Afile:widestring); published property Filename : Widestring Read fFilename write fFilename; property PageTitle : widestring read fpagetitle write fpagetitle; end; das Teil mit Leben füllen. 5. Im Detail Die beiden Propertys und den Konstruktor brauch ich glaube nicht groß Beschreiben, da hier nix großes passiert. Im Konstruktor setzen wir lediglich die Property Filename und ansonsten rufen wir nur die inherited Methode auf. Das wars schon. Viel interressanter sind die anderen Methoden, die wir nun im Folgenden näher untersuchen. a)GetObjectInformation(out pObjectInfo: SI_OBJECT_INFO): HRESULT; Diese Methode wird vom Dialog immer dann aufgerufen, wenn er Informationen braucht, wie er sich Darstellen und Verhalten soll. Dazu erwartet er von einen Record vom Typ SI_OBJECT_INFO, den wir hier befüllen müssen. Der Record hat folgende Felder:
Mit diesen Informationen können wir der Methoden jetzt Leben einhauchen:
Delphi-Quellcode:
b) GetAccessRights(pguidObjectType: LPGUID; dwFlags: DWORD;out ppAccess: PSI_ACCESS; out pcAccesses, piDefaultAccess: ULONG): HRESULT;
function TFilesecurityInformation1.GetObjectInformation(out pObjectInfo: SI_OBJECT_INFO):HRESULT;
begin ZeroMemory(@pObjectInfo,SizeOf(SI_OBJECT_INFO)); pObjectInfo.dwFlags := SI_READONLY or SI_ADVANCED or SI_PAGE_TITLE; pObjectInfo.hInstance := SysInit.HInstance; pObjectInfo.pszObjectName := pwidechar(ffilename); pObjectInfo.pszPageTitle := pwidechar(fpagetitle); Result := S_OK; end; Diese Methode wird immer dann vom Dialog aufgerufen, wenn er wissen will, welche Rechte mit welchen Bezeichnungen er anzeigen soll.
Viel Text, ich hoffe das erschlägt euch nicht gleich . Schauen wir uns mal kurz die Elemente eines SI_ACCESS-Records an.
Damit haben wir eigentlich alles zusammen, um die Methode zum leben zu erwecken. Das sieht dann so aus:
Delphi-Quellcode:
So..weiter im Text mit der nächsten Methode
function TFilesecurityInformation1.GetAccessRights(pguidObjectType: LPGUID; dwFlags: DWORD;
out ppAccess: PSI_ACCESS; out pcAccesses, piDefaultAccess: ULONG): HRESULT; begin ppAccess := @FileAccessRights[0]; pcAccesses := 15; piDefaultAccess := 0; Result := S_OK; end; c) function GetInheritTypes(out ppInheritTypes: PSI_INHERIT_TYPE;out pcInheritTypes: ULONG): HRESULT;stdcall; Diese Methode wird vom Dialog aufgerufen, wenn er etwas über die "Vererbung" der Rechte an Untergeordnete Objekte wissen will. Da diese Thema nicht ganz einfach ist, und den Rahmen dieses Tutorials sprengen würde, verweise ich am Ende des Tuts auf einige Seiten, die euch mehr Informationen liefern. An dieser Stelle definieren wir uns wieder ein Konstanten-Array, da auch diese Teile sicher eher selten ändern.
Delphi-Quellcode:
Wie ihr seht, ist der Record ganz ähnlich aufgebaut, wie SI_ACCESS. Nur die Flags haben hier eine andere Bedeutung. Sie geben die Art der Vererbung an. Die IDS_-Konstanten sind wieder Strings für die Bezeichnungen. Damit können wir dann auch die Methode implementieren, was so aussieht:
CONST
IDS_THISFILE_ONLY = 'Nur diese Datei/dieses Verzeichnis'; IDS_THISANDSUB = 'Diese Datei/Verzeichnis und Unterverzeichnisse'; IDS_ONLY_SUBS = 'Nur Unterverzeichnisse'; FileInheritTypes: array [0..2] of SI_INHERIT_TYPE = ( (pguid:@GUID_NULL; dwFlags: 0; pszName:IDS_THISFILE_ONLY; ), ( pguid:@GUID_NULL; dwFlags:CONTAINER_INHERIT_ACE; pszName:IDS_THISANDSUB; ), ( pguid:@GUID_NULL; dwFlags:INHERIT_ONLY_ACE or CONTAINER_INHERIT_ACE; pszName:IDS_ONLY_SUBS; ) );
Delphi-Quellcode:
Langsam kommt Land in Sicht. Nicht mehr lange und wir können unseren Dialog in aller Pracht bewundernt
function TFilesecurityInformation1.GetInheritTypes(out ppInheritTypes: PSI_INHERIT_TYPE;out pcInheritTypes: ULONG): HRESULT;
begin ppInheritTypes := @FileInheritTypes; pcInheritTypes := 3; Result := S_OK; end; d)MapGeneric(pguidObjectType: LPGUID; pAceFlags: PUCHAR;pMask: PACCESS_MASK): HRESULT; Es gibt unter Windows sog. generische Zugriffsrechte. Das heißt nix anderes, als das sie unabhängig vom eigentlichen Objekt sind und sozusagen global vorhanden sind. Damit Windows, und damit der Dialog, weiß, welches unserer Zugriffsrechte welchem generischen Recht entspricht, müssen wir diese Methode befüllen. Der Einfachheit halber, definieren wir uns auch hier wieder ein Konstanten-Array, das wie folgt aussieht:
Delphi-Quellcode:
Wie ihr seht, nix dramatisches. Und nun die entsprechende Methode dazu:
CONST
FileMaping : GENERIC_MAPPING=( GenericRead: FILE_READ_DATA; GenericWrite: FILE_WRITE_DATA; GenericExecute:FILE_EXECUTE; GenericAll: FILE_ALL_ACCESS );
Delphi-Quellcode:
MapGenericMask ist eine API Routine, die uns die Zuweisung übernimmt.
function TFilesecurityInformation1.MapGeneric(pguidObjectType: LPGUID; pAceFlags: PUCHAR;pMask: PACCESS_MASK): HRESULT;
var maping : GENERIC_MAPING; begin maping := FileMaping; MapGenericMask(pMask^,maping); pMask^ := pMask^ and (not SYNCHRONIZE); Result := S_OK; end; e)GetSecurity(RequestedInformation: SECURITY_INFORMATION;out ppSecurityDescriptor: PSECURITY_DESCRIPTOR; fDefault: BOOL): HRESULT; Sodale, das ist nun die letzte, für unser Beispiel wichtige, Methode. Sie wird vom Dialog immer dann aufgerufen, wenn er die vorhanden Zugriffsrechte des jeweiligen Objektes (in unserem Beispiel der Datei) benötigt. Da Luckie schon sehr gut beschrieben hat, wie man diese Information dem System entlocken kann, kürze ich das hier ab und stelle euch gleich die fertige Methode vor:
Delphi-Quellcode:
Über den Parameter RequestedInformation sagt uns der Dialog, was er den nun wissen will. Diesen können wir direkt an die API-Routine übergeben, die uns, hoffentlich, die Infos im SecurityDescriptor zurück gibt.
function TFilesecurityInformation1.GetSecurity(RequestedInformation: SECURITY_INFORMATION;
out ppSecurityDescriptor: PSECURITY_DESCRIPTOR; fDefault: BOOL): HRESULT; var POWNER,POTHER : PPSID; PDACL,PSACL : PPACL; begin RESULT := E_FAIL; POWNER := NIL; POTHER := NIL; PDACL := NIL; PSACL := NIL; if (GetNamedSecurityInfow(pwidechar(ffilename), SE_FILE_OBJECT,RequestedInformation,powner,pother,pdacl,psacl,ppSecurityDescriptor)=0) then RESULT := S_OK; end; f)SetSecurity(SecurityInformation: SECURITY_INFORMATION;pSecurityDescriptor: PSECURITY_DESCRIPTOR): HRESULT; Diese Methode wird immer dann vom Dialog aufgerufen, wenn der Benutzer etwas an den Rechten geändert hat, und diese dem Objekt zugewiesen werden müssen. Da wir hier nur die Rechte Anzeigen wollen, geben wir einfach S_OK als Result zurück. g)PropertySheetPageCallback(hwnd: HWND; uMsg: UINT;uPage: SI_PAGE_TYPE): HRESULT; Wird immer dann aufgerufen, wenn eine Eigenschaftsseite erzeugt oder freigegeben wird. uMSG gibt dabei an, was grad der Fall ist (Erzeugen, Freigeben, Initialisieren). hwnd gibt das Handle auf die Eigenschaftsseite an (nur im Falle von Initialisieren, ansonsten ist das 0) und uPage sagt uns, um welchen Eigenschaftsseitentyp es sich handelt (Standard, Erweitert usw..). Für unser Beispiel brauchen wir auch das nicht. Also geben wir als Result einfach nur S_OK zurück (oder zu bayrisch "Bast scho"). 6. The End Ja, es ist viel Tipp-Arbeit. Aber, wie ich finde, die Arbeit lohnt sich. Zumal das ganze sich sehr flexibel einsetzen läßt. Nach dem ihr das ganze jetzt gespeichert habt, und entsprechend ins Testprojekt eingebunden habt, können wir das ganze jetzt compilieren und starten. Nach einem Klick auf den Button und der Auswahl einer Datei, sollte der Dialog auftauchen. 7. Links zum Thema http://www.michael-puff.de Hat zwei sehr gute Artikel (06/2006) die einige Grundlagen erklären http://www.codeproject.com/win32/accessctrl1.asp Eine sehr gute Artikelreihe (Englisch), die das Sicherheitskonzept von Windows recht gut erklärt. Schade das die Codeschnippsel für C++ sind. http://msdn.microsoft.com Tja..wer kennt sich besser aus als MS ? Neben den Beschreibungen der API-Funktionen und Interfaces findet ihr im englischsprachigen Bereich auch einige Artikel (als Suchbegriff einfach mal "Keith Brown" eingeben), die sich mit verschiedenen Aspekten des Sicherheitskonzepts befassen. So..das war es für den 1. Teil. Ich hoffe es bringt euch ein wenig weiter und stiftet euch zu eigenen Experimenten an. Euer Ghostwalker (aka Uwe Rupprecht)
Uwe
|
Zitat |
Delphi 10.2 Tokyo Professional |
#9
Hallo,
warum wird auf die Fehlermeldung nicht eingegangen? Ich finde den Artikel ganz gut, auch wenn für die Freigabe der Unicode-Strings in SI_OBJECT_INFO andere Quellen bemüht werden müssen(sind ja nur kleine Fallstricke). Gruss |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |