Monitor GAC changes in registry with WMI - RegistryKeyChangeEvent GACChangeNotification Not Found - c#

I'm trying to monitor the registry for changes to the GAC using WMI. I have the following code:
WqlEventQuery query = new WqlEventQuery(#"SELECT * FROM RegistryKeyChangeEvent WHERE Hive = 'HKEY_LOCAL_MACHINE' AND KeyPath='SOFTWARE\\Microsoft\\Fusion\\GACChangeNotification\\Default'");
_regWatcher = new ManagementEventWatcher(query);
_regWatcher.EventArrived += new EventArrivedEventHandler(_regWatcher_EventArrived);
_regWatcher.Start();
But when it calls Start(), it causes a ManagementException with the message "Not Found". I copied the key path from the registry so I know it exists. I have never done this before, so maybe I'm misusing it. I want to receive notification when any value is changed in the Default key (specifically when a value is added). Why is it giving the "Not Found" exception and how do I correctly monitor this key for changes using WMI?

You are surely yet another victim of the registry redirector in the 64-bit version of Windows. Project + Properties, Build tab, change the Platform target setting from x86 to AnyCPU. On VS2012 and up, untick the "Prefer 32-bit" checkbox.
Your program will now as a 64-bit process and can properly see the registry key. Instead of the HKLM\Software\Wow6432Node subkey you tried to look at before.

Related

Getting registry key returns null when using Registry.LocalMachine.OpenSubKey and the key exists

I am trying to get below registry key from Windows Registry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\16.0\ClickToRunStore\Applications
and then the value for Outlook.
I am running on a Windows 64 bits and Outlook is installed in 64 bits
Using below piece of code is working:
RegistryKey lmRegistry
= RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
Environment.Is64BitOperatingSystem
? RegistryView.Registry64
: RegistryView.Registry32);
string keyPath = #"SOFTWARE\Microsoft\Office\16.0\ClickToRunStore\Applications";
RegistryKey registry = lmRegistry.OpenSubKey(keyPath);
string keyName = "Outlook";
string value = registry.GetValue(keyName) as string;
However if I do below it does not work, rk is null:
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(keyPath))
{
string outlookPath = rk?.GetValue(keyName) as string;
}
I am trying to understand why I am getting null in the second case since keyPath and keyName exist both in the registry.
Why is it necessary to first select the correct registry view using RegistryView if I am already pointing to the full and correct keyPath?
For example If I had installed Outlook 32 bits installed on Windows 64 bits instead of Outlook 64 bits, wouldn't it be enough to retrieve it using OpenSubkey and then GetValue without previously using OpenBaseKey if for example I specify the full path as "SOFTWARE\WOW6432Node\Microsoft\Office\16.0\ClickToRunStore\Applications" ? Why do I have to use OpenBaseKey first?
I just walked a coworker through this same scenario. To fix using the shorter code snippet, set the target architecture of your project to x64 to force your process to run as 64-bit. Assemblies compiled with x86 or AnyCPU run as a 32-bit process.
The reason for the apparent weirdness is because the registry redirector presents a different logical view of the registry to 32-bit processes running on a 64-bit version of Windows. The longer code snippet explicitly forces the logical view to the one you want no matter which target architecture you compile with.

Registry and Wow6432Node on C#

I´m trying to access a path in the registry inside Wow6432Node, to write a value inside it, but it is not working. I tried with different codes, but it´s still not working. I am running it as "Any CPU" on a x64 bit Windows 10. I suspect it has something to do with the difference on the registry between x86 and x64. Am I wrong?
if (rv3.Checked == true)
{
string line2 = File.ReadLines(AppDomain.CurrentDomain.BaseDirectory + "simulators.txt").Skip(3).Take(1).First();
MessageBox.Show(line2);
if (System.IO.Directory.Exists(line2))
{
var baseReg = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var Key = baseReg.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Microsoft Games\flight simulator\10.0\");
if (Key != null)
{
RegistryKey key2 = baseReg.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Microsoft Games\flight simulator\10.0\");
key2.SetValue("SetupPath", line2);
key2.Close();
}
}
}
Kind regards!
I ran into similar issues when working with the registry, and I suspect you're a victim of "virtualization".
On a machine with User Account Control (UAC) you aren't strictly denied permission to write to the registry, but the calls get virtualised. See if the values you are expected to see are turning up at HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software\.
The solution is to add an application manifest file to the solution, and set requestedExecutionLevel level="requireAdministrator", which means whenever you run the application on a machine with UAC it will ask "Are you sure?". You also need to ensure the project properties specify the manifest to use.
I then ran into a second problem, which is that when you're debugging through Visual Studio, it will run with VS execution level, not those specified in the manifest (see here). The easiest solution is to set VS to run as Administrator in the shortcut properties.

VB6 EXE with argument working in CMD file, but not in C# code

I have a VB6 EXE which I want to trigger through C# code as shown below. After this code execution, I can see the EXE has been started in taskmanager, and got finished after sometime.
I deploy the code in IIS Server. Start Browsing the site and click on the button of c# code which starts the VB6SOME.exe. The Exe started but never got completed (Taskmanager is showing the VB6SOME.exe for user NETWORK Service).
prcstrinfo.FileName = "VB6SOME.exe";
prcstrinfo.Arguments = "USERID,PASSWORD," + DateTime.Now.ToShortDateString();
Process proc = Process.Start(prcstrinfo);
Also, I tried to call the VB6SOME.exe through CMD passing all necessary arguments. It got started and finished correctly. (I also monitored the TaskManager and I saw that it started as MY ID not as Network Service). Please help to fix the issue.
Registry Redirector
The registry redirector isolates 32-bit and 64-bit applications by providing separate logical views of key portions of the registry on WOW64. The registry redirector intercepts 32-bit registry calls to each logical registry view and maps them to the corresponding physical registry location. The redirection process is transparent to the application. Therefore, a 32-bit application can access registry data as if it were running on 32-bit Windows even if the data is stored in a different location on 64-bit Windows.
Redirection is enabled for the following registry keys:
HKEY_LOCAL_MACHINE\Software
From Windows SDK 64 Bit Development Guide

File exists in Windows Explorer and notepad, but is not accessable in my program

Why does the following problem happen?
Scenario:
Make sure that IIS is installed
Execute "notepad
%WINDIR%\System32\inetsrv\config\applicationHost.config" using admin
account
Actual Result: the file is successfully opened in notepad
Execute the following code in admin account's context:
string filePath = #"%WINDIR%\System32\inetsrv\config\applicationHost.config";
Console.WriteLine(File.Exists(Environment.ExpandEnvironmentVariables(filePath)));
Actual Result: False
Expected Result: True
The problem is if you are running a 32-bit application on a 64-bit OS, the .Net framework automatically redirects the request from %WINDIR%\System32 to %WINDIR%\SysWOW64.
If you change your project to target 64-bit, this will solve your problem.
You can also resolve the problem by changing System32 to sysnative, but only if you leave the application as a 32-bit app:
string filePath = #"%WINDIR%\sysnative\inetsrv\config\applicationHost.config";
This might be due to file system redirection. AFAIK t happens either for 32/64 bit mismatch or in case of low-privilege (UAC) processes.
I know of now way of disabling that behavior using managed APIs. You need to use http://msdn.microsoft.com/en-us/library/windows/desktop/aa365743(v=vs.85).aspx and/or be a high privilege process.
If you change your project to target 64-bit, this is likely to solve your problem.
I can't reproduce your result. When I run this from an administrator command line prompt, I get exists = True.
string s = #"%WINDIR%/System32\inetsrv\config\applicationHost.config";
bool exists = File.Exists(Environment.ExpandEnvironmentVariables(s));
Console.WriteLine("exists = {0}", exists);
I'm running Windows Server 2008, 64-bit. .NET 4.0.

Which user's registry am I accessing which my program is being launched from my installer?

I have a system which includes an installer, a windows service and a configuration GUI program. The installer isn't your standard visual studio setup deployment project, but another program that I have coded. The installer launches the config program after the service is installed.
I've made a change to the config program that defaults a text box to a registry value in the HKEY_CURRENT_USER registry (which is from 3rd party software so I can't change the location of this value). This all works fine when I launch the config program from my start menu, however when the installer launches the program after it is complete, this value is not loaded from the registry.
Here's the code that launches the program after the installer has finished:
Process process = new Process();
process.StartInfo.FileName = Program.Installer.ConfigPath;
process.StartInfo.Arguments = Location.X.ToString() + " " + Location.Y.ToString();
process.Start();
while (!process.Responding)
Thread.Sleep(50);
Close();
Application.Exit();
Here's the code that gets the registry value:
_regKey = Registry.CurrentUser.OpenSubKey("Software\\" + _appName);
return _regKey.GetValue(key);
I've viewed both processes in task manager, and I can see no difference between the two at all. Both are being ran by the same user at the same path. The installer requires elevation, but I have elevated the config program separately and this has still worked.
Can anyone think of any other differences in a process that has been started by Windows and a process that has been called by another process?
Thanks,
Turns out that this was nothing to do with the registry at all. I moved my code around so that the registry value was loaded on the press of the "Next" button in the installer, rather than the start of the application. In my OnLoad function, there was a line which returns if a connection to a server was not initialised (which it wont be if it has not yet been set up at all). My code that was loading the value was AFTER this line of code and was therefore never being reached.
Just me being stupid.
Thanks

Categories

Resources