简体   繁体   中英

Why does this Attempt to Update a Registry Value Fail?

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?

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);

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM