因此,我使用一个用户来运行以下代码,该用户是 Windows 7 x64 计算机上“用户”组的成员。我正在尝试使用模拟(通过以属于管理员组的用户身份登录)来允许当前用户从注册表中读取数据。由于某种原因,登录成功,但即使 WindowsIdentity.GetCurrent() 返回属于管理员组的用户,我仍然收到一条错误消息,指出“不允许请求的注册表访问”。我做错了什么?
这是主要代码:
Dim ra As RunAs = Nothing
If UserDomain.Length > 0 AndAlso UserName.Length > 0 AndAlso UserPassword.Length > 0 Then
ra = New RunAs
ra.ImpersonateStart(UserDomain, UserName, UserPassword)
End If
If Not My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) Is Nothing AndAlso _
My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) = 0 Then
My.Computer.Registry.SetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 1)
End If
假设我的 RunAs 类如下:
Public Class RunAs
Public Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
Public Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
ByRef DuplicateTokenHandle As IntPtr) As Boolean
' Test harness.
' If you incorporate this code into a DLL, be sure to demand FullTrust.
<PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
Public Sub ImpersonateStart(ByVal Domain As String, ByVal userName As String, ByVal Password As String)
tokenHandle = IntPtr.Zero
' Call LogonUser to obtain a handle to an access token.
Dim returnValue As Boolean = LogonUser(userName, Domain, Password, 2, 0, tokenHandle)
'check if logon successful
If returnValue = False Then
Dim ret As Integer = Marshal.GetLastWin32Error()
Console.WriteLine("LogonUser failed with error code : {0}", ret)
Throw New System.ComponentModel.Win32Exception(ret)
Exit Sub
End If
'Logon succeeded
' Use the token handle returned by LogonUser.
Dim newId As New WindowsIdentity(tokenHandle)
impersonatedUser = newId.Impersonate()
End Sub
End Class
最佳答案
我同意@Hans。使用UAC,您需要以UAC权限重新启动应用程序,这将导致显示UAC提示。实现此目的的简单方法如下:
- 在应用程序的正常路径中,当需要管理员权限时,请使用 UAC 请求和命令行标志重新启动应用程序,例如
/admin
。 - 第二次运行应用程序时,检测标志
/admin
,并执行应用程序的管理部分。 - 当第二次运行完成 (#2) 时,如果成功,则继续第一遍的应用程序逻辑。如果不成功,则显示错误/执行适当的异常处理逻辑。
在我们的应用程序中,我有一个名为 RunElevated
的帮助程序方法,它尝试使用请求的管理员权限重新启动应用程序,这将导致显示 UAC 提示(我还包含了我的 IsAdmin() 帮助程序函数):
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
Public Function IsAdmin() As Boolean
Dim id As WindowsIdentity = WindowsIdentity.GetCurrent
Dim p As New WindowsPrincipal(id)
Return p.IsInRole(WindowsBuiltInRole.Administrator)
End Function
使用时,我传递一个标志并运行提升。就我而言,我有一个设置注册表项的函数,并使用标志 /setregistry
来指示实例是出于 UAC 目的而启动的,以便仅设置注册表项。该代码看起来像这样:
Dim success As Boolean
If Not IsAdmin() Then
' try to create the registry keys as administrator
success = RunElevated("/setregistry", 30000)
success = success And ValidateKeysSet() ' check if it was successful
Return success
End If
' If we are Admin (Not IsAdmin() = False), then go ahead and set the keys here
然后在启动逻辑(Form_Load,因为这是一个表单应用程序)中,我检查该标志是否存在:
If Command.ToLower.Contains("/setregistry") Then
' if application instance is for sole purpose of setting registry keys as admin
If IsAdmin() Then
SetRegistryKeys() ' set the keys, since we are admin
Else
MsgBox("ERROR: Application must be run as administrator to set registry keys.")
End If
Else
' Perform normal startup process
End If
关于c# - Windows 7 中的 .NET 模拟(不允许请求的注册表访问),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7573192/