我一般在我们写的一些客户端软件中使用的流程是这样的:
- 尝试启动提升的进程以设置注册表项。
- 等到进程完成或抛出异常。
- 通过尝试读取预期的键来验证注册表键(非管理员可以这样做)
- 如果未设置键,则运行回退方法(例如,写入 HKCU)
我有一个帮助函数来运行看起来像这样的提升代码(VB.Net)。由于我只是使用带有命令行标志的同一应用程序来运行提升的进程,因此您可以看到我正在使用当前程序集作为进程名称。您可以替换为您的特定过程。
Private Function RunElevated(commandLine As String, Optional ByVal timeout As Integer = 0) As Boolean
Dim startInfo As New ProcessStartInfo
startInfo.UseShellExecute = True
startInfo.WorkingDirectory = Environment.CurrentDirectory
Dim uri As New Uri(Assembly.GetEntryAssembly.GetName.CodeBase)
startInfo.FileName = uri.LocalPath
startInfo.Verb = "runas"
startInfo.Arguments = commandLine
Dim success As Boolean
Try
Dim p As Process = Process.Start(startInfo)
' wait thirty seconds for completion
If timeout > 0 Then
If Not p.WaitForExit(30000) Then
' did not complete in thirty seconds, so kill
p.Kill()
success = False
Else
success = True
End If
Else
p.WaitForExit()
success = True
End If
Catch ex As Win32Exception
success = False
Catch ex As Exception
MsgBox("Error occurred while trying to start application as administrator: " & ex.Message)
success = False
End Try
Return success
End Function
在上面的代码中,我将异常作为失败代码处理,并且我将环境的执行时间限制为 30 秒。您可能不希望在您的情况下有时间限制,因此您可以删除该部分代码。
在管理员模式过程中,我首先使用此帮助函数仔细检查我实际上是管理员:
Public Function IsAdmin() As Boolean
Dim id As WindowsIdentity = WindowsIdentity.GetCurrent
Dim p As New WindowsPrincipal(id)
Return p.IsInRole(WindowsBuiltInRole.Administrator)
End Function
一旦我知道我是管理员,然后我继续设置注册表项并返回。调用程序然后验证密钥是否已成功设置,以确定是否需要运行回退过程。这是RunElevated
返回给调用者的时间,因为那时子进程已经完成并且设置键成功或失败。该代码如下所示:
Public Function UpdateSettings(...) As Boolean
Dim success As Boolean
Try
If Not IsAdmin() Then
' try to create the registry keys as administrator
success = RunElevated(Command() & " /admin", 30000)
Else
' if we're already admin, then just update directly
success = UpdateSettingsAdmin(...)
End If
success = success And ValidateUpdateSettings(...)
Catch ex As Exception
success = False
End Try
Return success
End Function