Retrieving Java installation directory in any situation using C# - c#

So I'm creating an installer for the Java Access Bridge for my application and it is required to find the Java installation directory. I was using this piece of code which worked..
public static string GetJavaInstallationPath()
{
try
{
string environmentPath = Environment.GetEnvironmentVariable("JAVA_HOME");
if (!string.IsNullOrEmpty(environmentPath))
{
return environmentPath;
}
string javaKey = "SOFTWARE\\JavaSoft\\Java Runtime Environment\\";
using (Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(javaKey))
{
string currentVersion = rk.GetValue("CurrentVersion").ToString();
using (Microsoft.Win32.RegistryKey key = rk.OpenSubKey(currentVersion))
{
return key.GetValue("JavaHome").ToString();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return null;
}
}
until.. I ran a clean Windows 7 64 bit install on my Virtual Machine and installed Java from java.com. It installed the 32 bit version of Java by default but I really thought it wouldn't matter because 32 bit would also require or the JAVA_HOME variable or the Registry Key. Well, this wasn't the case! There was no Registry Key, no entry in the PATH variable and there was no JAVA_HOME variable either. So this code wouldn't work! My question is, how would I detect the java installation directory even when it's the 32 bit Java version that's installed. There is nothing I know of that I can use..

You're forgetting about the registry path being different for 32bit application. See this MS article: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724072%28v=vs.85%29.aspx

Related

Accessing Registry Keys from .dll in C#

The environment I'm using might sound a bit messed up, so I will try to explain it at best.
I'm doing some experimental things with Electron. Right now, I have a simple .dll written in C# with using .NET Standard 2.0 as the base. On Electron's side, I'm using electron-edge-js, which, I think, works fine because I'm able to communicate with both of them.
So basic process goes like this,
I'm building my C# code to get my .dll's (I'm also adding reference dlls as well). Putting them into the same folder with Electron project. Starting the project to see how they did.
The problem lies at .dll's code. I'm using the following simple code,
public string RegisterUser(string username, string userkey) {
try {
RegistryKey key;
if (Microsoft.Win32.Registry.CurrentUser == null) return "Current user is null";
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(#"SOFTWARE\Test\TestFunctions");
if (key == null) return "Key is null";
key.SetValue("uid", username);
key.SetValue("upsw", userkey);
key.Close();
return "Done";
} catch (Exception e) {
return e.ToString();
}
}
However, whenever I call this method, it always returns "Current user is null" no matter what. I tried building my .exe and running it as administrator as well. I checked the privileges in Regedit as well. They all seem fine. I'm having a kinda hard time for such an easy code. A little help would be amazing, thanks!

How to find an EXE's install location - the proper way?

I am making a software in C# and MATLAB that calls another software (CMG) to do some processing. My problem is that the address of the software I have put in my program is only correct on my personal computer and not on the customers' computers (I don't know what would be the path to CMG software on their computer).
How can I provide a general form of the address in order to make it work on every computer?
The following is the path I call from my MATLAB software:
C:\Program Files (x86)\CMG\STARS\2011.10\Win_x64\EXE\st201110.exe
As you see it is in drive C and the version is 2011.10. So if customer's version is something else and it is installed on other drives, this path makes no sense.
Method 1
The registry keys SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall provides a list of where most applications are installed:
Note: It doesn't list all EXE applications on the PC as some dont require installation.
In your case I am pretty sure that CMG STARS will be listed and you will be able to search for it by iterating over all subkeys looking at the DisplayName value and fetching the InstallLocation.
Also note that this Uninstall registry key exists in 3 places in the registry:
1. SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall inside CurrentUser
2. SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall inside LocalMachine
3. SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall in LocalMachine
Here is an class that returns the installed location of an application:
using Microsoft.Win32;
public static class InstalledApplications
{
public static string GetApplictionInstallPath(string nameOfAppToFind)
{
string installedPath;
string keyName;
// search in: CurrentUser
keyName = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
installedPath = ExistsInSubKey(Registry.CurrentUser, keyName, "DisplayName", nameOfAppToFind);
if (!string.IsNullOrEmpty(installedPath))
{
return installedPath;
}
// search in: LocalMachine_32
keyName = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
installedPath = ExistsInSubKey(Registry.LocalMachine, keyName, "DisplayName", nameOfAppToFind);
if (!string.IsNullOrEmpty(installedPath))
{
return installedPath;
}
// search in: LocalMachine_64
keyName = #"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
installedPath = ExistsInSubKey(Registry.LocalMachine, keyName, "DisplayName", nameOfAppToFind);
if (!string.IsNullOrEmpty(installedPath))
{
return installedPath;
}
return string.Empty;
}
private static string ExistsInSubKey(RegistryKey root, string subKeyName, string attributeName, string nameOfAppToFind)
{
RegistryKey subkey;
string displayName;
using (RegistryKey key = root.OpenSubKey(subKeyName))
{
if (key != null)
{
foreach (string kn in key.GetSubKeyNames())
{
using (subkey = key.OpenSubKey(kn))
{
displayName = subkey.GetValue(attributeName) as string;
if (nameOfAppToFind.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return subkey.GetValue("InstallLocation") as string;
}
}
}
}
}
return string.Empty;
}
}
Here is how you call it:
string installPath = InstalledApplications.GetApplictionInstallPath(nameOfAppToFind);
To get the nameOfAppToFind you'll need to look in the registry at the DisplayName:
REF: I modified the above code from here to return the install path.
Method 2
You can also use the System Management .Net DLL to get the InstallLocation although it is heaps slower and creates "Windows Installer reconfigured the product" event log messages for every installed product on your system.
using System.Management;
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach (ManagementObject mo in mos.Get())
{
Debug.Print(mo["Name"].ToString() + "," + mo["InstallLocation"].ToString() + Environment.NewLine);
}
Getting the EXE's name
Neither of the above methods tell you the name of the executable, however it is quite easy to work out by iterating over all the files in the install path and using a technique I discuss here to look at file properties to detect the EXE with the correct File Description, eg:
private string GetFileExeNameByFileDescription(string fileDescriptionToFind, string installPath)
{
string exeName = string.Empty;
foreach (string filePath in Directory.GetFiles(installPath, "*.exe"))
{
string fileDescription = GetSpecificFileProperties(filePath, 34).Replace(Environment.NewLine, string.Empty);
if (fileDescription == fileDescriptionToFind)
{
exeName = GetSpecificFileProperties(filePath, 0).Replace(Environment.NewLine, string.Empty);
break;
}
}
return exeName;
}
Either method (1 or 2) you use I recommend that you save the location of exe name so you only do this operation once. In my opinion its better to use Method 1 as its faster and doesn't create all the "Windows Installer reconfigured the product." event logs.
Alternate Method using an Installer
If your application is being installed you could find out where CMG STARS is located during installation Using Windows Installer to Inventory Products and Patches:
Enumerating Products
Use the MsiEnumProductsEx function to enumerate Windows Installer applications that are installed in the
system. This function can find all the per-machine installations and
per-user installations of applications (managed and unmanaged) for the
current user and other users in the system. Use the dwContext
parameter to specify the installation context to be found. You can
specify any one or any combination of the possible installation
contexts. Use the szUserSid parameter to specify the user context of
applications to be found.
During installation you would find the exe path to CMG STARS and save a registry key with the value.
I discuss using this approach of saving an EXE's install path in the registry for updating applications here.
Tip
As mentioned in the comments, it is worthwhile you do a search in the registry for the EXE's name st201110.exe and see if the authors of the CMG STAR application already provide this information in a registry key you can access directly.
Plan B
If all else fails present the user with a FileOpenDialog and get them to specify the exe's path manually.
What if the 3rd party application is uninstalled or upgraded?
I mentioned to store the install path and exe name in the registry (or database, config file, etc) and you should always check the exe file exists before making any external calls to it, eg:
if (!File.Exists(installPath + exeName))
{
//Run through the process to establish where the 3rd party application is installed
}

Get registry value using C#

I am not able to retrieve a software's Installdir. I have tried GetValue and even OpenSubKey but everytime I get a NULL. I am using VS2008, .Net 3.5, 64bit machine, 32bit process setting.
private string GetInstallPath()
{
string keyValue = string.Empty;
Object key = Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\My Company\\My Tool", "Installdir", null);
...
}
key is returning NULL though there is a valid string there. Equivalent code works in VC++. Please provide your insight to the issue. What am I doing wrong for this supposedly easy task? I cannot use a 'Hive' as it's 4.0 standard. Code level help instead of links would be helpful.
VC++ equivalent
HKEY hkey = NULL;
LSTATUS status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\My Company\\My Tool\\", 0, KEY_READ, &hkey );
if ( status == ERROR_SUCCESS )
{
DWORD type;
char buff[ 100 ];
DWORD numBytes = sizeof( buff );
if ( RegQueryValueExA( hkey, REGISTRY_ENTRY, NULL, &type, (LPBYTE) buff, &numBytes ) == ERROR_SUCCESS )
{
...
}
You mentioned your machine is x64, and your app is 32 bit unless I misread. Given your environment the firs thing I would check is to be sure the key exists in the 64 bit node, HKCU\Software\My Company\... and not in the 32 bit node HKCU\Software\Wow6432Node\My Company\..., if your key exists in the 32 bit node, you will need to make sure your app is a 32 bit app, otherwise, you will need to make sure your app is 64 bit or you won't find the key.
The following code worked for me, running in 64 bit and found the key outside of the Wow6432Node. I don't understand why you can't user 'Hive', it works in both 3.5 and 4.0
RegistryKey regKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\VisualStudio\\10.0");
if (regKey != null)
{
object val = regKey.GetValue("FullScreen");
}
Update:
The following also worked for me, running .NET 3.5, if it's not a platform (x86 vs x64) issue, then it is possibly a permissions problem, make sure that the context under which your app is running has access to the registry key (try running the app as administrator or even system)
object test = Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\VisualStudio\\10.0", "FullScreen", null);

Registry keys handling 64 bit OS

I am using registry keys to access the path of an XML file from installed folder of my machine.
My machine has 32 bit OS. So I am using
using (RegistryKey pRegKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Folder\subfolder\key"))
{
if (pRegKey == null)
{
return;
}
else
// get path
But when I run it in 64 bit machine it is showing error, since I have not handled the exception case for 64 bit OS.
How can I handle it??
If your app is 32-bit and you want to install it both on 32-bit and 64-bit OS, use this:
string regPath = string.Format(#"SOFTWARE\{0}AppName\Folder\subfolder\key",
Environment.Is64BitProcess ? #"Wow6432Node\" : string.Empty());
using (RegistryKey pRegKey = Registry.LocalMachine.OpenSubKey(regPath))
{
.....

Get effective executable filename

A .NET application (managed) runs on Windows 7 64 bit. It is actually running on a 64 bit environment.
The application inspect running process (for example, calc.exe) which is located in c:\windows\syswow64\calc.exe.
So, why the function
Process.MainModule.Filename
returns c:\windows\system32\calc.exe? Is it possible to get the effective executable main module location, when is unredirected from SYSWOW64 directory?
What are possible workarounds? The quickest I wrote is the following snippet:
bool iWindows = pFilename.StartsWith(#"c:\windows\", StringComparison.InvariantCultureIgnoreCase);
bool iWindowsSystem32 = pFilename.StartsWith(#"c:\windows\system32\", StringComparison.InvariantCultureIgnoreCase);
if ((iWindows == true) || (iWindowsSystem32 == true)) {
string pActualFileName;
if (iWindowsSystem32 == true)
pActualFileName = pFilename.Replace(#"c:\windows\system32\", #"c:\windows\syswow64\");
else
pActualFileName = pFilename.Replace(#"c:\windows\", #"c:\windows\syswow64\");
Am I missing something?
Try getting the assembly and then getting the assembly location, such as
System.Reflection.Assembly.GetExecutingAssembly().Location
Try to call Wow64DisableWow64FsRedirection before the usage of Process.MainModule.Filename. Verifying that the program are running on 64-bit operation system with IsWow64Process or Environment.Is64BitOperatingSystem (if you use .NET 4.0) before usage of Wow64DisableWow64FsRedirection is recommended.
UPDATED: I am sure that you have a small error in your code or the problem can be on .NET runtines which you have installed. I tested your problem with respect of the following test code
using System;
using System.Diagnostics;
namespace Win64ProcesPath {
class Program {
static void Main (string[] args) {
Process myProcess = new Process ();
try {
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = "calc.exe";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start ();
System.Threading.Thread.Sleep (1000);
Console.WriteLine ("{0}", myProcess.MainModule.FileName);
Process p = Process.GetProcessById (myProcess.Id);
Console.WriteLine ("{0}", p.MainModule.FileName);
//Process p32 = Process.GetProcessById (8048);
//Console.WriteLine ("{0}", p32.MainModule.FileName);
}
catch (Exception e) {
Console.WriteLine (e.Message);
}
}
}
}
with .NET 4.0 and Visual Studio 2010 installed on Vindows 7 64-bit (x64). On Vindows 7 64-bit there are two version of calc.exe: one 32-bit under C:\Windows\SysWOW64\calc.exe and another 64-bit under C:\Windows\system32\calc.exe. How can easy verify the files has different file size (776,192 and 918.528 bytes). If I compile the program as 64-bit program it starts C:\Windows\system32\calc.exe and Process.GetProcessById(processId).MainModule.FileName shows also correct file name. One can also use Process.GetProcessById() to get correct path of 32-bit version of calc.exe which are started separately (see commented lines). So 64-bit versin of this program has no problem in my envoronment.
If you do have 32-bit application you will be able to access to the full filesystem after the call of Wow64DisableWow64FsRedirection, but you will not be able to access the memory of 64-bit programs and Process.MainModule will throw the excepion System.ComponentModel.Win32Exception with the code NativeErrorCode: 299 and the Message: "A 32 bit processes cannot access modules of a 64 bit process." To be able to get the full filename of 64-bit application you should use API with get you results produced from a 64-bit operation system component (like WMI and so on). But it's already another probelm, because how you wrote your program is 64-bit program.

Categories

Resources