I am trying to modify a registry key that I have been told controls whether write-caching is enabled on particular hard drives. The key should be: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\IDE\<DiskName>\<SerialNo>\Device Parameters\Disk\UserWriteCacheSetting
However I keep having problems when trying to create this key (as it doesn't exist by default). If I try to open up the ...\Device Parameters\Disk\ with write access I get a SecurityException error; "Requested registry access is not allowed". Now I have added the <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> flag to my manifest file so as to ensure I have admin access, but I'm still not having any luck.
Any ideas would be great!
static void Main(string[] args)
{
RegistryKey myKey = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum\\IDE\\");
foreach (string driveManafacturer in myKey.GetSubKeyNames())
{
RegistryKey driveKey = myKey.OpenSubKey(driveManafacturer);
foreach (string driveID in driveKey.GetSubKeyNames())
{
RegistryKey driveIDKey = driveKey.OpenSubKey(driveID, true);
string driveType = (string)driveIDKey.GetValue("Class");
if (driveType == "DiskDrive")
{
RegistryKey tempKey = driveIDKey.OpenSubKey("Device Parameters\\Disk\\", true);
if (tempKey == null)
{
tempKey = driveIDKey.CreateSubKey("Device Parameters\\Disk\\");
tempKey.SetValue("UserWriteCacheSetting", 0x0);
}
}
}
}
return;
}
I don't have a better suggestion. Try to create registry entry by hand, just to make sure that you can. Then make sure that the application is running with your credentials. Just to eliminate the permission issue.
EDIT: Removed the idea about partial trust ... it turned out that it had nothing to do with the problem.
I tried your code and got the same error - with some modifications it works:
RegistryKey myKey = Registry.LocalMachine.OpenSubKey( "SYSTEM\\CurrentControlSet\\Enum\\IDE\\" );
foreach( string driveManafacturer in myKey.GetSubKeyNames() )
{
RegistryKey driveKey = myKey.OpenSubKey( driveManafacturer );
foreach( string driveID in driveKey.GetSubKeyNames() )
{
RegistryKey subKey = driveKey.OpenSubKey( driveID );
string driveType = (string)subKey.GetValue( "Class" );
if( driveType == "DiskDrive" )
{
RegistryKey tempKey = subKey.OpenSubKey( "Device Parameters", true );
RegistryKey tempKey2 = tempKey.OpenSubKey( "Disk" );
if( tempKey2 == null )
{
tempKey2 = tempKey.CreateSubKey( "Disk" );
tempKey2.SetValue( "UserWriteCacheSetting", 0x0 );
}
}
}
}
Related
So to my final programming project I need to rename a value inside Registry through C#, this is what I wrote so far:
public bool RenameSubKey(string parentKey, string subKeyName, string newSubKeyName)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
rk64.OpenSubKey(parentKey);
//copy all the values
foreach (string valueName in rk64.OpenSubKey(subKeyName).GetValueNames())
{
object objValue = rk64.OpenSubKey(subKeyName).GetValue(valueName);
RegistryValueKind valKind = rk64.OpenSubKey(subKeyName).GetValueKind(valueName);
rk64.CreateSubKey(newSubKeyName).SetValue(valueName, objValue, valKind);
}
rk64.DeleteSubKeyTree(subKeyName); // Deletes old value
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(parentKey, false))
{
rk.OpenSubKey(parentKey);
//copy all the values
foreach (string valueName in rk.OpenSubKey(subKeyName).GetValueNames())
{
object objValue = rk.OpenSubKey(subKeyName).GetValue(valueName);
RegistryValueKind valKind = rk.OpenSubKey(subKeyName).GetValueKind(valueName);
rk.CreateSubKey(newSubKeyName).SetValue(valueName, objValue, valKind);
}
rk.DeleteSubKeyTree(subKeyName); // Deletes old value
return true;
}
}
It needs to be able to rename a 32-bit Registry value as well as a 64-bit Registry value (the application is 32-bit). Rename function simply means to create new value with the new name, copy all the data from the old one to the new one and delete the old one.
Let's take an example: There's a ListView presents all the installed application on the PC and I want to change the value UninstallString to !UninstallString with the press of a button so the users won't be able to uninstall the selected application in the ListView. The app might be 64-bit (meaning the Registry values are 64-bit and it requires a little different approach) or it can be 32-bit - Hence comes the if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess).
So in the example I place SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip as my path and I want to rename the value UninstallString to !UninstallString, but it quits on the foreach with an error says System.NullReferenceException: 'Object reference not set to an instance of an object.' Microsoft.Win32.RegistryKey.OpenSubKey(...) returned null.
First of all, let me say, this requieres elevated privileges, the changes are because you want to enter the registry and write in them so you need to actually tell that when you are opening the sub key. Either in 64 or 32 bit. Im not sure about the If, as pointed out before by the general, but this will work at least for 32 bits path
public static bool RenameSubKey(string parentKey, string key, string newValue)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(parentKey, RegistryKeyPermissionCheck.ReadWriteSubTree);
rk64.SetValue(key, newValue);
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(parentKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
rk.SetValue(key, newValue);
return true;
}
}
Thanks to #nalnpir I fixed the rename Registry value function:
public static bool RenameSubKey(string path, string keyName, string newKeyName)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(path, RegistryKeyPermissionCheck.ReadWriteSubTree);
object objValue = rk64.GetValue(keyName);
RegistryValueKind valKind = rk64.GetValueKind(keyName);
rk64.SetValue(newKeyName, objValue, valKind);
rk64.DeleteValue(keyName);
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(path, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
object objValue = rk.GetValue(keyName);
RegistryValueKind valKind = rk.GetValueKind(keyName);
rk.SetValue(newKeyName, objValue, valKind);
rk.DeleteValue(keyName);
return true;
}
}
Now I see that I didn't access it the right way (as he enlightened me) and thus was the error.
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");
I am trying to delete a registry key sub tree which happens to be SAPI 5 user profile as shown below. The "nameofprofile" is the data value of the subkey and the subkey name is a CLSID but it comes up with an exception telling me that the subkey does not exist?
RegistryKey RegKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Speech\\RecoProfiles\\Tokens\\", true);
RegKey.DeleteSubKeyTree("NameOfProfile");
You can try this.
string keyName = #"Software\Microsoft\Speech\RecoProfiles\Tokens";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName, true))
{
key.DeleteSubKeyTree("NameOfProfile",false);
}
If you get the error again, you can try to run application in administrator mode.
Do a search of the string[] GetSubKeyNames() first and see if the sub key exists.
Try ignoring casing in case that is an issue.
var name = #"Software\Microsoft\Speech\RecoProfiles\Tokens";
var regKey = Registry.CurrentUser.OpenSubKey(name, true);
if (regKey != null) {
using (regKey) {
var subKeyName = "CLSID";
var actual = regKey.GetSubKeyNames()
.FirstOrDefault(n => string.Equals(n, subKeyName, StringComparison.InvariantCultureIgnoreCase));
if (actual != null) {
regKey.DeleteSubKeyTree(actual);
}
}
}
In the end I worked it out myself and I did this which worked fine. I should have said in the post that I always knew the profile name but I did not know the CLSID. No doubt there is an easier way to do this(No special permissions were required which was preferable if possible):
public static void DeleteKey (String profileName)
{
// Folder for SAPI 5 user profile tokens
String keyLocation = #"Software\Microsoft\Speech\RecoProfiles\Tokens";
RegistryKey key = Registry.CurrentUser.OpenSubKey(keyLocation, true);
// Get a list of Key names and work out which one is the "test" profile
String [] subKeyNames = key.GetSubKeyNames();
// Enumerate through the sub key names to find out which one is the "Test" profile
for(int i = 0; i < subKeyNames.Length; i++)
{
RegistryKey subKey =
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Speech\\RecoProfiles\\Tokens\\" + subKeyNames[i]);
if(((String)subKey.GetValue("")).Equals(profileName))
{
key.DeleteSubKeyTree(subKeyNames[i]);
return;
}
}
}
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.
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 .