When I run the code I get this error: Class does not exists
from BuildExplicitAccessWithName.
I Hope that someone knows a bit more about this than I do.
var
pDACL: PACL;
pEA: PEXPLICIT_ACCESS_A;
begin
//Create new ACE
pEA := AllocMem(SizeOf(EXPLICIT_ACCESS));
ZeroMemory(pEA, SizeOf(EXPLICIT_ACCESS));
BuildExplicitAccessWithName(pEA,
'EVERYONE',
GENERIC_READ,
GRANT_ACCESS, //SET_ACCESS ?
NO_INHERITANCE);
showmessage( SysErrorMessage(GetLastError) ); //gives me this message:
Class does not exists
//Create new ACL
PDACL := AllocMem(SizeOf(ACL));
SetEntriesInAcl(1,
pEA,
nil,
pDACL);
showmessage( SysErrorMessage(GetLastError) );
//Assign ACL to file
SetNamedSecurityInfo('c:\test.txt',
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
nil, //owner SID?
nil, //group SID?
pDACL,
nil);
showmessage( SysErrorMessage(GetLastError) );
end;
BuildExplicitAccessWithName does _not_ set the last error code; it
simply always succeeds. The value returned by GetLastError is the value
that happened to be there all along. Try inserting a SetLastError(0)
before the call to BuildExplicitAccessWithName to see this in action.
best regards,
Marcel van Brakel
Project JEDI: http://delphi-jedi.org
Do not send me private e-mail unless explicitly requested otherwise.
If you do anyway please include a billing address...
What does this means, the file c:\test.txt is there for sure and the drive
is ntfs
Everything is not fine because it's not the SetNamedSecurityInfo
function that fails but SetEntriesInAcl. This is one function that does
return an error code. What you want to do is check the result of this
function before you continue to SetNamedSecurityInfo. Additionally, I
think you misunderstood the parameters of SetEntriesInAcl, specifically
the last one. You should not allocate memory for it because
SetEntriesInAcl does that for you (you should free afterwards). Here's a
corrected version of your code which functions correctly:
procedure TForm1.Button1Click(Sender: TObject);
var
pDACL: PACL;
pEA: PEXPLICIT_ACCESS_A;
R: DWORD;
begin
pEA := AllocMem(SizeOf(EXPLICIT_ACCESS));
BuildExplicitAccessWithName(pEA, 'EVERYONE', GENERIC_READ,
GRANT_ACCESS, NO_INHERITANCE);
R := SetEntriesInAcl(1, pEA, nil, pDACL);
if R = ERROR_SUCCESS then
begin
if SetNamedSecurityInfo('c:\test.txt', SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
nil, nil, pDACL, nil) <> ERROR_SUCCESS then
ShowMessage('SetNamedSecurityInfo failed: ' + SysErrorMessage
(GetLastError));
LocalFree(Cardinal(pDACL));
end
else ShowMessage('SetEntriesInAcl failed: ' + SysErrorMessage(R));
end;
PS AllocMem already sets the allocate memory buffer to all 0's so the
explicit call to ZeroMemory is redundant (which is why I removed it)!
I tried to play a bit around with it and when I inserts this line
showmessage( SysErrorMessage(GetLastError) );
after BuildExplicitAccessWithName, SetNamedSecurityInfo fails.
Can you explain that, I thought that GetLastError was a non destructive read
function, this is wrong when I read the Delphi help, that says the error
state is usual reset after reading.
But why does this mean anything ?
I tried to SetLastError(0) before the other two procedures to see if they
wanted a succesfull error code of the preceding procedure, but it stills
fails.
GetLastError is a non destructive read function (you can verify by
looking at the assembler) and no API function should be dependent on the
last error value upon entry.
The problem here is that the initial buffer for
BuildExplicitAccessWithName is too small and corrupts the stack. This in
turn is caused by an incorrect declaration of the EXPLICIT_ACCESS
structure in AccCtrl.pas. The problem seems to ly in the fact that the
enumeration types such as ACCESS_MODE are supposed to be 4 bytes each,
but AccCtrl.pas fails to include the $Z4 directive to accomplish this.
Note that the fact that this didn't show earlier is pure luck. The call
to SysErrorMessage simply surfaces it but is otherwise unrelated (any
function that allocates memory probably would have surfaced the
problem).
I suggest you copy the AccCtrl.pas file into your project directory, add
it too the project and include te {$Z4} directive somewhere at the top
of this unit. After a rebuild the problem should be solved.
Alternatively, you could download my Win32 API conversion package from
http://delphi-jedi.org and use those instead.