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
{}
}
}
Related
I have a Project and i am trying to run the installer on a new pc to test my WPF application, but the registry key is not automatically created. I have tried adding it manually but i don't know why it is not working, i am sure i am not adding the key the right way. Also i am confused since it is a new PC how do i add something that will automatically create a path?
The one that i am creating is something like this in the Image:
[VS Image][1]
HKLM -- do you have Admin right? really privileged rights?
How to test that you have enough right to write to HKLM (just call OpenSubKey):
public bool CanSetRegKeyValue(string path, string valueName, RegistryKey registry = null)
{
bool result = true;
try
{
RegistryKey registryKey = null;
if (registry == null)
{
registryKey = Registry.LocalMachine;
}
using (RegistryKey key = registryKey.OpenSubKey(path, true))
{
result = key != null;
}
}
catch (NullReferenceException)
{
result = false;
}
catch (SecurityException)
{
result = false;
}
return result;
}
and usage sample, which checking write ability to Key DefaultLevel under node HKLM\SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers:
bool result = CanSetRegKeyValue("SOFTWARE\\Policies\\Microsoft\\Windows\\safer\\codeidentifiers\\", "DefaultLevel");
At start up of my application I am trying to see if the user has a specific version of a software installed, specifically the MySQL connector, all using c#. In the registry, the MySQL contains a version entry. So what I am trying to accomplish is this.
My app starts up. Somewhere in the start up code I need to do the following things in order. Check to see if the user has the MySQL connector installed, which is located at...
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\MySQL AB\MySQL Connector/Net
If the user has the connector installed, I wanted to check what version they have, which is stored as Name = "Version" and Data = x.x.x (Picture below)
Now if the user has a specific version installed, then I will execute other code, which is where I can take from.
What would be the best way of going about this?
EDIT: Below is the code I currently have and I am getting an error on line 19 (It is commented). My error says "error CS1001: Identifier Expected" I wasnt able to figure out what that means. Any help?
using System;
using Microsoft.Win32;
using System.Data;
public class regTest
{
public static void Main()
{
try
{
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\MySQL AB\\MySQL Connector\\Net");
if (key != null)
{
Object o = key.GetValue("Version");
if (o != null)
{
Version version = new Version(o as String); //"as" because it's REG_SZ...otherwise ToString() might be safe(r)
Version broken = new Version("6.7.4");
if (version.Equals.(broken)) //This is where the error is occuring
{
DataSet dataSet = ConfigurationManager.GetSection("system.data") as ystem.Data.DataSet;
DataView vi = dataSet.Tables[0].DefaultView;
vi.Sort = "Name";
if (vi.Find("MySql") == -1)
{
dataSet.Tables[0].Rows.Add("MySql"
, "MySql.Data.MySqlClient"
, "MySql.Data.MySqlClient"
,
typeof(MySql.Data.MySqlClient.MySqlClientFactory).AssemblyQualifiedName);
}
}
}
}
}
catch (Exception ex) //just for demonstration...it's always best to handle specific exceptions
{
//react appropriately
}
}
}
You need to first add using Microsoft.Win32; to your code page.
Then you can begin to use the Registry classes:
try
{
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\MySQL AB\\MySQL Connector\\Net"))
{
if (key != null)
{
Object o = key.GetValue("Version");
if (o != null)
{
Version version = new Version(o as String); //"as" because it's REG_SZ...otherwise ToString() might be safe(r)
//do what you like with version
}
}
}
}
catch (Exception ex) //just for demonstration...it's always best to handle specific exceptions
{
//react appropriately
}
BEWARE: unless you have administrator access, you are unlikely to be able to do much in LOCAL_MACHINE. Sometimes even reading values can be a suspect operation without admin rights.
#DonBoitnott have a good code, but require admin rights. I use this (only need Read Rights)
try
{
var subKey = "Software\\Wow6432Node\\MySQL AB\\MySQL Connector\\Net";
using (var key = Registry.LocalMachine.OpenSubKey(subKey, false)) // False is important!
{
var s = key?.GetValue("Version") as string;
if (!string.IsNullOrWhiteSpace(s))
{
var version = new Version(s);
}
}
}
catch (Exception ex) //just for demonstration...it's always best to handle specific exceptions
{
//react appropriately
}
Change:
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\MySQL AB\\MySQL Connector\\Net"))
To:
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\Wow6432Node\MySQL AB\MySQL Connector\Net"))
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());
}
}
}
}
I have to insert this to the registry:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect]
"AutoRun"="d:\\MyFolder\\MyProgram.exe"
How would I do this in C#?
Something like this:
string name = #"SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(name, true))
{
if (key == null)
{
// Whatever you want to do if the key isn't found
}
else
{
key.SetValue("AutoRun", #"d:\MyFolder\MyProgram.exe");
}
}
If you use CreateSubKey instead of OpenSubKey, that will create it if it doesn't already exist (or open it for write otherwise) - but I suspect that in most cases, if the key doesn't exist then that indicates the rest of the system isn't in an appropriate state for your app.
You could use the Registry class:
var path = #"Software\Microsoft\Windows CE Services\AutoStartOnConnect";
using (var key = Registry.LocalMachine.OpenSubKey(path, true))
{
if (key != null)
{
key.SetValue("AutoRun", #"d:\MyFolder\MyProgram.exe");
}
}
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 .