我正在寻找工作(显然)Delphi 7 代码,以便我可以检查我的程序是否以管理员权限启动。
提前致谢
[--- 重要更新 ---]
到目前为止,在查看了答案中的代码后,我意识到我的问题可能不是很清楚,或者至少不完整:
我想知道我的 Delphi 7 程序是否以设置了“以管理员身份运行”复选框启动。
换句话说:我想知道我的Delphi 7 程序是否可以在 c:\Program Files... 文件夹中创建/更新文件。
仅检查您是否具有管理员权限是不够的。
Windows API(用于)有一个帮助函数(IsUserAnAdmin)来判断您是否以管理权限运行。
OS Account Type UAC IsUserAdmin
============== ============= ============ ===========
Windows XP Standard n/a False
Windows XP Administrator n/a True
Windows Vista Standard Disabled False
Windows Vista Administrator Disabled True
Windows Vista Standard Not Elevated False
Windows Vista Administrator Not Elevated False
Windows Vista Standard Elevated True
Windows Vista Administrator Elevated True
Shell32 包装函数已弃用;这很好,因为它只是其他代码的包装器,您仍然可以称自己为:
function IsUserAdmin: Boolean;
var
b: BOOL;
AdministratorsGroup: PSID;
begin
{
This function returns true if you are currently running with admin privileges.
In Vista and later, if you are non-elevated, this function will return false
(you are not running with administrative privileges).
If you *are* running elevated, then IsUserAdmin will return true, as you are
running with admin privileges.
Windows provides this similar function in Shell32.IsUserAnAdmin.
But the function is deprecated, and this code is lifted
from the docs for CheckTokenMembership:
http://msdn.microsoft.com/en-us/library/aa376389.aspx
}
{
Routine Description: This routine returns TRUE if the callers
process is a member of the Administrators local group. Caller is NOT
expected to be impersonating anyone and is expected to be able to
open its own process and process token.
Arguments: None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
}
b := AllocateAndInitializeSid(
SECURITY_NT_AUTHORITY,
2, //2 sub-authorities
SECURITY_BUILTIN_DOMAIN_RID, //sub-authority 0
DOMAIN_ALIAS_RID_ADMINS, //sub-authority 1
0, 0, 0, 0, 0, 0, //sub-authorities 2-7 not passed
AdministratorsGroup);
if (b) then
begin
if not CheckTokenMembership(0, AdministratorsGroup, b) then
b := False;
FreeSid(AdministratorsGroup);
end;
Result := b;
end;
换句话说:这个功能给你你想要的答案:用户可以更新程序文件。
您需要对检查您是否是管理员组成员的代码感到厌烦。您可以是管理员组的成员,但没有任何管理权限。您也可以拥有管理权限,但不是管理员组的成员。
program Project1;
{$APPTYPE CONSOLE}
uses
Windows,
ShellAPI;
// high-level wrapper, see Ian Boyd's answer for details on this function
function IsUserAnAdmin(): BOOL; external shell32;
begin
if IsUserAnAdmin() then
Writeln('TEH R00T OMG')
else
Writeln('rtfmnoobkthx');
Readln;
end.
JEDI 项目的JEDI 代码库在 JclSecurity 单元中有一个 IsAdministrator 函数,它会告诉您。它仍然适用于 Delphi 7。
Microsoft 推荐的解决此问题的方法:将应用程序拆分为两个。
http://msdn.microsoft.com/en-us/library/aa511445.aspx
第一个应用程序检查是否需要运行第二个应用程序。
第二个应用程序包含一个“需要管理员”清单(就像大卫写的那样),你用 ShellExecuteEx 'runas' 动词打开它。
如果是网络更新程序,工作流程可能是这样的:
更新程序1.exe
更新程序2.exe
这有几个优点:
它也适用于 Windows XP,如果您不是管理员,您会看到一个登录对话框。
我在 Windows XP、7 和 8(管理员和受限帐户)上使用 Delphi 7 测试了此代码:
Function CheckTokenMembership(TokenHandle: THandle; SIdToCheck: PSID; var IsMember: Boolean): Boolean; StdCall; External AdvApi32;
Function IsAdmin: Boolean;
const
DOMAIN_ALIAS_RID_ADMINS = $00000220;
SECURITY_BUILTIN_DOMAIN_RID = $00000020;
SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
var
Admin: Boolean;
AdmGroup: PSID;
Begin
Admin := AllocateAndInitializeSid(SECURITY_NT_AUTHORITY,
2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, AdmGroup);
If (Admin) Then
Begin
If (not CheckTokenMembership(0, AdmGroup, Admin)) Then
Admin := False;
FreeSid(AdmGroup);
end;
Result := Admin;
end;
Jwscl (The Jedi Windows Security Library) 有一个功能:JwCheckAdministratorAccess。
function JwCheckAdministratorAccess: boolean;
用法很简单:
Uses
JwsclToken;
IsElevated := JwCheckAdministratorAccess;
如果启用了 UAC,此功能也适用于 Windows Vista 及更高版本。如果当前进程未提升,则返回值为 false,即使令牌包含管理员组(当时已禁用)。此功能检测管理员组中的组成员身份,这意味着用户不需要直接在管理员组中,而是一个组可以是管理员组的成员。
此代码在 D7..XE inc 下工作。
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;