问题
I have this code:
RegistryKey myKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Android Studio", true);
myKey.SetValue("StartMenuGroup", "Droidio", RegistryValueKind.String); // was "Android Studio" - change to "Droidio"
...which I adapted from here.
Running it, though results in the following NRE dump:
*System.NullReferenceException was unhandled
_HResult=-2147467261
_message=Object reference not set to an instance of an object.
HResult=-2147467261
IsTransient=false
Message=Object reference not set to an instance of an object.
Source=Sandbox
StackTrace:
at Sandbox.Form1.button57_Click(Object sender, EventArgs e) in c:\HoldingTank\Sandbox\Form1.cs:line 2524
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Sandbox.Program.Main() in c:\HoldingTank\Sandbox\Program.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:*
The registry setting I'm trying to update (as a test; I'll then set it back) is here:
How could this be failing when the registry key is plainly there?
UPDATE
I tried an alternative approach, which I adapted from here:
RegistryKey reg32key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
RegistryView.Registry32);
RegistryKey reg_32bit_AppKey =
reg32key.OpenSubKey(@"HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio");
if (reg_32bit_AppKey != null)
{
MessageBox.Show(String.Format("value was {0}",
reg_32bit_AppKey.GetValue("StartMenuGroup").ToString()));
reg_32bit_AppKey.SetValue("StartMenuGroup", "Droidio");
MessageBox.Show(String.Format("value is now {0}",
reg_32bit_AppKey.GetValue("StartMenuGroup").ToString()));
}
else
{
MessageBox.Show("Cannot open registry");
}
...but, while it doesn't crash, I see the "Cannot open registry" message.
UPDATE 2
With this (doubling the bitness):
RegistryKey reg64key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
RegistryView.Registry64);
RegistryKey reg_64bit_AppKey =
reg64key.OpenSubKey(@"HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio");
if (reg_64bit_AppKey != null)
{
MessageBox.Show(String.Format("value was {0}",
reg_64bit_AppKey.GetValue("StartMenuGroup").ToString()));
reg_64bit_AppKey.SetValue("StartMenuGroup", "Droidio");
MessageBox.Show(String.Format("value is now {0}",
reg_64bit_AppKey.GetValue("StartMenuGroup").ToString()));
}
else
{
MessageBox.Show("Cannot open registry");
}
...I still get the "Cannot open registry" result.
UPDATE 3
Okay, changing the code to this (removing the "HKEY_LOCAL_MACHINE" from the alternative attempt):
RegistryKey reg64key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
RegistryView.Registry64);
RegistryKey reg_64bit_AppKey = reg64key.OpenSubKey(@"SOFTWARE\Android
Studio");
if (reg_64bit_AppKey != null)
{
MessageBox.Show(String.Format("value was {0}",
reg_64bit_AppKey.GetValue("StartMenuGroup").ToString()));
reg_64bit_AppKey.SetValue("StartMenuGroup", "Droidio");
MessageBox.Show(String.Format("value is now {0}",
reg_64bit_AppKey.GetValue("StartMenuGroup").ToString()));
}
else
{
MessageBox.Show("Cannot open registry");
}
...changes the exception. First, though, there is some progress, as I see, "value was Android Studio"
...but then it breaks on the next line, namely:
reg_64bit_AppKey.SetValue("StartMenuGroup", "Droidio");
...with:
*System.UnauthorizedAccessException was unhandled
_HResult=-2147024891
_message=Cannot write to the registry key.
HResult=-2147024891
IsTransient=false
Message=Cannot write to the registry key.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowUnauthorizedAccessException(ExceptionResource resource)
at Microsoft.Win32.RegistryKey.EnsureWriteable()
at Microsoft.Win32.RegistryKey.SetValue(String name, Object value, RegistryValueKind valueKind)
at Microsoft.Win32.RegistryKey.SetValue(String name, Object value)
at Sandbox.Form1.button57_Click(Object sender, EventArgs e) in c:\HoldingTank\Sandbox\Form1.cs:line 2559
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentM
anager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Sandbox.Program.Main() in c:\HoldingTank\Sandbox\Program.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object
state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state,
Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:*
So why can I read, but not write? I am running Visual Studio 2013 in Administrator mode as I run this code...
UPDATE 4
It's an unauthorized access problem now.
Here's the value of reg_64bit_AppKey as I reach the line to set the value:
F10ing through it coughs up the "Unauthorized access" whin[g]ing.
UPDATE 5
Creating a file with this content:
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio]
"StartMenuGroup"="Droidio"
...naming it "DroidioReg.reg", and manually selecting the Merge context menu from Windows Explorer did what I expected (hoped, anyway): changed StartMenuGroup's value to "Droidio". Actually, even just 2-clicking the file and moving through all the confirmation dialogs works, too.
So, this is kludgy to the Nth degree, but is it possible to programatically call "Merge" on that file - IOW, place that file on the handheld device and then, in code, execute it? Will the user have to navigate through the cautionary dialogs, or is there a way to programmatically prevent those from displaying?
回答1:
Use an escaped string instead of a string literal. The OpenSubKey method doesn't appear to read your escaped path properly.
Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Android Studio", true);
回答2:
I found the key point to overcome the access rights violation here in a comment by Pwninstein - simply appending a "true" to the OpenSubKey() method does the trick.
I was cowed, but now I can crow that the working code, assembled via tWotC (the Wisdom of the Crowd) is:
RegistryKey reg64key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey reg_64bit_AppKey = reg64key.OpenSubKey(@"SOFTWARE\Android Studio", true);
if (reg_64bit_AppKey != null)
{
//MessageBox.Show(String.Format("value was {0}", reg_64bit_AppKey.GetValue("StartMenuGroup")));
reg_64bit_AppKey.SetValue("StartMenuGroup", "Droidio", RegistryValueKind.String);
//MessageBox.Show(String.Format("value is now {0}", reg_64bit_AppKey.GetValue("StartMenuGroup")));
}
else
{
MessageBox.Show("Cannot open registry");
}
For my real case, I will doubtless need to use the 32-bit version, instead of 64, as the handheld device is older than Joe Dirt and twice as cantankerous.
来源:https://stackoverflow.com/questions/28074592/why-does-this-attempt-to-update-a-registry-value-fail