您最好的选择是在您自己的应用程序中自己启动服务。
问题当然是您的应用程序通常不是以管理员身份运行的(您也不希望这样)。这意味着您无法启动或停止服务。这就是为什么您应该暂时提升,执行所需的任务,然后退出。
换句话说,启动您的应用程序的第二个副本,传递一个命令行选项来指示您启动服务。第二个副本仅执行此操作,然后退出。
代码
首先我们有一个按钮,用户可以点击它来启动服务。我们首先检查用户是否已经是管理员,在这种情况下我们不需要做任何特殊的事情:
private void button1_Click(object sender, EventArgs e)
{
//If we're an administrator, then do it
if (IsUserAnAdmin())
{
StartService("bthserv"); //"Bluetooth Support Service" for my sample test code
return;
}
//We're not running as an administrator.
//Relaunch ourselves as admin, telling us that we want to start the service
ExecuteAsAdmin(Application.ExecutablePath, "/serviceStart");
}
//helper function that tells us if we're already running with administrative rights
private Boolean IsUserAnAdmin()
{
//A user can be a member of the Administrator group, but not an administrator.
//Conversely, the user can be an administrator and not a member of the administrators group.
//Check if the current user has administrative privelages
var identity = WindowsIdentity.GetCurrent();
return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
}
private void ExecuteAsAdmin(string Filename, string Arguments)
{
//Launch process elevated
ProcessStartInfo startInfo = new ProcessStartInfo(Filename, Arguments);
startInfo.Verb = "runas"; //the runas verb is the secret to making UAC prompt come up
System.Diagnostics.Process.Start(startInfo);
}
然后,在启动期间,我们只需要检查是否使用命令行选项调用我们。如果是,启动服务:
public Form1()
{
InitializeComponent();
//Ideally this would be in program.cs, before the call to Application.Run()
//But that would require me to refactor code out of the Form file, which is overkill for a demo
if (FindCmdLineSwitch("serviceStart", true))
{
StartService("bthserv"); //"Bluetooth Support Service"
Environment.Exit(0);
}
}
private bool FindCmdLineSwitch(string Switch, bool IgnoreCase)
{
foreach (String s in System.Environment.GetCommandLineArgs())
{
if (String.Compare(s, "/" + Switch, IgnoreCase) == 0)
return true;
if (String.Compare(s, "-" + Switch, IgnoreCase) == 0)
return true;
}
return false;
}
最后启动服务:
private void StartService(String ServiceName)
{
TimeSpan timeout = TimeSpan.FromMilliseconds(30000); //30 seconds
using (ServiceController service = new ServiceController(ServiceName))
{
try
{
service.Start();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error starting service");
return;
}
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
}
特别花哨
您可以添加任意数量的精美代码。检测用户是否不是管理员,如果不是,则使用正确的 Windows API (BCM_SETSHIELD message) 为您的按钮添加 UAC 屏蔽:
这样用户就知道期望 UAC 会出现;因为您遵循了 Microsoft UI 指南:
指南
UAC 盾牌图标
显示带有 UAC 盾牌的控件,以指示在完全启用 UAC 时任务需要立即提升,即使 UAC 当前未完全启用也是如此。如果向导和页面流的所有路径都需要提升,请在任务的入口点显示 UAC 盾牌。 正确使用 UAC 防护罩有助于用户预测何时需要提升。
阅读奖励
注意:任何代码都会发布到公共领域。无需署名。