C# Windows registry GetValue Error - c#

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.

Related

why can't I no longer compile $ with cmd

I made a code to "translate" paths or texts in general to the Git Bash syntax, at the time I didn't know that I could just put them inside '', in the code I use the $ special character on a couple of strings, compile the code via csc filename.cs on cmd, it gives me the .exe and its all great, today I go make some minor changes on the code and when I run the same code to compile it gives me:
GiTranslator.cs(59,62): error CS1056: Unexpected character '$'
GiTranslator.cs(71,25): error CS1056: Unexpected character '$'
GiTranslator.cs(72,25): error CS1056: Unexpected character '$'
GiTranslator.cs(73,25): error CS1056: Unexpected character '$'
so, why? And what can I do to fix it?
note: the minor changes were literally just some spelling on comments.
edit 1: as asked, the code(it is probably terrible, sorry):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Git_Path_Translator
{
class Program
{
#region Functions
static void actuallyResetColors()
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();
Console.Write(".");
Console.Clear();
}
#endregion
#region Global Variables
static string path;
static bool repetTranslation;
static bool repetAfterExcep;
#endregion
[STAThread] // don't know what it does, but its needed, classic right?
static void Main(string[] args)
{
Console.BackgroundColor = ConsoleColor.DarkCyan;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Title = "Path Translator for Git Bash - by Tom Zamataro"; // just some credit to me, that no one is going to see, classic right?
Console.Clear();
// set up for the API loop
do
{
repetTranslation = false;
path = "";
Console.WriteLine("\n Inform the path you would like to translate to Git Bash syntax:");
Console.Write("\n "); // just for aesthetics, class... sory, no more classic joke tho, right? yes, I've a lot of shit in my head
// set up for the exception handling loop
do
{
repetAfterExcep = false;
try
{
if (path == "")
{
path = Console.ReadLine();
}
#region The Translation
string[] metaChars = new string[] { #"\", " ", "<", ">", "&", ";","*",
"?", "#", ".", "~", "|", "!", "$", "(", ")", "[", "]", "{", "}", "'", "\"" }; // the meta characters that I've to deal with
foreach (string meta in metaChars)
{
// backslash is the special case in this contex
if (meta == #"\") { path = path.Replace(meta, "/"); }
// the rest
else { path = path.Replace(meta, $#"\{meta}"); }
}
path = path.Trim(new char[] { '\'', '"' }); // jusr making sure, ..., what? I didn't say anything
/*
* the fist way I did, yes, much worse, you know alredy, right?
* path = path.Trim().Replace(#"\", "/").Replace(" ", #"\ ").Replace("(", #"\(").Replace(")", #"\)"); // taking of the spaces and putting '\' where its needed
* path = path.Replace("[", #"\[").Replace("]", #"\]").Replace("{", #"\{").Replace("}", #"}]").Trim('"'); // nor sure if
*/
#endregion
Clipboard.SetText(path); // coping it to the user's clipboard
Console.WriteLine
(
$"\n The path was translated to:" +
$"\n\n {path}" +
$"\n\n and it is alredy copied to your clipbord."
); // just a bit more of aestheticness, yeah, ..., go on continue throught the code
}
catch (ArgumentNullException)
{
Console.Clear();
Console.WriteLine("\n Please inform a non-null value so the translation is possible," +
"\n if you would like to finish the solution, press enter:");
Console.Write("\n "); // same thing as before, just for aesthetics
if ((path = Console.ReadLine()) == "")
{
// didn't want to a valid translation
actuallyResetColors(); // Console.ResetColor() isn't all that great on doing its job, so, yeah
Console.Write("\n "); // aesthetic for VS console
Environment.Exit(0);
}
else { repetAfterExcep = true; } // did want to do a valid translation
}
} while (repetAfterExcep); // exception handling loop
Console.Write
(
"\n Type anything and press enter to make another translation,\n" +
" or press enter to finish the solution: "
); // asking for the loop
if (Console.ReadLine() == "")
{
// didn't want to do another translation
actuallyResetColors(); // Console.ResetColor() isn't that great on doing its job, so, yeah
Console.Write("\n "); // aesthetics for VS console
Environment.Exit(0);
}
// did want to do another translation
repetTranslation = true;
Console.Clear();
} while (repetTranslation); // API loop
}
}
}
edit 2: maybe useful information, I can normally run the code on VS, but when I try to compile it via csc filename.exe it gives me that error.
edit 3: so,
well, I don't know what to think or say about that.

Best way StreamReader skipping Null or WhiteSpace line

After searching and trying the different ways I found I either wasn't happy with the way I was doing the code or it didn't work right for me. I'm new at programming so my understanding is limited. Please keep in mind with the answer.
I want to read a .csv file line by line and skipping lines that are blank. With the contents of the lines I want to put into a list of object. I have everything working except for the skipping line part. Also any feedback about improving any parts of my code are all welcome. I like constructive criticism.
public void CardaxCsvFileReader()
{
string cardaxCsvPath = (#"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
try
{
using (System.IO.StreamReader cardaxSR =
new System.IO.StreamReader(System.IO.File.OpenRead(cardaxCsvPath)))
{
string line = "";
string[] value = line.Split(',');
while (!cardaxSR.EndOfStream)
{ // this commented out part is what I would like to work but doesn't seem to work.
line = cardaxSR.ReadLine();//.Skip(1).Where(item => !String.IsNullOrWhiteSpace(item));
value = line.Split(',');
if (line != ",,,,,") // using this as temp to skip the line because the above commented out part doesn't work.
{
CardaxDataObject cardaxCsvTest2 = new CardaxDataObject();
cardaxCsvTest2.EventID = Convert.ToInt32(value[0]);
cardaxCsvTest2.FTItemID = Convert.ToInt32(value[1]);
cardaxCsvTest2.PayrollNumber = Convert.ToInt32(value[2]);
cardaxCsvTest2.EventDateTime = Convert.ToDateTime(value[3]);
cardaxCsvTest2.CardholderFirstName = value[4];
cardaxCsvTest2.CardholderLastName = value[5];
Globals.CardaxQueryResult.Add(cardaxCsvTest2);
}
}
}
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
EDITED
If you are lines are not truly blank and contain commas, you can split with RemoveEmptyEntries option and then check the column count.
while (!cardaxSR.EndOfStream)
{ // this commented out part is what I would like to work but doesn't seem to work.
line = cardaxSR.ReadLine();//.Skip(1).Where(item => !String.IsNullOrWhiteSpace(item));
value = line.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries); // <-- Remove empty columns while splitting. It has a side-effect: Any record with just a single blank column will also get discarded by the if that follows.
if (value.length < 6)
continue;
CardaxDataObject cardaxCsvTest2 = new CardaxDataObject();
cardaxCsvTest2.EventID = Convert.ToInt32(value[0]);
cardaxCsvTest2.FTItemID = Convert.ToInt32(value[1]);
cardaxCsvTest2.PayrollNumber = Convert.ToInt32(value[2]);
cardaxCsvTest2.EventDateTime = Convert.ToDateTime(value[3]);
cardaxCsvTest2.CardholderFirstName = value[4];
cardaxCsvTest2.CardholderLastName = value[5];
Globals.CardaxQueryResult.Add(cardaxCsvTest2);
}
Another improvement feedback I have: When you catch an exception, it's a good practice to log the exception in addition to your custom error line. A custom error line might be good for say website users, but as a developer running some service you will appreciate the actual exception stack trace. It will help you debug a bug easier.
catch (Exception ex)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\".\r\n Exception: {1}", cardaxCsvPath, ex.ToString());
}
Just check if value.Length == 6, this way it'll skip lines which don't contain enough data for your columns
Use a dedicated CSV parser, such as the EasyCSV class available here*:
https://github.com/jcoehoorn/EasyCSV
public void CardaxCsvFileReader()
{
try
{
string cardaxCsvPath = (#"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
Globals.CardaxQueryResult =
EasyCSV.FromFile(cardaxCsvPath)
.Where(r => r.Any(c => !string.IsNullOrEmpty(c)))
.Select(r => CardaxDataObject() {
cardaxCsvTest2.EventID = int.Parse(r[0]),
cardaxCsvTest2.FTItemID = int.Parse(r[1]),
cardaxCsvTest2.PayrollNumber = int.Parse(r[2]),
cardaxCsvTest2.EventDateTime = DateTinme.Parse(r[3]),
cardaxCsvTest2.CardholderFirstName = r[4],
cardaxCsvTest2.CardholderLastName = r[5]
}).ToList();
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
}
I also recommend re-thinking how you structure this. The code below is better practice:
public IEnumerable<CardaxDataObject> ReadCardaxCsvFile(string filename)
{
//no try block at this level. Catch that in the method that calls this method
return EasyCSV.FromFile(cardaxCsvPath)
.Where(r => r.Any(c => !string.IsNullOrEmpty(c)))
// You may want to put a try/catch inside the `Select()` projection, though.
// It would allow you continue if you fail to parse an individual record
.Select(r => CardaxDataObject() {
cardaxCsvTest2.EventID = int.Parse(r[0]),
cardaxCsvTest2.FTItemID = int.Parse(r[1]),
cardaxCsvTest2.PayrollNumber = int.Parse(r[2]),
cardaxCsvTest2.EventDateTime = DateTinme.Parse(r[3]),
cardaxCsvTest2.CardholderFirstName = r[4],
cardaxCsvTest2.CardholderLastName = r[5]
});
}
Suddenly the method boils down to one statement (albeit a very long statement). Code like this is better, because it's more powerful, for three reasons: it's not limited to using just the one input file, it's not limited to only sending it's output to the one location, and it's not limited to only one way to handle errors. You'd call it like this:
try
{
string cardaxCsvPath = (#"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
Globals.CardaxQueryResult = ReadCardaxCsvFile(cardaxCsvPath).ToList();
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
or like this:
try
{
string cardaxCsvPath = (#"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
foreach (var result in ReadCardaxCsvFile(cardaxCsvPath))
{
Globals.CardaxQueryResult.Add(result);
}
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
I also recommend against using a Globalsclass like this. Find a more meaningful object with which you can associate this data.
* Disclaimer: I am the author of that parser

How to read value of a registry key c#

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

How to use registry to refill a text box

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

Printing entire tree contents of LocalMachine

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

Categories

Resources