My application writes user settings to the registry for easy retrieval but this is causing a little headache because it's writing them as version specific.
So each time I update my application it creates a new subkey pertaining to the new version number.
Settings are written to the registry as:
Application.UserAppDataRegistry.SetValue
I would like to find utilize a simple method to delete all the VERSION subkeys that do not match the current Application version.
At the moment and because my application is relatively new I have resorted to this, which does work but is rather untidy:
Registry.CurrentUser.DeleteSubKey("SOFTWARE\\COMPANY\\PRODUCT\\1.0.0.0", false);
Registry.CurrentUser.DeleteSubKey("SOFTWARE\\COMPANY\\PRODUCT\\1.0.10.0", false);
in the above code I have removed the COMPANY & PRODUCT info deliberately & my application is currently on version 1.0.20.0 so at app start the DeleteSubKey lines are run and they are every time the app is run.
I am thinking that something along the lines of using:
If(PreviousVersion != Application.ProductVersion)
{
Registry.CurrentUser.DeleteSubKey(PreviousVersion);
}
but I am having trouble fleshing this out.
Plus it would be nice to have it only run the one time and not at every startup.
You can list subkeys and check if they're different from current version:
RegistryKey rk = Registry.CurrentUser.OpenSubKey("SOFTWARE\\COMPANY\\PRODUCT");
var keys = rk.GetSubKeyNames();
foreach (string s in keys)
{
if (s != "Current_verion_number")
{
Registry.CurrentUser.DeleteSubKeyTree("SOFTWARE\\COMPANY\\PRODUCT\\" + s);
}
}
Related
I'm trying to fetch some data on the Office Click-To-Run currently installed.
I've read these posts : Can't Read Registry Key or OpenSubKey() returns null for a registry key that I can see in regedit.exe
I'm on Windows 10 64bit. My application is an Outlook add-in, so I can't change the target platform (32/64bit), it's the Host that determine if I'm running in 32bit or 64bit. So I've to handle both cases.
So I've this (test) code :
using (var hklmTest64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
var test = hklmTest64.GetValue(#"SOFTWARE\Microsoft\Office\ClickToRun\Configuration\AudienceData");
if (test == null)
{
using (var hklmTest32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
{
test = hklmTest32.GetValue(#"SOFTWARE\Microsoft\Office\ClickToRun\Configuration\AudienceData");
}
}
}
So I first fetch the registry key using the 64bit view, then if null I retry using the 32bit view.
Problem: test is always NULL.
Of course the key exists and I can see it using regedit:
Of course I first tried simple code that until now always worked for me, but doesn't work to fetch this key:
test = Registry.LocalMachine.GetValue(#"SOFTWARE\Microsoft\Office\ClickToRun\Configuration\AudienceData");
test = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\ClickToRun\Configuration", "AudienceData", null);
And more strange thing, it's that I had exactly the same problem for fetching the windows build number. This code was not working :
var wBuild = Registry.LocalMachine.GetValue(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId");
But this one works perfectly for windows build (not for outlook key):
var wBuild = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", null);
Any idea how to fetch this registry key ?
UPDATE 1
See the post C# get Office ClickToRun Registry Key returns null
But reading the post, my code using RegistryView.RegistryXX should work...
UPDATE 2
I've reprod the problem using LinqPad, so this is not due to the Outlook host / add-in. I tried to reprod in a .NET Fiddle but indeed the code is not allowed to access the registry :)
I can get the correct values using P/Invoke like explained in this article. So for me it's clearly a 32/64bit (wow6432node) problem.
you dont need
RegistryKey.OpenBaseKey
just use Registry.GetValue(keyName, valueName, defualt value)
this is working example
string InstallPath = (string)Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\" + path, "ActivationCode", null);
I can get the correct values using P/Invoke like explained in this article. So for me it's clearly a 32/64bit (wow6432node) problem.
I'm building an asset tracker of sorts. I'm already searching the registry to get a list of all software titles, publishers, install dates and it's working great. However, programs installed with ClickOnce don't store the install date in the registry(at least not that I can find).
I know I should eb able to use WMI to get the install date, but this is very slow. Also, per this post: Get installed applications in a system
"using the WMI Win32_Product class is a bad idea if you plan to run this query repeatedly"
So, without using WMI, how can I get the install date of ClickOnce programs? I know the information is available somehow because the date is inside of Add/Remove programs.
As ClickOnce application installs per user, you can find uninstall information (what app wizard shows you) by follwing path in registry:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall\5f7eb300e2ea4ebf
This 'Uninstall' has unique hash subkeys, to find your app you can iterate through these keys and filter for example by DisplayName like this:
private RegistryKey GetUninstallRegistryKeyByProductName(string productName)
{
var subKey = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Uninstall");
if (subKey == null)
return null;
foreach (var name in subKey.GetSubKeyNames())
{
var application = subKey.OpenSubKey(name, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.QueryValues | RegistryRights.ReadKey | RegistryRights.SetValue);
if (application == null)
continue;
foreach (var appKey in application.GetValueNames().Where(appKey => appKey.Equals("DisplayName")))
{
if (application.GetValue(appKey).Equals(productName))
return application;
break;
}
}
return null;
}
This method returns RegistryKey, then you can get 'DisplayVersion' key value:
var key = GetUninstallRegistryKeyByProductName("myApp");
var version = key.GetValue("DisplayVersion");
Update
Regarding Install date, Try getting last write time of registry key (Getting last write time of "DisplayVersion" is what you need). It looks like there's no managed wrapper for getting this, so use P/Invoke. You need to call RegQueryInfoKey.
Im developing a custom browser solution with .net's Webbrowser control.
To disable the IE-Compatibilty View, I set the registry entry
Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION:
[Sreenshot regedit] http://zbirk.mirk.at/browserreg.png "Screenshot"
i tried to use the values: dword=8000,dword=8888,dword=9000, but the webbrowser control seems to ignore these reg entries.
Maybe someone had this problems too and may help me.
The WebBrowser control definately DOES respect these keys.
Remember that while taskman may show application.exe in the name column, if you are debugging the exe name is application.vshost.exe
So in my application sI just attempt to create the key every time the app runs. If it fails to create it (because it already exists) then I continue running, if it creates the key then I inform the user that they need to restart the application.
ensure that you are not running within vshost
the app name would be different ie appname.vshost.exe
Thx for your reply, now its working.
Her is my working peace of code:
public void setIEcomp()
{
String appname = Process.GetCurrentProcess().ProcessName+".exe";
RegistryKey RK8 = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION",RegistryKeyPermissionCheck.ReadWriteSubTree);
int value9 = 9999;
int value8 = 8888;
Version ver = webBrowser1.Version;
int value = value9;
try
{
string[] parts = ver.ToString().Split('.');
int vn = 0;
int.TryParse(parts[0], out vn);
if (vn != 0)
{
if (vn == 9)
value = value9;
else
value = value8;
}
}
catch
{
value = value9;
}
//Setting the key in LocalMachine
if (RK8 != null)
{
try
{
RK8.SetValue(appname, value, RegistryValueKind.DWord);
RK8.Close();
}
catch(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
I too could not see that FEATURE_BROWSER_EMULATION made any difference in my application.
I was testing the FEATURE_BROWSER_EMULATION functionality by manually editing the registry with regedit. Nothing I did made any difference. My hosted page was still failing on any new-ish JavaScript and could not load external libraries.
I found my mistake:
I was editing the 64-bit view of the registry with regedit. My app was running as a 32-bit app and looking at the 32-bit view of the registry. That's why my changes to the registry seemed to have no impact on my application. By the way, the WPF project template defaults to "Prefer 32-bit."
Manually editing with regedit within the Wow6432Node key worked:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Of course, setting the DWORD value programmatically within your application will also work, since your 32-bit application will edit within the Wow6432Node.
An older post and solution is no longer accurate.
Running procmon and watching for FEATURE_BROWSER_EMULATION shows the following registry variables actually checked. This was for WINWORD.exe but other than that - take your pick...
HKU\S-1-5-21-[my-sid-paws-off]\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKU\S-1-5-21-[my-sid-paws-off]\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION(Default)
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKLM\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*
HKLM\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*
I'm currently building a registry explorer, mostly because I want to support some much better searching operations. Like 'find all' and regular expressions. One problem I'm facing is that some keys throw a security exception when opening. I HAVE TRIED running the app with administrator priviledges, my user account is an administrator also. I embedded a manifest with "requireAdministrator" requested priviledges. I have also tried setting the ClickOnce security settings to Full trust, which is incompatible with requireAdministrator, or so Visual Studio tells me.... Nothing seems to help with avoiding this exception.
I would just like to iterate over all of the keys. I do not wish to add/delete keys. If a user wishes to delete a key and does not have permission to do so, it would display an error message. I just want to be able to have unrestricted READ access. Is this possible?
FTR: I'm on Win7 x64 and using Vs2010u and project is written in C# on .net 4.0. If regedit is capable of reading all keys even if it doesn't let you edit some of them. It would seem appropriate that we too can make an app to do the same thing. Though I'm finding it very difficult, and there doesn't seem to be any real help on the www. Only link-link circles, yay.
[EDIT]
Here's the code that reads the keys:
private void IterateSubKeys(RegistryKeyModel key) {
var subKeys = key.Key.GetSubKeyNames();
var values = key.Key.GetValueNames();
foreach (var valuename in values) {
try {
var valueKind = key.Key.GetValueKind(valuename);
var value = key.Key.GetValue(valuename);
key.Values.Add(new RegistryValueModel(valuename, value, valueKind));
}
catch { }
}
foreach (var keyname in subKeys) {
try {
var subkey = key.Key.OpenSubKey(
keyname,
RegistryKeyPermissionCheck.ReadSubTree,
RegistryRights.ReadKey);
key.SubKeys.Add(new RegistryKeyModel(subkey));
}
catch { Console.WriteLine("Error reading key: {0}", keyname); }
}
}
This is by design. There are lots of security related keys that can only accessible to the System account. You can't use that account. Regedit can't read these keys either, they are just not visible. Avoiding the expensive exception is going to require pinvoke.
I have already looked at existing topics, so please try to refrain from dropping links here.
I want to get the value of a registry key - plain and simple. Here is what I have so far.
Registry:
1) Made a key under
Current_User\Software\Custom_Subkey\Custom_Value\Custom_key\string_value
I am trying to find the string_value
string reg_subKey = "Software\\Custom_Subkey\\Custom_Value";
RegistryKey root = Registry.CurrentUser.CreateSubKey(reg_subKey);
foreach (string keyname in root.GetValueNames())
{
textBox4.AppendText(keyname.ToString() + Environment.NewLine);
// Appends the following data to textBox4 once the foreach is completed:
// Header1
// Header2
// Header3
// Header4
// Header5
// Now I want to get the VALUES of each header:
using (RegistryKey key = root.OpenSubKey(keyname))
{
**// THIS LINE GETS HIGHLIGHTED WITH THE FOLLOWING ERROR:
"Object reference not set to an instance of an object.**"
MessageBox.Show(key.ValueCount.ToString());
}
}
Hopefully this is a simple fix. I look forward to hearing your responses.
Thanks,
Evan
I believe you want root.GetSubKeyNames() in the loop not GetValueNames()
While values is working to get the values I would suggest the following loop:
foreach(string keyname in root.GetSubKeyNames())
{
// use key to get value and set textbox4
using (RegistryKey key = root.OpenSubKey(keyname))
{
MessageBox.Show(key.ValueCount.ToString());
}
}
The OpenSubKey method does not throw an exception if the specified subkey is not found. Instead, it simply returns null. It's your responsibility as a programmer to ensure that the appropriate key was found and opened by checking the return value of the method call.
Thus, my suspicion is that the registry key that you've specified is invalid. Open up Registry Editor (regedt32.exe), and verify that you can find the key in the registry exactly as written.
If you find that the registry key is indeed located exactly where you thought it was, then the problem may be related to the WOW64 subsystem, which allows 64-bit versions of Windows to run 64-bit apps. If the value was written to the registry by a 32-bit program, you won't be able to read it with the above code from a 64-bit program (or vice versa). The simplest way to check this is to change the compilation settings for your project. For example, if you're currently compiling for x86, then change to compiling for x64, or vice versa. Registry redirection may also be getting in your way; this will check for that as well.
I wanted the very same thing and your code helped me, but as you said, it didn't work properly. So, I made some modifications and I think it works fine now! Try this:
//Just make the reference until "custom_subkey", not to the next one ("custom value")
string reg_subKey = "Software\\Custom_Subkey";
RegistryKey root = Registry.CurrentUser.CreateSubKey(reg_subKey);
//Use GetSubKeyNames, instead of GetValueNames, because now you are in a higher level
foreach (string keyname in root.GetSubKeyNames())
{
using (RegistryKey key = root.OpenSubKey(keyname))
{
foreach (string valueName in key.GetValueNames())
{
MessageBox.Show(valueName);
MessageBox.Show(key.GetValue(valueName).ToString() );
}
}
}