I'm trying to develop a c# program to print the entire tree of LocalMachine to the console. So far I've just been able to get the subkeys of HKEY_LOCAL_MACHINE, but nothing deeper than that. I'm relatively sure I need to use some kind of recursion here to get all the contents of subkeys and their subkeys, and so on. I'm just not sure how to go about it. Here's what I've got as of now:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
namespace PrintLocalMachine
{
class PrintLocalMachine
{
static void Main(string[] args)
{
Console.Out.WriteLine(Registry.LocalMachine.Name);
string[] subkeynames = Registry.LocalMachine.GetSubKeyNames();
foreach (string subkey in subkeynames)
{
try
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey(subkey);
Console.Out.WriteLine(rk.Name);
string[] subkeynames2 = rk.GetSubKeyNames();
foreach (string s in subkeynames2)
{
recurse(s, rk);
}
}
catch (Exception e) { }
}
}
private static void recurse(string sub, RegistryKey rk)
{
RegistryKey rk2 = Registry.LocalMachine.OpenSubKey(sub);
Console.Out.WriteLine(rk2.Name);
string[] subkeynames3 = rk.GetSubKeyNames();
foreach(string s2 in subkeynames3){
recurse(s2, rk2);
}
}
}
}
Could someone explain how I should go about this? I really just need to be pointed in the right direction, I've just hit a wall with this.
EDIT: I changed a bit and updated the code; the updated code is hanging on HKEY_CURRENT_MACHINE\SAM, just printing it over and over until StackOverflowException
recurse() is not recursion unless it calls itself.
Move all your code from main to recurse() and call recurse() from main.
You might also want to close opened subkeys.
You are right. This kind of problem where you have a structure inside a structure can be solved through recursion. What you need to do is write a recursive function i.e. a function that calls itself until a certain condition satisfies. In this case that condition would be that if a Registry Key has at least one child we need to go inside that Registry Key and we will continue to do so until we reach a leaf node i.e. a Registry Key which has no more children.
private static void Main(string[] args)
{
string[] subkeynames = Registry.LocalMachine.GetSubKeyNames();
Console.Out.WriteLine(Registry.LocalMachine.Name);
foreach (string subkey in subkeynames)
{
try
{
//this might raise a security exception
RegistryKey rk = Registry.LocalMachine.OpenSubKey(subkey);
recurse(rk);
rk.Close();
}
catch (Exception e)
{
Console.Write("Couldnt access key : " + subkey + "\n " + e.ToString());
}
}
Console.ReadKey();
}
private static void recurse(RegistryKey rk)
{
Console.WriteLine(rk.Name);
string[] subkeys = rk.GetSubKeyNames();
if (null != subkeys && subkeys.Count() > 0)
{
foreach (var subkey in subkeys)
{
try
{
//this might raise a security exception
RegistryKey key = rk.OpenSubKey(subkey);
recurse(key);
}
catch (Exception e)
{
Console.Write("Couldnt access key : " + subkey + "\n " + e.ToString());
}
}
}
}
Related
I am using the registry to store some (20+) data values like window location & size to start with. I am curious if you should preload all of the keys from the registry instead of live query them when a GET or SET is called on a variable. Are there risks to querying or writing data to the registry frequently?
Code example:
internal int MainWindowHeight
{
get
{
try
{
using (RegistryKey mykey = Registry.CurrentUser.OpenSubKey("xxxxx"))
{
return Convert.ToInt32(mykey.GetValue("xxxx"));
}
}
catch
{ return 0; }
}
set
{
try
{
using (RegistryKey mykey = Registry.CurrentUser.OpenSubKey("xxxxx", true))
{
mykey.SetValue("xxxx", value, RegistryValueKind.DWord);
}
}
catch
{}
}
}
I'd like to preface this by highlighting that I am fairly new to C#.
I'm trying to make a program to find and edit a registry value in order to disable CPU core parking using this method: Registry Edit
The issue is that I know the start of the key:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Power\PowerSettings\
But not the Next part but I know the segment after that:
0cc5b647-c1df-4637-891a-dec35c318583
So if it looks like this:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Power\PowerSettings\<UNKNOWN>\0cc5b647-c1df-4637-891a-dec35c318583
How do I find the using Registry and Registrykey? I tried looping through all subkeys and I just get an exception because all I get back is null.
Any suggestions appreciated.
You can use recursion for finding SubKey.
private RegistryKey SearchSubKey(RegistryKey Key,String KeyName)
{
foreach (String subKey in Key.GetSubKeyNames())
{
RegistryKey key1 = Key.OpenSubKey( subKey);
if (subKey.ToUpper() == KeyName.ToUpper())
return key1;
else
{
RegistryKey mReturn = SearchSubKey(key1, KeyName);
if (mReturn != null)
return mReturn;
}
}
return null;
}
Call this function as
RegistryKey key = Registry.LocalMachine.OpenSubKey(#"SYSTEM\ControlSet001\Control\Power\PowerSettings\");
RegistryKey SubKey = SearchSubKey(key, "0cc5b647-c1df-4637-891a-dec35c318583");
This function search through all sub keys in main key recursively. If you want to search up to particular level then you have to add that logic in function.
I guess you forgot to mention the Registry key name in a proper fashion. Here is the piece of code which brings out the output :
class Program
{
static void Main(string[] args)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion");
foreach (var v in key.GetSubKeyNames())
{
RegistryKey key1 = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\" + v);
foreach ( var v1 in key1.GetSubKeyNames())
{
if (v1 == "{00EC8ABC-3C5A-40F8-A8CB-E7DCD5ABFA05}")
Console.WriteLine(key1);
}
}
}
}
Please let me know if this works.
How can i refill a textbox with it's previous text after the program was stopped using registry.
I read multiple articles like:
Stack OverFlow1
Stack OverFlow2
Code Project1
Code Project2
So far i have nothing because nothing is working out, all i get are errors D:
public string Read(string KeyName)
{
RegistryKey rk = baseRegistryKey ;
RegistryKey sk1 = rk.OpenSubKey(subKey);
if ( sk1 == null )
return null;
else
{
try
{
return (string)sk1.GetValue(KeyName.ToUpper());
}
catch (Exception ex)
{
}
}
}
says that baseRegistryKey and subKey don't exist. And it says that RegistryKey doesn't exist. How do i fix?
I've had the same problem a couple of days ago, don't use those sights, they are all bad.
there are several things wrong with your code:
baseRegistryKey and subKey need to be set to some sort of a parameter.
if RegisterKey isn't working than you probably didn't do using Microsoft.Win32
The code i used to solve this was:
public WindowsConsoleForm1();
try
{
InitializeComponent();
textBox1.Text = Application.UserAppDataRegistry.GetValue("example").ToString();
}
catch { }
and then where ever you have ex: textbox1.text = Path.GetDirectoryName(saveFileDialoge1.FileName);, under it you post Application.UserAppDataRegistry.SetValue("example", textbox1.text);
I have a program which outputs the various registry values from "Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedMRU".
However the program outputs an error on Cannot implicity convert type'object' to 'string' at the s variable at the GetValue portion or the program! And the program outputs an error of "Cannot access a closed registry key too".
Can someone please give advise on the codes? Thanks!
The Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
namespace RegKeys
{
class ConsoleApplication1
{
static void Main(string[] args)
{
try
{
RegistryKey rk = Registry.CurrentUser;
rk = rk.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedMRU", false);
PrintKeys(rk);
}
catch (Exception MyError)
{
Console.WriteLine("An error has occurred: " + MyError.Message);
}
}
static void PrintKeys(RegistryKey rk)
{
if (rk == null)
{
Console.WriteLine("No specified registry key!");
return;
}
String[] names = rk.GetValueNames();
Console.WriteLine("Subkeys of " + rk.Name);
Console.WriteLine("-----------------------------------------------");
foreach (String s in names)
{
try
{
if (s == "MRUList")
{
continue;
}
else
{
String val = rk.GetValue(s);
Console.WriteLine(s + " Contains the value of : " + val);
}
rk.Close();
}
catch (Exception MyError)
{
Console.WriteLine("An error has occurred: " + MyError.Message);
}
Console.WriteLine("-----------------------------------------------");
rk.Close();
}
}
}
}
As well as Matti's advice, it's not clear why you're looking through all the subvalues. Why not just get the one you want? Something like this:
using System;
using Microsoft.Win32;
class Test
{
static void Main()
{
using (var key = Registry.CurrentUser.OpenSubKey
(#"Software\Microsoft\Windows\CurrentVersion\" +
#"Explorer\ComDlg32\LastVisitedMRU", false))
{
string value = (string) key.GetValue("MRUList");
Console.WriteLine(value);
}
}
}
(Note the using statement to make sure you always close the registry key.)
You might also want to put in some tests to make sure the key and value exist, of course.
Here's some advice on the codes:
GetValue returns an object, not a string. You need to either cast it to string, or call ToString on it (always use the former if you know it's actually a string).
If you are sure that the expected result is string, just typecast it.
String val = (String) rk.GetValue(s);
//or
String val = rk.GetValue(s) as String;
I believe GetValue is expecting a lowercase 's' string, which is a primitive, as opposed to an uppercase 'S' String which is an object. Try this:
String val = rk.GetValue(s.toString());
Or in general replace your usage of 'string' with 'String' except where 'String' is appropriate.
Use a Convert.ToString() method to convert the object to string. You can also use .ToString() but it may result in a null reference exception if the key does not exist.
Secondly, on the exception you get with the closed key. Change your for each loop and move the rk.Close() call outside the loop.
foreach (String s in names)
{
try
{
if (s == "MRUList")
{
continue;
}
else
{
String val = rk.GetValue(s);
Console.WriteLine(s + " Contains the value of : " + val);
}
}
catch (Exception MyError)
{
Console.WriteLine("An error has occurred: " + MyError.Message);
}
Console.WriteLine("-----------------------------------------------");
}
rk.Close();
I'm using a struct and trying to do this. I kept getting objects returned when I wanted strings and when I did .ToString() the whole program just froze up. I realized that the properties I wanted to retrieve are also fields. It took me all day to figure it out:
string value = myObjectInstance.GetType().
GetField("myFieldName").GetValue(newEntry) as string;
That worked perfectly for me.
I have a web application which is importing DLLs from the bin folder.
const string dllpath = "Utility.dll";
[DllImport(dllpath)]
Now what I want to do is first import the DLLs from a folder not in the current project but at some different location.
The path of that folder is stored in a registry key.
How should I do this?
Edit:
Why can't I work this out???
public partial class Reports1 : System.Web.UI.Page
{
RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(#"Software\xyz");
string pathName = (string)registryKey.GetValue("BinDir");
const string dllpath = pathName;
[DllImport(dllpath)]
public static extern bool GetErrorString(uint lookupCode, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder buf, uint bufSize);
protected void Page_Load(object sender, EventArgs e)
{
string pathName = (string)registryKey.GetValue("BinDir"); is not working here, but is working in the pageload event...
But if I do this DLL import won't work...
How can I fix this?
Reading the registry is pretty straightforward. The Microsoft.Win32 namespace has a Registry static class. To read a key from the HKLM node, the code is:
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("Software\\NodeName")
If the node is HKCU, you can replace LocalMachine with CurrentUser.
Once you have the RegistryKey object, use GetValue to get the value from the registry. Continuing Using the example above, getting the pathName registry value would be:
string pathName = (string) registryKey.GetValue("pathName");
And don't forget to close the RegistryKey object when you are done with it (or put the statement to get the value into a Using block).
Updates
I see a couple of things. First, I would change pathName to be a static property defined as:
Private static string PathName
{
get
{
using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(#"Software\Copium"))
{
return (string)registryKey.GetValue("BinDir");
}
}
}
The two issues were:
The RegistryKey reference will keep the registry open. Using that as a static variable in the class will cause issues on the computer.
Registry path's use forward slashes, not back slashes.
None of these answers worked for me. This is what I used:
static void Main()
{
const string dotNetFourPath = "Software\\Microsoft";//note backslash
using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(dotNetFourPath))
{
Console.WriteLine(registryKey.SubKeyCount);//registry is not null
foreach (var VARIABLE in registryKey.GetSubKeyNames())
{
Console.WriteLine(VARIABLE);//here I can see I have many keys
//no need to switch to x64 as suggested on other posts
}
}
}
All these answers may lead to problems running on 64bit OS - which is usual nowadays.
In my situation, i compile to 'Any CPU' target and the software is working fine when i install on 64bit OS.
But my unit tests are running into problems - obviously they are executed in 32bit mode.
In this case not the HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\MySoftware is searched but HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\MyCompany\MySoftware but there are no entries!
In this situation we have to specify the start point of our search using
RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)
In total we can use.
string configurationDirectory = string.Empty;
using (RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (RegistryKey registryKey = hklm.OpenSubKey(#"SOFTWARE\MyCompany\MySoftware"))
{
if (registryKey != null)
{
configurationDirectory = (string)registryKey.GetValue("ConfigurationDirectory");
}
}
}
try
{
RegistryKey regKey = Registry.LocalMachine;
regKey = regKey.OpenSubKey(#"Software\Application\");
if (regKey != null)
{
return regKey.GetValue("KEY NAME").ToString();
}
else
{
return null;
}
}
catch (Exception ex)
{
return null;
}
You can use this:
/// <summary>
/// To read a registry key.
/// input: KeyName (string)
/// output: value (string)
/// </summary>
public string Read(string KeyName)
{
// Opening the registry key
RegistryKey rk = baseRegistryKey ;
// Open a subKey as read-only
RegistryKey sk1 = rk.OpenSubKey(subKey);
// If the RegistrySubKey doesn't exist -> (null)
if ( sk1 == null )
{
return null;
}
else
{
try
{
// If the RegistryKey exists I get its value
// or null is returned.
return (string)sk1.GetValue(KeyName.ToUpper());
}
catch (Exception e)
{
// AAAAAAAAAAARGH, an error!
ShowErrorMessage(e, "Reading registry " + KeyName.ToUpper());
return null;
}
}
}
For more information visit this web site .