2013-05-30 74 views
0

给所有人,我被困在一个位置,并希望大家对此事提出建议。处理UAC管理令牌

我的应用程序由79个表格组成,其中许多地方需要管理员权限。程序在Windows启动时运行,因此不能使用默认管理令牌(asAdministator)。 Lazarus无法创建ActiveX dll,所以还有其他选择对我有利,我几乎完成了我在拉撒路的大部分项目,所以没有回头路。

+0

您不能绕过UAC提示,这是设计。通常的做法是向应用程序添加应用程序清单,以便在启动应用程序时UAC提示只出现一次。通过这种方式,您的应用程序将以管理员身份运行,并且不会再有任何UAC提示。 (一个单独的问题:你的应用在做什么,它首先需要管理员权限?) –

+0

我的程序在Windows启动时运行,并且在添加清单时,程序nevers开始。 – Rahul

+0

然后,我建议不要在您的应用程序中执行需要管理权限的事情。您无法绕过UAC提示,这是设计。 –

回答

1

如果您的应用程序真的没有做一些事情,需要管理员权限

,那就是如果一个非常大的;几乎没有人需要它

那么最好的方法是启动你自己的升级副本,通过一个命令行开关,说明你想要采取的行动。

比方说你想开始服务。你就可以创建一个UAC屏蔽按钮:

ss

然后在点击事件中,你推出自己的升高复制,传递/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是使用ShellExecuterunas动词。我曾经创造了一个方便的包装:

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; 

注意:释放到公共领域的任何代码。无需归属。