Accessing a Registry Key is Failing from .Net Application - c#

I am trying to access a registry key in LocalMachine. The code works on my machine, but does not work on my friend's. I have looked at his registry and the key is in the same place as mine.
I tried to put try{} catch{} blocks around OpenBaseKey to see if I can see which exception is being thrown, and none of the exceptions are being caught (Makes me think that it doesn't get past OpenBaseKey.
So, what is happening on my friend's machine, the application will run until my MessageBox.Show("Getting Registry Key") and then crash. I have included a screen shot of the error box.
What could be causing this?
string path = string.Empty;
const string hfss_key_name = #"SOFTWARE\Ansoft\HFSS\2014.0\Desktop";
const string hfss_value = "LibraryDirectory";
MessageBox.Show("Getting Registry Key");
RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
localKey = localKey.OpenSubKey(hfss_key_name);
if(localKey != null)
{
path = localKey.GetValue(hfss_value).ToString();
path += #"\HFSS\userlib\";
}
Error Window:
I found the issue, I had the wrong hfss_value. For some reason his and my value are different for that LibraryDirectory. Thanks for all the help.

As it has been pointed out you need to catch the exception to determine why there is a problem. Otherwise, your application can crash exactly as you experience it.
But even without any details about the exception with some code inspection it is perhaps possible to reveal the source of the exception.
Unless you have some weird security settings reading from the registry should be possible and you are careful to check for existence of the key. However, the call to GetValue will return null if the value is missing and calling ToString on null will throw a NullReferenceException. The next line of code should not throw an exception even if path is null.
So changing this code
path = localKey.GetValue(hfss_value).ToString();
path += #"\HFSS\userlib\";
into this code
var value = localKey.GetValue(hffs_value);
if (value != null)
path = value + #"\HFSS\userlib\";
should fix the problem if I am not mistaken.

You probably don't have permissions to get to the key; it is crashing because you're not catching exception thrown.
Change your code to catch the exception and it should help you figure it out:
string path = string.Empty;
const string hfss_key_name = #"SOFTWARE\Ansoft\HFSS\2014.0\Desktop";
const string hfss_value = "LibraryDirectory";
MessageBox.Show("Getting Registry Key");
try
{
RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
localKey = localKey.OpenSubKey(hfss_key_name);
if (localKey != null)
{
path = localKey.GetValue(hfss_value).ToString();
path += #"\HFSS\userlib\";
}
}
catch (SecurityException secex)
{
MessageBox.Show("SecurityException: " + secex);
}
catch (UnauthorizedAccessException uex)
{
MessageBox.Show("UnauthorizedAccessException: " + uex);
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex);
}

Make sure you are administrator on your friends machine. LocalMachine generally needs admin privileges. you might check out http://msdn.microsoft.com/en-us/library/windows/desktop/ms724878(v=vs.85).aspx

If you run your app with administrator privileges (right mouse button -> Run as administrator) and it works, it's a permission problem.
If it still crashes, most likely it's because you have a 64 bit Windows, while he has a 32 bit Windows or vice versa.

Related

program fails to get RegistryKey on particular Win10 box

I have a small subroutine to check for the existence of a required server program, as follows:
private bool IsProgramInstalled(string programDisplayName)
{
string logstr = string.Format("Checking install status of {0}....", programDisplayName);
RegistryKey rk = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Bridge Club Utilities");
foreach (string s in rk.GetSubKeyNames())
{
Console.WriteLine(s);
if (s != null)
{
if (s.Equals(programDisplayName))
{
AppendToLog(logstr + " INSTALLED");
return true;
}
}
}
AppendToLog(logstr + " NOT INSTALLED", Color.Red);
return false;
}
I have installed the program containing the above subroutine on many Windows boxes with no problems, but one customer receives an 'Unhandled Exception' error on program startup, as shown below:
When I loaded VS2022 on the customer's machine and ran it in debug mode, the exception appears on the line that sets RegistryKey rk, as shown below:
So I thought this user had maybe installed the required server program (BridgeComposer) in the wrong place, or the registry was screwed up somehow, or there was a permissions issue. I tried running my app in 'administrative mode', but this did not solve the problem.
Next, I tried to see if the user's PC had the same registry entries as my PC, and it appears that they do. If I manually navigate to 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\RegisteredApplications' on both machines, I see the same entry for 'BridgeComposer' as shown below:
Clearly I'm doing something wrong/stupid, but I have no clue what it is. Any pointers/clues would be appreciated.
Most likely your program is running as 32-bit on a 64-bit computer and is therefore searching in HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node.
There are a number of ways one can approach this:
Use Registry.OpenBaseKey and specify the desired Registry View.
Compile for AnyCPU, but uncheck Prefer 32-bit (Project => <project name> Properties... => Build => Uncheck Prefer 32-bit)
Compile for 64-bit
Option 1:
Note: The following is untested, but should work - it's a slight modification of the code in your OP.
private bool IsProgramInstalled(string programDisplayName, RegistryView regView = RegistryView.Registry64)
{
string logstr = string.Format("Checking install status of {0}....", programDisplayName);
using (RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView))
{
if (localKey != null)
{
using (RegistryKey rk = localKey.OpenSubKey(#"SOFTWARE\Bridge Club Utilities"))
{
if (rk != null)
{
foreach (string s in rk.GetSubKeyNames())
{
Console.WriteLine(s);
if (s != null)
{
if (s.Equals(programDisplayName))
{
AppendToLog(logstr + " INSTALLED");
return true;
}
}
}
}
}
}
}
AppendToLog(logstr + " NOT INSTALLED", Color.Red);
return false;
}

SharePoint ClientContext.ExecuteQuery works in c# application but crashes in DLL

I have written C# code to search for specific file types in SharePoint lists within a site and display the file names in a listview.
The code works perfectly well in a C# windows application, but when it is compiled into a C# DLL and called from a Delphi2007 application it crashes when it hits the first call to ClientContext.ExecuteQuery(). There is no exception or error message - the Delphi application just stops running.
The really weird part is that my Delphi test application has a web browser component, and if I use that to navigate to the top level list on the site the DLL then works OK.
The question therefore is why does the first ExecuteQuery call fail in the DLL if I haven't logged on to the site first?
This is the C# code:
public void ListFiles()
{
string LContains = "<Contains><FieldRef Name='FileLeafRef'/> <Value Type ='Text'>{0}</Value></Contains>";
string LNotEqual = "<Contains><FieldRef Name='FileLeafRef'/><Value Type ='Text'>{0}</Value></Contains>";
string LWhereQuery = "";
switch (comboFileType.SelectedIndex)
{
case 0: LWhereQuery = string.Format(LContains, ".DOC"); break;
case 1: LWhereQuery = string.Format(LContains, ".PDF"); break;
case 2: LWhereQuery = string.Format(LNotEqual, "xxxx"); break;
}
Uri LUri = new Uri(SharePointURL);
using (SP.ClientContext LContext = new SP.ClientContext(SharePointURL))
{
System.Net.CredentialCache cc = new System.Net.CredentialCache();
if (!string.IsNullOrEmpty(Domain))
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password, Domain));
else
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password));
LContext.Credentials = cc;
LContext.AuthenticationMode = SP.ClientAuthenticationMode.Default;
var LWeb = LContext.Web;
lvItems.BeginUpdate();
try
{
try
{
SP.List LList = LWeb.Lists.GetByTitle(DefaultListName);
SP.CamlQuery LQuery = new SP.CamlQuery();
LQuery.ViewXml = "<View Scope='RecursiveAll'><Query><Where>"
+ LWhereQuery
+ "</Where></Query><RowLimit> 30 </RowLimit></View>";
SP.ListItemCollection LItems = LList.GetItems(LQuery);
LContext.Load(LItems);
LContext.ExecuteQuery(); **<<<< Crash happens here**
foreach (SP.ListItem LItem in LItems)
{
SP.File LFile = LItem.File;
LContext.Load(LFile);
LContext.ExecuteQuery();
var LViewItem = new ListViewItem();
try { LViewItem.Text = LFile.Name; }
catch { LViewItem.Text = "!Error"; }
try { LViewItem.SubItems.Add(LFile.TimeLastModified.ToString()); }
catch { LViewItem.SubItems.Add("!Error"); }
if (LFile.CheckOutType != Microsoft.SharePoint.Client.CheckOutType.None)
{
try { LViewItem.SubItems.Add(LFile.CheckedOutByUser.LoginName); }
catch { LViewItem.SubItems.Add("!Error"); }
}
else
LViewItem.SubItems.Add("Not checked out.");
try { LViewItem.Tag = LFile.ServerRelativeUrl; }
catch { LViewItem.Tag = "!Error"; }
lvItems.Items.Add(LViewItem);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex);
}
}
finally
{
lvItems.EndUpdate();
}
}
The code is in the .cs of a dialog form in the DLL. The form displays as it should and the crash only happens when I click a button to do the search.
I put some debug code in to check all the string params etc. (by writing them to a text file) and they are all OK.
I tried debugging the DLL from VS by specifying the D2007 app as the 'startup external program' but I can't get breakpoints to work and at the point where it crashes it says: An unhandled exception of type 'System.StackOverflowException' occurred in Microsoft.SharePoint.Client.Runtime.dll and suggests I might have an infinite recursive call but, as mentioned earlier, the code all works perfectly if I have already logged into the site and browsed to the top level list, so i don't think it is a recursive call.
UPDATE: I got the debugging to work by copying the Delphi exe to the same directory as the DLL.
I've tried using the ExceptionHandlingScope but it hasn't helped. This is how it looks when it crashes:
The scope has no exception and the errormessage is blank. I tried a few connotations of what was inside the scope but to no avail.
The whole code block is in a try..catch and I've tried wrapping the ExecuteQuery line in it's own try..catch as well, but nothing catches it. The app crashes out every time when I hit continue.
I've also tried putting an execute query before loading the web but it still crashes out.
I'm thinking this has to be something to do with credentials? If I deliberately put the wrong username I get a polite '401 Unauthorized' back and no crash. And if I'm already logged in it doesn't crash either?
After trying the C# test application I tried the same with Delphi XE8 and that also worked, so in the end I've resorted to writing an intermediate DLL in XE8.
I noticed that when importing the TLB from the C# DLL into XE8 it behaved differently from D2007 in that it complained about other missing TLB's when building - notably the system.windows.forms library (and some dependencies). I'm not sure if this has any bearing on XE8 working and D2007 failing, but hopefully it well help anyone else needing a workaround.

C# getting status of SystemRestore from the registry

I'm trying to read the registry key "RPSessionInterval" from the subkey "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" in C#. I'm using the following code and getting the exception "Object reference not set to an instance of an object."
string systemRestore = #"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore";
RegistryKey baseRegistryKey = Registry.LocalMachine;
public string SystemRestoreStatus(string subKey, string keyName)
{
RegistryKey rkSubKey = baseRegistryKey.OpenSubKey(systemRestore);
if (rkSubKey != null)
{
try
{
string sysRestore = rkSubKey.GetValue("RPSessionInterval").ToString();
if (string.Compare(sysRestore, "1") == 0)
{
MessageBox.Show("System Restore is Enabled!");
return "System Restore is Enabled!";
}
else if (string.Compare(sysRestore, "0") == 0)
{
MessageBox.Show("System Restore is Disabled!");
return "System Restore is Disabled!";
}
else
{
return null;
}
}
catch (Exception ex) //This exception is thrown
{
MessageBox.Show("Error while reading registry key: " + subKey + "\\" + keyName + ". ErrorMessage: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
else
{
MessageBox.Show("Error while reading registry key: " + subKey + "\\" + keyName + " does not exist!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
Here is a picture showing that the registry key actually exists:
You most likely have a spelling issue for the call to SystemRestoreStatus, which is causing the exception on the following line:
string sysRestore = rkSubKey.GetValue(keyName).ToString();
If you aren't sure whether the value will exist or not, you can change this line to:
string sysRestore = rkSubKey.GetValue(keyName) as string;
and then test to see if the string is null or empty before trying to use it.
Update
Another possibility is that you are executing the code from a 32-bit application on a 64-bit OS. In this case, .Net helpfully redirects your request to the
SOFTWARE\Wow6432Node\Microsoft\...
node instead.
You can get around this issue by using RegistryKey.OpenBaseKey using RegistryView.Registry64 as the second parameter.
You probably have the wrong bitness for your C# application. By default, a Visual Studio 2010 C# project will compile to x86 (32-bit). A 32-bit application running on a 64-bit OS can generally only access the 32-bit registry, the contents of which are often different than the native 64-bit registry. Change the architecture to "Any CPU" or "x64" and it may work.

Unable to set registry values using RegistryKey class in C# .NET

I am using Visual C# 2010 and am having problems setting registry keys. I assumed this was to do with the fact that I wasn't running it as admin at first but i have tried building the Release and then right clicking the exe and selecting 'run as administrator' to no avail.
I also tried using the RegistryPermission class which didn't seem to make any difference.
Here is the code:
RegistryKey rkey = Registry.LocalMachine;
// RegistryPermission f = new RegistryPermission(
// RegistryPermissionAccess.Write | RegistryPermissionAccess.Read,
// #"HKEY_LOCAL_MACHINE\SOFTWARE\Company\Product");
/**********************/
/* set registry keys */
/**********************/
RegistryKey wtaKey = rkey.OpenSubKey(#"SOFTWARE\Company\Product", true);
try
{
wtaKey.SetValue("key1", 123);
wtaKey.SetValue("key2", 567);
wtaKey.SetValue("key3", textbox.Text);
wtaKey.SetValue("key4", "some string");
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
return;
}
This gives me the error message from the exception each time I run it, even with 'run as administrator'. Any ideas how I can get around this? It seems strange because my standard user account allows me to go into regedit and manually change these values no problem.
This works :)
First:
You should be using CreateSubKey rather than OpenSubKey.
Second:
It was not an administrative issue that you were experiencing, rather, you simply needed to add another "\" to the end of your registry path.
private void button1_Click(object sender, EventArgs e)
{
RegistryKey rkey = Registry.LocalMachine;
RegistryPermission f = new RegistryPermission(
RegistryPermissionAccess.Write | RegistryPermissionAccess.Read,
#"HKEY_LOCAL_MACHINE\SOFTWARE\Company\Product");
/**********************/
/* set registry keys */
/**********************/
RegistryKey wtaKey = rkey.CreateSubKey(#"SOFTWARE\Company\Product\");
try
{
wtaKey.SetValue("key1", 123);
wtaKey.SetValue("key2", 567);
wtaKey.SetValue("key4", "some string");
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
return;
}
}

What's wrong with Registry.GetValue?

I trying to get a registry value:
var value = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", "MachineGuid", 0);
In Windows XP all ok, but in Windows 7 returns 0. In HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography using regedit I see MachineGuid, but if I run
var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE").OpenSubKey("Microsoft").OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree).GetValueNames();
keys.Length is 0.
What do I do wrong? With other values all ok in both of OS.
The problem is that you probably are compiling the solution as x86, if you compile as x64 you can read the values.
Try the following code compiling as x86 and x64:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MachineGUID:" + MachineGUID);
Console.ReadKey();
}
public static string MachineGUID
{
get
{
Guid guidMachineGUID;
if (Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography") != null)
{
if (Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography").GetValue("MachineGuid") != null)
{
guidMachineGUID = new Guid(Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography").GetValue("MachineGuid").ToString());
return guidMachineGUID.ToString();
}
}
return null;
}
}
}
You can read more about Accessing an Alternate Registry View.
You can found in here a way of reading values in x86 and x64.
It probably has to do with UAC (User Account Control). The extra layer of protection for Windows Vista and Windows 7.
You'll need to request permissions to the registry.
EDIT:
Your code right now:
var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE")
.OpenSubKey("Microsoft")
.OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree)
.GetValueNames();
Only requests the permissions on the Cryptography subkey, maybe that causes the problem (at least I had that once), so the new code would then be:
var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE", RegistryKeyPermissionCheck.ReadSubTree)
.OpenSubKey("Microsoft", RegistryKeyPermissionCheck.ReadSubTree)
.OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree)
.GetValueNames();
EDIT2:
I attached the debugger to it, on this code:
var key1 = Registry.LocalMachine.OpenSubKey("SOFTWARE", RegistryKeyPermissionCheck.ReadSubTree);
var key2 = key1.OpenSubKey("Microsoft", RegistryKeyPermissionCheck.ReadSubTree);
var key3 = key2.OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
var key4 = key3.GetValueNames();
It turns out, you can read that specific value, at least that's my guess, because all data is correct, until I open key3, there the ValueCount is zero, instead of the expected 1.
I think it's a special value that's protected.
You say you're on 64-bit Windows: is your app 32-bit? If so it's probably being affected by registry redirection and is looking at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography. You may have to P/Invoke to work around it: http://msdn.microsoft.com/en-us/library/aa384129.aspx.
If you're not an administrator, you only have read permission on HKLM. You need to open the key read-only instead. Not sure how to do that with .NET's Registry class; with the API directly, you use RegOpenKeyEx() with the KEY_READ flag.
EDIT: After checking MSDN, I see that OpenSubKey() does open read only, and returns the contents if it succeeds and nothing if it fails. Since you're chaining multiple OpenSubKey calls, it's most likely one of them that's failing that causes the others to fail. Try breaking them out into separate calls, and checking the intermediate values returned.
Maybe a little late to the party, but, none of the solutions worked for me.
This is how I've solved this issue:
public static Guid GetMachineGuid
{
get
{
var machineGuid = Guid.Empty;
var localMachineX64View = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var cryptographySubKey = localMachineX64View.OpenSubKey(#"SOFTWARE\Microsoft\Cryptography");
if (cryptographySubKey == null) return machineGuid;
var machineGuidValue = (string)cryptographySubKey.GetValue("MachineGuid");
Guid.TryParse(machineGuidValue, out machineGuid);
return machineGuid;
}
}
I solved the problem when i imported Microsoft.Win32 and changed the application-settings to x64 like pedrocgsousa mentioned.

Categories