给所有人,我被困在一个位置,并希望大家对此事提出建议。处理UAC管理令牌
我的应用程序由79个表格组成,其中许多地方需要管理员权限。程序在Windows启动时运行,因此不能使用默认管理令牌(asAdministator)。 Lazarus无法创建ActiveX dll,所以还有其他选择对我有利,我几乎完成了我在拉撒路的大部分项目,所以没有回头路。
给所有人,我被困在一个位置,并希望大家对此事提出建议。处理UAC管理令牌
我的应用程序由79个表格组成,其中许多地方需要管理员权限。程序在Windows启动时运行,因此不能使用默认管理令牌(asAdministator)。 Lazarus无法创建ActiveX dll,所以还有其他选择对我有利,我几乎完成了我在拉撒路的大部分项目,所以没有回头路。
如果您的应用程序真的没有做一些事情,需要管理员权限
,那就是如果一个非常大的;几乎没有人需要它
那么最好的方法是启动你自己的升级副本,通过一个命令行开关,说明你想要采取的行动。
比方说你想开始服务。你就可以创建一个UAC屏蔽按钮:
然后在点击事件中,你推出自己的升高复制,传递/StartService
命令行参数:
procedure TForm1.StartService(Sender: TObject);
begin
if IsUserAnAdmin then
begin
//no need to elevate, we're already an admin
StartService();
Exit;
end;
//We're a standard user, relaunch elevated to start the service
RunAsAdmin(0, ParamStr(0), '/StartService');
end;
与助手函数来检查我们是否拥有管理权限:
///This function tells us if we're running with administrative permissions.
function IsUserAdmin: Boolean;
var
b: BOOL;
AdministratorsGroup: PSID;
begin
{
This function returns true if you are currently running with admin privelages.
In Vista and later, if you are non-elevated, this function will return false (you are not running with administrative privelages).
If you *are* running elevated, then IsUserAdmin will return true, as you are running with admin privelages.
}
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;
将启动您的应用程序作为管理员r是使用ShellExecute与runas动词。我曾经创造了一个方便的包装:
function RunAsAdmin(hWnd: HWND; filename: string; Parameters: string): Boolean;
{
See Step 3: Redesign for UAC Compatibility (UAC)
http://msdn.microsoft.com/en-us/library/bb756922.aspx
}
var
sei: TShellExecuteInfo;
begin
ZeroMemory(@sei, SizeOf(sei));
sei.cbSize := SizeOf(TShellExecuteInfo);
sei.Wnd := hwnd;
sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
sei.lpVerb := PChar('runas');
sei.lpFile := PChar(Filename); // PAnsiChar;
if parameters <> '' then
sei.lpParameters := PChar(parameters); // PAnsiChar;
sei.nShow := SW_SHOWNORMAL; //Integer;
Result := ShellExecuteEx(@sei);
end;
现在你只需要观看的应用程序启动一个/StartService
命令行开关。在这个快速和肮脏的代码中,我把它放在FormActivate中。在现实中,你会把它放进你的项目文件,Application.Run前:
procedure TForm1.FormActivate(Sender: TObject);
begin
if FindCmdLineSwitch('startService', True) then
begin
//If we're not an admin, then use ShellExecute to launch ourselves as one
if not IsUserAdmin then
begin
//Relaunch ourselves as an admin
Toolkit.RunAsAdmin(0, ParamStr(0), '/StartService'); //don't forget to pass the command option
Application.Terminate;
Exit;
end;
//We are an admin; do the updates.
StartOurService();
MessageDlg('Service started!', mtInformation, [mbOk], 0);
Application.Terminate;
Exit;
end;
end;
注意:释放到公共领域的任何代码。无需归属。
您不能绕过UAC提示,这是设计。通常的做法是向应用程序添加应用程序清单,以便在启动应用程序时UAC提示只出现一次。通过这种方式,您的应用程序将以管理员身份运行,并且不会再有任何UAC提示。 (一个单独的问题:你的应用在做什么,它首先需要管理员权限?) –
我的程序在Windows启动时运行,并且在添加清单时,程序nevers开始。 – Rahul
然后,我建议不要在您的应用程序中执行需要管理权限的事情。您无法绕过UAC提示,这是设计。 –