Platform target x86 and Any CPU - c#

I have small problem with simple code. This code is working properly on "x86" mode but not on "Any CPU" mode, maybe it is possible to run one class on "x86" and another class on "Any CPU" mode? Code:
namespace Software_Info_v1._0
{
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
public class Adobe
{
public string GetAdobeVersion()
{
try
{
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
foreach (string versionNumber in acroReadVersions)
{
Console.WriteLine("Acrobat Reader version: " + versionNumber);
}
}
}
}
catch
{
}
return null;
}
}
}

This is because of registry redirection.
The structure of the registry is different for 32-bit and 64-bit OS.
See this MSDN article for more information.
See also this SO thread.
Assuming you are running your application on a 64-bit machine, compiling for x86 target makes your program run using WOW64 mode (32-bit process on 64-bit) and you're reading keys under the Wow6432Node. See Weird behaviour when reading registry in C#

When running as 32bit, the registry key gets redirected. When you run as 64bit, it won't get redirected, and thus won't hit the key to which adobe's registry entry got redirected anymore.
So I'd create a Find32BitRegEntry(string path) function, that does nothing on 32bit, and adds the redirect on x64.

The registry keys can be in a different place on 64 bit machines - see this. (Notice that RegistryKey in your sample code comes from Microsoft.Win32 ?)
I think you need to use a Registry Redirector, there's some talk about it over here.

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.

DriverPackagePreinstall to work on 64 bit (compiled to 32 bit)

Is there a way I can compile an application which calls the DriverPackagePreinstall() (using Pinvoke) in such a way that it can work on 64-bit devices (Windows 7) even though it's targeted to 32bit?
The reason being it will be run as part of an installer of a much bigger application (using Windows Installer Project), which will target 32 bit but must run on a 64 bit platform also.
Here is my code:
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace MyDriver
{
class Program
{
static void Main(string[] args)
{
if (args.Count() == 0)
{
Console.WriteLine("Please specify filename!");
return;
}
int result= DriverPackagePreinstall(args[0], 0);
if (result == 0)
{
Console.WriteLine("Success");
} else {
Console.WriteLine("Error: 0x{0}", result.ToString("X8"));
}
}
[DllImport("DIFxAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Int32 DriverPackagePreinstall(
[MarshalAs(UnmanagedType.LPTStr)] string DriverPackageInfPath,
Int32 Flags);
}
}
}
If I build this targeting x86, and try to run on a 64-bit machine, I get error E0000235 (ERROR_IN_WOW64). This error goes away if I build targeting x64.
Now I don't mind compiling it twice and letting the installer decide which to install based on the platform it's being installed to. However, if I try to build the installer while including the 64-bit version I get the error,
263 File 'MyDriver.x64.exe' targeting 'AMD64' is not compatible with the project's target platform 'x86'
Alternatively a way of getting the Installer to overlook this error at build time (and run it anyway when the project is installing) would be good.
I worked around this by adding both the 64-bit and 32-bit versions of the application to a self-extracting zip-file together with a batch file which decides which one to execute.
The self-extractor is a 32-bit exe so as long no one tells Visual Studio that it contains a 64-bit one, it works.

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.

Regedit shows keys that are not listed using GetSubKeyNames()

I've checked some other replies on SO but as far I can see, this is a different issue than the hits I got.
When I open RegEdit, I can see a set of keys but when I list them from my program using e.g.:
Registry.LocalMachine.OpenSubKey(#"SOFTWARE").GetSubKeyNames()
some of them are missing. I thought it might to do with the access rights so I checked .CurrentUser too. The same behavior can be experienced there. A few of the subkeys are just not listed.
What am I missing?
Is your OS x64? If that is the case, for "LocalMachine\Software" there are two different nodes: Normal for x64 apps and Wow6432Node for x86 apps.
A sample application to demonstrate the above.
using System;
using Microsoft.Win32;
namespace ConsoleApplication1
{
internal class Program
{
public static void Main()
{
String[] values = Registry.LocalMachine.OpenSubKey(#"SOFTWARE").GetSubKeyNames();
foreach (String value in values)
Console.WriteLine(value);
}
}
}
This is the output of the code on my machine when the console application is built in x86:
Adobe
AGEIA Technologies
Alcohol Soft
Apple Computer, Inc.
Apple Inc.
Aureal
Avira
Azureus
BazisSoft
C07ft5Y
Canon
Citrix
...
This is the output on my machine when the console application is built in x64:
7-Zip
AGEIA Technologies
Apple Computer, Inc.
Apple Inc.
ATI Technologies
Canon
Classes
Clients
...
As you see, the outputs vary a lot based on whether the application is x86 or x64.
EDIT:
A similar question was asked on StackOverflow previously.

How to get list of all startup processes from Registry using C# on Windows 7 64 bit?

Hi guys I have a strange issue.
I am trying to get list of all startup programs from Registry - LocalMachine,CurrentUser, subkeys Run, RunOnce, RunOnceEx. And after that I can get list of links in Startup folder
For Win64 I found that startup programs are in this key
LocalMachine/Software/Wow6432Node/Microsoft/Windows/CurrentVersion/Run
The problem is in this code, running it I get List of apps which are in different Subkey LocalMachine\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run instead of the described bellow LocalMachine\Software\Microsoft\Windows\CurrentVersion\Run
Is that normal?
Microsoft.Win32.RegistryKey key;
key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", false);
foreach (string appName in key.GetValueNames())
{
try
{
MessageBox.Show(appName);
}
catch (Exception ex)
{
}
}
I tryed using this WMI solution but it didnt get all startup apps. That's why i decided to get them manually from the Registry.
Is this script correct and why it doesn't do what it is supposed to do?
Is there any other way to get all startup apps and processes?
Thanks
On a 64-bits windows OS, there are 2 distinct HKLM\Software hives. One for 64-bits apps (which is HKLM\Software) and one for 32-bits apps (which is HKLM\Software\Wow6432Node when viewed from a 64-bits apps. It is viewed as HKLM\Software for a 32-bits apps).
If you compile your .Net application as MSIL or x64, you could access the 32-bit software hive by adding Wow6432node to the registry path.
Otherwise, you could also compile as x86 and run in 32-bits.
Hope this help

Categories

Resources