Delphi code pour afficher un message convivial si vous n'êtes pas autorisé à faire quelque chose qui nécessite que comme administrateur possède des privilèges d'installer un service
-
27-10-2019 - |
Question
Un client signale une erreur de notre application lors de l'installation qui indique que le code « IsWindowsAdministrator » ci-dessous est de retour FALSE lorsque l'installation est effectuée par un administrateur de domaine. Connecté en tant qu'administrateur locale tout fonctionne très bien. Le programme d'installation (InnoSetup) appelle un fichier exe qui fait des opérations de gestionnaire de contrôle de service (voir ci-dessous), mais après la IsWindowsAdministrator ci-dessous a été appelé pour vérifier l'état de l'utilisateur.
Ma raison de vouloir vérifier l'état d'administration est de fournir une erreur gracieuse avant d'appeler les tâches de gestionnaire de services à travailler avec un pilote (voir ci-dessous CODE DRIVER INSTALLATION). Ce sont des tâches que je ne peux pas facilement faire à l'intérieur InnoSetup et moi avons choisi de les envelopper dans un petit exe appelé par l'installateur.
Le code de vérification Code ADMIN valide pour cette tâche? Ou devrais-je abandonner simplement et envelopper l'appel au gestionnaire de contrôle de service dans un essai, sauf avec un plus joli message d'erreur?
Merci
===================== CONDUCTEUR CODE ======================= INSTALL =
procedure ArtIODriver_Install( AShowSummary : boolean );
var
hServiceControlManager : THandle;
hService : SC_HANDLE;
ServiceStatus : TServiceStatus;
ServiceArgVectors : PAnsiString;
begin
If not IsWindowsAdministrator then
Raise EArtIODriver.Create(
'Error IODR4 - You must be a windows administrator to perform this action' );
If not FileExists( ArtIODriver_FilePath ) then
Raise EArtIODriver.CreateFmt(
'Error IODR7 - Unable to locate the driver file "%s"',
[ArtIODriver_FilePath] );
hService := 0;
hServiceControlManager := 0;
try
hServiceControlManager := OpenSCManager(
nil,
nil,
SC_MANAGER_ALL_ACCESS);
If hServiceControlManager = 0 then
Raise EArtIODriver.CreateFmt(
'Error IOD1 - Unable to open service control manager - %s',
[GetWinLastErrorStr] );
// can we see the service?
hService := OpenService(
hServiceControlManager,
JustDriverName,
SERVICE_ALL_ACCESS);
etc
etc
========= VÉRIFICATION CODE ADMIN ================
function IsWindowsAdministrator: Boolean;
// Returns TRUE if the user has administrator priveleges
// Returns a boolean indicating whether or not user has admin
// privileges. Call only when running under NT. Win9.x will return false!
var
hAccessToken : tHandle;
ptgGroups : pTokenGroups;
dwInfoBufferSize : DWORD;
psidAdministrators : PSID;
int : integer; // counter
blnResult : boolean; // return flag
const
SECURITY_NT_AUTHORITY: SID_IDENTIFIER_AUTHORITY =
(Value: (0,0,0,0,0,5)); // ntifs
SECURITY_BUILTIN_DOMAIN_RID: DWORD = $00000020;
DOMAIN_ALIAS_RID_ADMINS: DWORD = $00000220;
DOMAIN_ALIAS_RID_USERS : DWORD = $00000221;
DOMAIN_ALIAS_RID_GUESTS: DWORD = $00000222;
DOMAIN_ALIAS_RID_POWER_: DWORD = $00000223;
begin
Result := False;
blnResult := OpenThreadToken( GetCurrentThread, TOKEN_QUERY,
True, hAccessToken );
if ( not blnResult ) then
begin
if GetLastError = ERROR_NO_TOKEN then
blnResult := OpenProcessToken( GetCurrentProcess,
TOKEN_QUERY, hAccessToken );
end;
ptgGroups := nil;
if ( blnResult ) then
try
GetMem(ptgGroups, 1024);
blnResult := GetTokenInformation( hAccessToken, TokenGroups,
ptgGroups, 1024,
dwInfoBufferSize );
CloseHandle( hAccessToken );
if ( blnResult ) then
begin
AllocateAndInitializeSid( SECURITY_NT_AUTHORITY, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
psidAdministrators );
{$IFOPT R+}
{$DEFINE RMINUS}
{$R-}
{$ENDIF}
for int := 0 to ptgGroups.GroupCount - 1 do
if EqualSid( psidAdministrators,
ptgGroups.Groups[ int ].Sid ) then
begin
Result := True;
Break;
end;
{$IFDEF IMINUS}
{$R-}
{$UNDEF IMINUS}
{$ENDIF}
FreeSid( psidAdministrators );
end;
finally
If ptgGroups <> nil then
FreeMem( ptgGroups );
end;
end;
La solution
Plutôt que de vérifier si l'utilisateur est un administrateur, il vous suffit de vérifier le code d'erreur de OpenSCManager()
et / ou OpenService()
à la place. Si l'utilisateur ne dispose pas de droits suffisants, GetLastError()
retournera ERROR_ACCESS_DENIED
, par exemple:
hServiceControlManager := OpenSCManager(
nil,
nil,
SC_MANAGER_ALL_ACCESS);
If hServiceControlManager = 0 then
Begin
If GetLastError() = ERROR_ACCESS_DENIED then
Raise EArtIODriver.Create('Error IODR4 - You must be a windows administrator to perform this action' )
else
Raise EArtIODriver.CreateFmt('Error IOD1 - Unable to open service control manager - %s', [GetWinLastErrorStr] );
End;
J'utilise cette technique dans une application qui ne nécessite pas de droits d'administrateur pour la plupart de ses opérations pour détecter manuellement Invoke une invite UAC sous Vista + pour obtenir des droits suffisants, et cela fonctionne très bien.
Autres conseils
Parce que vous exécutez un exécutable de votre programme d'installation, ce que vous avez probablement besoin de faire est de créer un manifeste pour votre exécutable qui demande l'élévation. Ne demandez pas ce que vous avez des privilèges. Demandez Windows pour les privilèges dont vous avez besoin.
Comment puis-je créer un manifeste pour une fenêtre installateur