locked
Counld anybody help me delete registry value Recursively? RRS feed

  • Question

  • I gonna post my code first:

    public partial class MainForm: Form {
            private List<string> _DeleteResult = new List<string>();    //Store the deleted keys and values.
            public MainForm() {
                InitializeComponent();
                labSearch.Click += (s, e) => { txtSearch.Focus(); };
            }
    
            private void Form1_Load(object sender, EventArgs e) {
                combox_path.SelectedIndex = 0;  //select the first as default.
                this.ActiveControl = txtSearch; //Just set the input textbox as Active control.
            }
    
            void RecursiveRegedit(RegistryKey regBoot) {
                if(regBoot == null) throw new ArgumentNullException("Null Item!");
                string[] vals = regBoot.GetValueNames();
                foreach(var v in vals) {
                    string s = regBoot.GetValue(v).ToString();
                    //if the value start with "C:","D:" and so on,and it contains search value such as "ArcGIS".
                    if(s.StartsWith(combox_path.Text.Trim(), StringComparison.CurrentCultureIgnoreCase) && s.ToLower().Contains(txtSearch.Text.ToLower().Trim())) {
                        _DeleteResult.Add(v + "->" + s);    //Add the key and value.
                        regBoot.DeleteValue(v, false);
                    }
                }
                if(regBoot.SubKeyCount <= 0)
                    return; //Exit.
                else {
                    string[] subs = regBoot.GetSubKeyNames();
                    foreach(string s in subs) {
                        RecursiveRegedit(regBoot.OpenSubKey(s,RegistryKeyPermissionCheck.ReadWriteSubTree,RegistryRights.ChangePermissions));
                    }
                }
                regBoot.Close();    //Close.
            }
    
            private void btn_Click(object sender, EventArgs e) {
                if(MessageBox.Show("Sure to delete?", "Delete registry values", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning) != DialogResult.Yes)
                    return;
                if(!chebox_current_user.Checked && !chebox_local_machine.Checked) {
                    MessageBox.Show("Please select \"Item to delete.\"!");
                    return;
                }
                if(chebox_hasESRI.Checked) {    //if ESRI item exist,just browse the current item(esri).
                    if(chebox_current_user.Checked)
                        RecursiveRegedit(Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("ESRI", true));
                    if(chebox_local_machine.Checked)
                        RecursiveRegedit(Registry.LocalMachine.OpenSubKey("SOFTWARE").OpenSubKey("ESRI", true));
                }
                else {
                    if(chebox_current_user.Checked) //if not ESRI item exist,start from "Software".
                        RecursiveRegedit(Registry.CurrentUser.OpenSubKey("SOFTWARE", true));
                    if(chebox_local_machine.Checked)
                        RecursiveRegedit(Registry.LocalMachine.OpenSubKey("SOFTWARE", true));
                }
    
                MessageBox.Show("Done!Total delete\t" + _DeleteResult.Count + "\t item.");
                foreach(var item in _DeleteResult) {
                    lbox.Items.Add(item);
                }
            }
        }

    Description:

    What I'm gonna to do is simple-"Delete the registry value beyond  "HKEY_LOCAL_MACHINE\SOFTWARE" and "HKEY_CURRENT_USER\Software",and the registry value must start with one drive symbol such as "C:","D:" and must contains my input value,such as "ArcGIS".

    and my running interface like this:

    Running

    and when I run my code, It always throw exception :

    System.UnauthorizedAccessException was unhandled
      HResult=-2147024891
      Message=Attempted to perform an unauthorized operation.
      Source=mscorlib
      StackTrace:
           at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
           at Microsoft.Win32.RegistryKey.InternalValueCount()
           at Microsoft.Win32.RegistryKey.GetValueNames()
           at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 27
           at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 41
           at DeleteRegedit.MainForm.btn_Click(Object sender, EventArgs e) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 62
           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 DeleteRegedit.Program.Main() in E:\Test\DeleteRegedit\DeleteRegedit\Program.cs:line 15
           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: 


    Thanks very much if you can help me....
    Saturday, September 28, 2013 9:25 AM

Answers

  • In addition to what Michael has posted:

    Do not delete in a recursion. You may use the recursion to find your keys, but then stuff them into a list. And delete the keys from that list.

    This gives you the advantage that you can present (debug) a list of keys before deleting and request a confirmation before doing so in your UI.

    Saturday, September 28, 2013 4:49 PM

All replies


  • System.UnauthorizedAccessException was unhandled
      HResult=-2147024891
      Message=Attempted to perform an unauthorized operation.
      Source=mscorlib
      StackTrace:
           at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
           at Microsoft.Win32.RegistryKey.InternalValueCount()
           at Microsoft.Win32.RegistryKey.GetValueNames()
           at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 27
           at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 41
           at DeleteRegedit.MainForm.btn_Click(Object sender, EventArgs e) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 62
           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 DeleteRegedit.Program.Main() in E:\Test\DeleteRegedit\DeleteRegedit\Program.cs:line 15
           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: 


    Thanks very much if you can help me....

    do you have enough rights to perform this operation? does the user used by application has it?

    You need write permissions to the registry in order to delete entries.


    Please remember to 'Mark as Answer' the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Saturday, September 28, 2013 1:11 PM
  • thanks for answering my question,yeah, it did so.

    when the user run this app., it report as:

    See the end of this message for details on invoking 
    just-in-time (JIT) debugging instead of this dialog box.

    ************** Exception Text **************
    System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
       at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
       at Microsoft.Win32.RegistryKey.InternalValueCount()
       at Microsoft.Win32.RegistryKey.GetValueNames()
       at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 26
       at DeleteRegedit.MainForm.RecursiveRegedit(RegistryKey regBoot) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 46
       at DeleteRegedit.MainForm.btn_Click(Object sender, EventArgs e) in E:\Test\DeleteRegedit\DeleteRegedit\MainForm.cs:line 67
       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.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


    ************** Loaded Assemblies **************
    mscorlib
        Assembly Version: 4.0.0.0
        Win32 Version: 4.0.30319.17929 built by: FX45RTMREL
        CodeBase: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
    ----------------------------------------
    DeleteRegedit
        Assembly Version: 1.0.0.0
        Win32 Version: 1.0.0.0
        CodeBase: file:///E:/Test/DeleteRegedit/DeleteRegedit/bin/Release/DeleteRegedit.exe
    ----------------------------------------
    System.Windows.Forms
        Assembly Version: 4.0.0.0
        Win32 Version: 4.0.30319.17929 built by: FX45RTMREL
        CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
    ----------------------------------------
    System.Drawing
        Assembly Version: 4.0.0.0
        Win32 Version: 4.0.30319.17929 built by: FX45RTMREL
        CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
    ----------------------------------------
    System
        Assembly Version: 4.0.0.0
        Win32 Version: 4.0.30319.17929 built by: FX45RTMREL
        CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
    ----------------------------------------

    ************** JIT Debugging **************
    To enable just-in-time (JIT) debugging, the .config file for this
    application or computer (machine.config) must have the
    jitDebugging value set in the system.windows.forms section.
    The application must also be compiled with debugging
    enabled.

    For example:

    <configuration>
        <system.windows.forms jitDebugging="true" />
    </configuration>

    When JIT debugging is enabled, any unhandled exception
    will be sent to the JIT debugger registered on the computer
    rather than be handled by this dialog box.

    I have search all day for this issue but in vain,I know that this code does not have much right to operate this.But what I search about does not help.

    I did something like this,

    solu_01,created a "app.manifest" file and changed the level="requireAdministrator",even delete some code like "xmlns="urn:schemas-microsoft-com:asm.v3",

    solu_02,seen nothing work, I turned off  the UAC of win7,

    solu_03,swith code between "RecursiveRegedit(regBoot.OpenSubKey(s,RegistryKeyPermissionCheck.ReadWriteSubTree,RegistryRights.ChangePermissions));"

    and "RecursiveRegedit(regBoot.OpenSubKey(s,true))",

    many people just post some code like,

    use the override method "OpenSubKey("SOFTWARE", true)" instead of "OpenSubKey("SOFTWARE")" or use the override method "DeleteValue(v, false);" rather then "DeleteValue(v);". or create a "app.manifest" file and change the level.

    but for me, It still throw the same exception or exception like "Attempted to perform an unauthorized operation".

    do you have some ideal about this.


    Saturday, September 28, 2013 2:40 PM
  • You cannot delete haphazardly from HKLM\Software or HKCU\Software.  More importantly if you were to try to recursively delete from every key based strictly on a value you will effectively mangle Windows such that it will likely fail to run.  Note that the first part of your code where you are searching ESRI is ok but the second part where you just open Software needs to go.  For example if the end user entered C:\ that would wipe the registry of any paths starting at C:\ which would include pretty much all installation and COM paths.  Your system wouldn't run anymore.  You need to be very explicit about the subkeys you will search.

    You can delete a specific subkey from under HKLM\Software provided you have admin privileges (elevated if you're running UAC) and the ACL allows you to delete it.  You need to exactly identify the subkey that you want to clean out and it should only be for your application/products.  In general it should be of the form HKLM\Software\<company>\<product>.  What you do inside your own product subkey is up to you but do not delete outside of that.  Once you've identified the exact key to clean up you can then either delete the entire key or recursively delete subkeys or values depending upon your requirement.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    • Proposed as answer by Stefan Hoffmann Saturday, September 28, 2013 4:46 PM
    Saturday, September 28, 2013 4:17 PM
  • In addition to what Michael has posted:

    Do not delete in a recursion. You may use the recursion to find your keys, but then stuff them into a list. And delete the keys from that list.

    This gives you the advantage that you can present (debug) a list of keys before deleting and request a confirmation before doing so in your UI.

    Saturday, September 28, 2013 4:49 PM
  • Your process has to be elevated to touch HKEY_LOCAL_MACHINE at all.  Are you asking for elevation in your manifest?  In addition, some of the keys created by Windows are owned by the LOCAL_SYSTEM account.  You would have to take ownership before you could delete it.

    Tim Roberts, VC++ MVP Providenza & Boekelheide, Inc.

    Sunday, September 29, 2013 5:21 AM
  • Thanks for answering,I've searched something about UAC(uer account control),I know that if I turn off the UAC,the window would not notice me as I change some stuff,there are 4 levels in win7,you know that.

    The reason why I want to scan starting with "Software" is that, When some one delete the ESRI item, it relate to a software called "ArcGIS", I've help some one uninstall the software,during that, I must delete many registry value,so I have to delete the relation registry value cleanly.

    I've thount about recuisively collect rather than delete them directly.

    So could you launch any solution? According to what you say,now that I do not have much permission to delete them,I just want to skip the privileges and continue the next, but it seems that it is impossible. I've tried reading,just reading starting with "Software", It throw SecurityException. Then I do not know what to do.

    Sunday, September 29, 2013 5:47 AM
  • Thanks, it seems that I have to catch and ignore the exception...
    Sunday, September 29, 2013 9:39 AM