I want to programmatically retrieve the version of an installed application (which is currently running), of which I have the name of the running process. If possible, retrieving the install directory would also be appreciated, but that is optional.
I've searched at a lot of places, and some questions looked similar, but they do not give me what I ask for.
To be a bit more specific, right now I want to do this for Visual Studio i.e. I have a WPF app, which is running alongside Visual Studio & given that I know the process name for Visual Studio i.e. "devenv", how can I get the version information of Visual Studio installed on my machine, from the WPF app? This is just an example, don't assume anything particular to Visual Studio. In the general case, we'd have an app running, for which we know the Process name & want its installed version.
Can you please provide the C# code for doing this?
This is gonna be simple. All kind of system related information will be present in Registry. (i.e) If you open regedit, you may find various HKEY. Now, please navigate to the following location.
" HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall "
You can find many folders inside this location, in which the name of the folder will be encrypted. Those folders indicates the installed application in the current machine.
In each folder there will be many key and data pair of values. In that you can find DisplayName and DisplayVersion. So this DisplayVersion gives you the actual version of your application.
So, How to achieve this through code?
RegistryKey rKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
List<string> insApplication = new List<string>();
if (rKey != null && rKey.SubKeyCount > 0)
{
insApplication = rKey.GetSubKeyNames().ToList();
}
int i = 0;
string version = "";
foreach (string appName in insApplication)
{
RegistryKey finalKey = rKey.OpenSubKey(insApplication[i]);
string installedApp = finalKey.GetValue("DisplayName").ToString();
if (installedApp == "Google Chrome")
{
version = finalKey.GetValue("DisplayVersion").ToString();
return;
}
i++;
}
Process.GetProcessesByName("DevEnv")[0].Modules[0].FileVersionInfo
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
This gets the version of the executing assembly.
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Public DTE As EnvDTE.DTE
Dim version As String
DTE = System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.9.0")
version = DTE.Version
MsgBox("The visual studio version is {0}", version)
Related
I have a C# WPF application, which is written in Visual Studio 2017 (15.9.9) using .Net 4.7. The solution for the application contains two projects - the WPF Project itself and also a Microsoft VS Installer Project that creates a .msi file on the build action.
I have stored the version information for the application project and can return it using the following method
public static string GetVersion()
{
try
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fvi.FileVersion;
return $"Version {version}";
}
catch(Exception ex)
{
//send error notif to IT dept.
Alert_IT(ex, GetCurrentMethod(), false);
return "0";
}
}
I would like to use the result of this to set the the version information in the Setup project when I build the solution - at the moment it has to be manually entered into the properties of the setup project.
Since we are planning on using setup projects for all our applications, it would be really nice to only have to alter the version in one place for all our projects, ensuring that there are no inconsistencies.
Is it possible to set the version on a setup project programmatically? It would have to be done before the .msi is created.
If this is not possible, do you have any other suggestions as to how to achieve the desired outcome - that the version information for the application need only be set in one place before it is built?
I have seen the advice here, but did not find it specific enough to be helpful.
I am trying to install Antlr4 on a new machine but I am getting the following build error:
C:\antlrtest\antlrtest\Reference\Antlr4\Antlr4.targets(129,5): error AC1000: Unknown build error: Object reference not set to an instance of an object.
This is the offending code:
<Antlr4ClassGenerationTask
ToolPath="$(Antlr4ToolLocation)"
BuildTaskPath="$(Antlr4BuildTaskLocation)"
OutputPath="$(IntermediateOutputPath)"
TargetLanguage="%(Antlr4.TargetLanguage)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
TargetNamespace="%(Antlr4.CustomToolNamespace)"
SourceCodeFiles="#(Antlr4)"
ContinueOnError="$(_IntellisenseOnlyCompile)"
TokensFiles="#(Antlr4Tokens)"
AbstractGrammarFiles="#(Antlr4AbstractGrammar)"
LanguageSourceExtensions="$(DefaultLanguageSourceExtension)"
GenerateListener="%(Antlr4.Listener)"
GenerateVisitor="%(Antlr4.Visitor)"
ForceAtn="%(Antlr4.ForceAtn)"
AbstractGrammar="%(Antlr4.Abstract)">
<Output ItemName="Antlr4GeneratedCodeFiles" TaskParameter="GeneratedCodeFiles" />
</Antlr4ClassGenerationTask>
I think I followed the correct procedure:
I installed the extension from the VS 2012 website for Antlr.
Then I edited the project file to point to the References.
Then I added a reference to the Runtime DLL.
Any help would be appreciated.
So I ran into this today and was pulling my hair out over it for quite some time. The solution for me was to install both the 32-bit and 64-bit versions of the Java SDK.
Initially I only had the 64-bit version installed. It immediately started working after I installed the 32-bit as well.
Hope that helps someone.
This error is caused by Antlr4 failing to find an appropriate version of Java. On a Windows machine, Antlr4 checks the registry first before it checks your environment variables to determine the suitable location of Java.
Shortly before I experienced the same problem, I had been consolidating the many instances of the Java Runtime Environment I had on my computer. I had many and I trimmed them down to only 1 instance of a 64b JRE and 32b JRE each. I removed the rest by just deleting their folders. Subsequently I checked that my user and system environment variables (specifically JAVA_HOME) still pointed to a valid Java directory.
But I failed to realise that there are registry entries that have to be updated too. Possibly a reinstall of Java would fix the registry entries, but I reverted to just fixing them manually.
So the appropriate place in the Antlr4 code is at https://github.com/tunnelvisionlabs/antlr4cs/blob/master/runtime/CSharp/Antlr4BuildTasks/Antlr4ClassGenerationTaskInternal.cs#L144 .
private string JavaHome
{
get
{
#if !NETSTANDARD
string javaHome;
if (TryGetJavaHome(RegistryView.Default, JavaVendor, JavaInstallation, out javaHome))
return javaHome;
if (TryGetJavaHome(RegistryView.Registry64, JavaVendor, JavaInstallation, out javaHome))
return javaHome;
if (TryGetJavaHome(RegistryView.Registry32, JavaVendor, JavaInstallation, out javaHome))
return javaHome;
#endif
if (Directory.Exists(Environment.GetEnvironmentVariable("JAVA_HOME")))
return Environment.GetEnvironmentVariable("JAVA_HOME");
throw new NotSupportedException("Could not locate a Java installation.");
}
}
#if !NETSTANDARD
private static bool TryGetJavaHome(RegistryView registryView, string vendor, string installation, out string javaHome)
{
javaHome = null;
string javaKeyName = "SOFTWARE\\" + vendor + "\\" + installation;
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView))
{
using (RegistryKey javaKey = baseKey.OpenSubKey(javaKeyName))
{
if (javaKey == null)
return false;
object currentVersion = javaKey.GetValue("CurrentVersion");
if (currentVersion == null)
return false;
using (var homeKey = javaKey.OpenSubKey(currentVersion.ToString()))
{
if (homeKey == null || homeKey.GetValue("JavaHome") == null)
return false;
javaHome = homeKey.GetValue("JavaHome").ToString();
return !string.IsNullOrEmpty(javaHome);
}
}
}
}
#endif
Your .\packages\Antlr4.CodeGenerator.4.6.3\build\Antlr4.CodeGenerator.targets file (adjust for correct version number) has lines to set the JavaVendor and JavaInstallation variables:
<Antlr4JavaVendor Condition="'$(Antlr4JavaVendor)'==''">JavaSoft</Antlr4JavaVendor>
<Antlr4JavaInstallation Condition="'$(Antlr4JavaInstallation)'==''">Java Runtime Environment</Antlr4JavaInstallation>
So, in my case at least, the appropriate registry settings were located in HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
To fix the incorrect registry:
Ensure that CurrentVersion's value (in my case 1.8.0_91) has a corresponding key
Ensure that the JavaHome key in HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.8.0_91 (replace with your version) has a directory path to a valid Java installation.
If you're running a 64b Windows, ensure this for both the 64b and 32b versions of the registry (see https://support.microsoft.com/fr-dz/help/305097/how-to-view-the-system-registry-by-using-64-bit-versions-of-windows for how to view the 32b registry on a 64b machine).
Keep in mind, that Visual Studio is a 32b process and that, by default, it will run Antlr4 by looking for a 32b version of the JRE. If, for some reason, you're building the solution outside of Visual Studio with 64b processes, the 64b version of the registry is used.
I am using Visual Studio 2022 and I had to compile a project that used Antlr4.4.5.3. The grammar file was configured to generate a Visitor but it did not work. I had the same error as you.
In my case I had an Open JDK in my JAVA_HOME environment variable. I also had an Oracle Java JDK installed. So, I deduced that Antl4 did not like my JAVA_HOME pointing to the Open JDK.
So I deleted the JDK and JRE folders (that pointed to the Open JDK) at HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft in the registry allowing me to compile my project successfully.
I deduce that Antlr then used the HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment folder where the configuration is set when you install an Oracle Java JDK version.
A synopsis of my question:
Is it possible to use your own, custom variables (the way that you can use [TARGETDIR]) in the Registry screen of a Windows Setup project in VS2010? Specifically, I need to store my assembly's strong name and assembly version in the registry, in order to register a COM object on a machine without the installing user having admin rights.
I already tried using a custom action, and I'd rather not continue down that road if possible.
Here are the specifics, and what I've tried:
Recently, my employer started blindly removing all employees' admin rights from their machines.
I had created a COM-exposed C# class that I'd been using on a few of my workstations, which is no longer able to be registered, because I no longer have the appropriate permissions under HKEY_CLASSES_ROOT.
Through Googling, I found out how to register all of the appropriate keys under HKCU*, but now I'd like to implement this in my deployment project.
I understand how to use the Registry screen within Windows Setup, but there are custom keys/values that need to be stored (install folder, assembly strong name, version).
I could use a custom action, but ideally, I want Windows Setup to manage my registry settings, because (a) it's better than I am at automatically removing all the proper keys/values upon uninstall, (b) during the install, registry changes are transactional & rolled back upon install error, and (c) the logic for registry key install/removal/transactions is already written by Microsoft, and I won't have to rewrite it myself.
The project was in VS2008 until today, but I just upgraded it to VS2010, so perhaps something has changed between 2008 and 2010 that might allow this behavior.
So, rather than using a custom action, is there a better way to do this?
EDIT: I found this answer, which seems to suggest that you can access the Windows Install "Registry" table within your install project. I'm not sure how to do access it, though. In the past, I seem to recall that you could access the MSI databases from a special external tool (Orca), but I don't know if you can access these tables in your setup project.
EDIT 2: Ah, I may be on to something; perhaps a post-build event:
Use Orca to edit msi from command line?,
Examples of Database Queries Using SQL and Script,
WiRunSQL.vbs
* Run RegAsm twice - once with /codebase and once without; both times with the /regfile option. Then merge both files together (removing duplicates), and replace all HKCR references with HKCU\Software\Classes.
Yes, this can be done*.
First, create a Console executable that will be run as part of a post-build event of the Windows Setup project. This modifies the Registry table in the MSI file that has been built by VS2010.
Note: You must add a reference to "Microsoft Windows Installer Object Library" under COM, for the below code to compile.
using System;
using WindowsInstaller;
using System.Runtime.InteropServices;
using System.Reflection;
namespace Post_Setup_Scripting
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Incorrect args.");
return;
}
//arg 1 - path to MSI
string PathToMSI = args[0];
//arg 2 - path to assembly
string PathToAssembly = args[1];
Type InstallerType;
WindowsInstaller.Installer Installer;
InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);
Assembly Assembly = Assembly.LoadFrom(PathToAssembly);
string AssemblyStrongName = Assembly.GetName().FullName;
string AssemblyVersion = Assembly.GetName().Version.ToString();
string SQL = "SELECT `Key`, `Name`, `Value` FROM `Registry`";
WindowsInstaller.Database Db = Installer.OpenDatabase(PathToMSI, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeDirect);
WindowsInstaller.View View = Db.OpenView(SQL);
View.Execute();
WindowsInstaller.Record Rec = View.Fetch();
while (Rec != null)
{
for (int c = 0; c <= Rec.FieldCount; c++)
{
string Column = Rec.get_StringData(c);
Column = Column.Replace("[AssemblyVersion]", AssemblyVersion);
Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName);
Rec.set_StringData(c, Column);
View.Modify(MsiViewModify.msiViewModifyReplace, Rec);
Console.Write("{0}\t", Column);
Db.Commit();
}
Console.WriteLine();
Rec = View.Fetch();
}
View.Close();
GC.Collect();
Marshal.FinalReleaseComObject(Installer);
Console.ReadLine();
}
}
}
The "variables" that we are going to use in the Windows Setup Registry screen get replaced in these lines of the above code; this could be adapted to any items that are necessary.
string Column = Rec.get_StringData(c);
Column = Column.Replace("[AssemblyVersion]", AssemblyVersion);
Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName);
Second, create a .reg file that contains the registry keys you want to create upon install. In the code above, we modify the MSI database in the post-build by replacing all instances of [AssemblyVersion] with the assembly version, and [AssemblyStrongName] with the assembly's strong name.
[HKEY_CURRENT_USER\Software\Classes\Record\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\[AssemblyVersion]]
"Class"="MyClass.MyClass"
"Assembly"="[AssemblyStrongName]"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="[TARGETDIR]MyClass.dll"
Third, import the .reg file into the Windows Setup registry screen in VS2010 by right-clicking "Registry On Target Machine", and clicking "Import".
Finally, call the post-build executable in the "PostBuildEvent" property of the setup project:
"C:\Path\To\Exe\Post-Setup Scripting.exe" [Path to MSI] [Path To DLL to extract strong name/version]
* This is a little different than using [TARGETDIR], because [TARGETDIR] gets resolved at install time, and these "variables" will get resolved at build time. For my solution, I needed to resolve at build time, because my version number increments with each build.
On one of my machines, I get a return value of null from any GetLocalWorkspaceInfo call. I have isolated to problem to where it even fails for this simple program:
namespace WorkstationTest
{
using Microsoft.TeamFoundation.VersionControl.Client;
class Program
{
static void Main()
{
string workspaceLocalPath = #"C:\Dev";
var info = Workstation.Current
.GetLocalWorkspaceInfo(workspaceLocalPath);
// info is always null here
}
}
}
What I have already checked:
The exact same code works on my other machine the way it should.
I have verified that I have a workspace at C:\Dev
I have created a new workspace and in a different directory and changed the workspaceLocalPath variable in the code to match.
I have consulted the documentation which states that the return value will be null if the path is not in a workspace. From the above image, the path should be in a workspace.
Yet, everything seems to suggest this should work. Is there anything I could be missing?
After migrating from TFS2013 to TFS2017 in the company I work for I had the same problem with Workstation.Current.GetLocalWorkspaceInfo.
What worked for me is a call to Workstation.EnsureUpdateWorkspaceInfoCache:
TfsTeamProjectCollection tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("<your-tfs-uri-here>"));
VersionControlServer tfServer = tpc.GetService<VersionControlServer>();
Workstation.Current.EnsureUpdateWorkspaceInfoCache(tfServer, tfServer.AuthorizedUser);
I added the above code lines to the constructor of my TFS proxy class that uses GetLocalWorkspaceInfo.
When executing tf workspaces (on my computer) in the Visual Studio 2010 command prompt it says No workspace matching * found on this computer, but when executing the same command in Visual Studio 2012 it returns back all my expected workspaces.
The issue can be resolved by doing any of the following:
Reference the version of the Microsoft.TeamFoundation.VersionControl.Client dll that was connected with Visual Studio 2012 instead of the dll connected with Visual Studio 2010.
Open Visual Studio 2010 and connect it to TFS to where it will create the workspaces for Visual Studio 2010
I know this is an old post, but just like to share the workaround that we have, by using VersionControlServer.QueryWorkspaces to query all the workspaces for the user on his/her machine.
private static Workspace FindWorkspaceByPath(TfsTeamProjectCollection tfs, string workspacePath)
{
VersionControlServer versionControl = tfs.GetService<VersionControlServer>();
WorkspaceInfo workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(workspacePath);
if (workspaceInfo != null)
{
return versionControl.GetWorkspace(workspaceInfo);
}
// No Workspace found using method 1, try to query all workspaces the user has on this machine.
Workspace[] workspaces = versionControl.QueryWorkspaces(null, Environment.UserName, Environment.MachineName);
foreach (Workspace w in workspaces)
{
foreach (WorkingFolder f in w.Folders)
{
if (f.LocalItem.Equals(workspacePath))
{
return w;
}
}
}
throw new Exception(String.Format("TFS Workspace cannot be determined for {0}.", workspacePath));
}
In my case, this issue occurred because of VersionControl.config file put under TFS cache folder (C:\Users\DeepakR\AppData\Local\Microsoft\Team Foundation\5.0\Cache\Volatile\0cb76a25-2556-4bd6-adaa-5e755ac07355_http) goes for a toss i.e. the configured workspace information weren't available as expected.
So, it basically needs a refresh of VersionControl.config file. Auto Refresh happens when Visual Studio gets loaded again i.e. it pulls the configured workspace information from Server and updates the config file or even if we execute tf command utility (tf.exe workspaces /collection:TFSURL)
Microsoft.TeamFoundation.VersionControl.Client's (v12.0.0.0) Workstation class has a function EnsureUpdateWorkspaceInfoCache which will do the same trick
VersionControlServer vcs = (VersionControlServer)tpc.GetService(typeof(VersionControlServer));
Workstation.Current.EnsureUpdateWorkspaceInfoCache(vcs, Environment.UserName);
https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.workstation.ensureupdateworkspaceinfocache(v=vs.120).aspx
Hope the suggestion helps to resolve the issue.
I had this issue recently (today) using Visual Studio 2017, plus several other versions installed and a number of local workspaces.
I ended up updating the 'Team Foundation Server Client' NuGet package to the latest version (15.x) through the 'Manage NuGet Packages' menu and that fixed it.
I did also remove the existing project references first but that part might depend on what you need.
Simply run with the tricks.
Nothing is going to work properly without a proper DLL reference. The below had fixed the same issue i had for 5 days as it was screwing my time up.
Place the below DLL's in the bin folder of your project and give a reference to the whole solution for all the DLL's. If any error comes up like 'Reference could not be given' ignore it and skip that DLL from giving reference instead just place also the error creating DLL in bin folder which the project will automatically take during build
DLL's:
Microsoft.TeamFoundation.Client.dll
Microsoft.TeamFoundation.Common.dll
Microsoft.TeamFoundation.Core.WebApi.dll
Microsoft.TeamFoundation.TestManagement.Client.dll
Microsoft.TeamFoundation.TestManagement.Common.dll
Microsoft.TeamFoundation.Work.WebApi.dll
Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
Microsoft.TeamFoundation.WorkItemTracking.Client.dll
Microsoft.TeamFoundation.WorkItemTracking.Common.dll
Microsoft.TeamFoundation.WorkItemTracking.Controls.dll
Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll
Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll
Microsoft.VisualStudio.Services.Client.Interactive.dll
Microsoft.VisualStudio.Services.Common.dll
Microsoft.VisualStudio.Services.WebApi.dll
Microsoft.WITDataStore32.dll
Microsoft.WITDataStore64.dll
The above dll's can be found in the below path if the System is installed with MTM or TFS
Path: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer
In my C:\Users\<username>\AppData\Local\Microsoft\Team Foundation folder I had 2 folders:
7.0
8.0
Within the 8.0 folder was the following folder:
\Cache\Volatile\c1dbda02-c575-4dd2-b221-e83f7cb63665_http
But within the 7.0 folder the \Cache\Volatile folder was empty
So all I did was copy across the c1dbda02-c575-4dd2-b221-e83f7cb63665_http folder into 7.0\Cache\Volatile\
After this GetLocalWorkspaceInfo call returned the workspace info successfully
This is how to find workspace when you have server path:
Workspace[] workspaces = _versionControl.QueryWorkspaces(null, Environment.UserName, Environment.MachineName);
return workspaces.FirstOrDefault(w => !string.IsNullOrEmpty(w.TryGetLocalItemForServerItem(ConstDefaultFlowsTfsPath)));
Where ConstDefaultFlowsTfsPath is server path with "$" for instance : "$/MyCompany/Services/DiagnosticsFlows"
You could also replace the last line to:
return workspaces.FirstOrDefault(w => !string.IsNullOrEmpty(w.GetServerItemForLocalItem(myLocalPath)));
and that should work for you too.
In Windows using C#, how can I get the installation path of a software (for example consider NUnit or any other software like MS word, etc.) from my project? Also how to set the path variables that we set in Environment variables so that we can run the application just by giving in command prompt.
Like if I install NUnit in "C:\Program Files" I can run it by giving 'NUnit' in cmd prompt but if I install in a different location I can't do the same.
I need to get the location or path of NUnit or any other software installed in my system (having Windows XP) from my project.
EDIT:
Like I can get the path of installed program from registry.
HKEY_CURRENT_USER->SOFTWARE
Use the system and application classes. This will give you all sorts of information.
EG: Application.ExecutablePath
It also provides methods to do what you want to.
Edit: Also see registry read/write instructions here:
http://www.c-sharpcorner.com/UploadFile/sushmita_kumari/RegistryKeys102082006061720AM/RegistryKeys1.aspx?ArticleID=0ce07333-c9ab-4a6a-bc5d-44ea2523e232
Application.ExecutablePath (includes filename)
Application.StartupPath (not includes filename)
This will give you the path where the application started. Hopefully it will be the installation path.
string appFileName = Environment.GetCommandLineArgs()[0];
will give you the full path of the executable and
string directory = Path.GetDirectoryName(appFileName);
extracts the directory.
string envPath = Environment.GetEnvironmentVariable("PATH");
Environment.SetEnvironmentVariable(envPath + ";" + yourPath);
edits the PATH environment variable for the current process.
Application.StartupPath is used to get installation location in c#.
Like if i install Nunit in "C:\Program
Files" i can run it by giving 'nunit'
in cmd prompt but if i install in a
different location i cant do the same.
May be you are using Windows Vista, which can search in Program Files, but won't look in other folders.
In windows using C#, how to get the
installation path of a software(for
example consider nunit).?
It depends, how you are installing the application. The installer knows the path, you may program the installer to write that path to somewhere, say registry.
Also how to set the path variables
that we set in Environment variables
so that we can run the application
just by giving in command prompt.
How do I get and set Environment variables in C#?
Steps to extract value from registry are shown in following code snippet.
You may already know that there are no standard rules for applications to place their installation info.
The steps shown below are for COM based applications where the appplication must provide Local executable path in a reasonably standard manner.
For non-com applications, check to see if some data can be extracted from installed applications cache.
I hate to admit that the solution is not as elegant as I want it to be. Each subkey has to opened in series and opening in single method does not work.
//string hiveName = #"CLSID"; // for 64 bit COM 7applications
string hiveName = #"WOW6432Node\CLSID"; // for 32 bit COM applications
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(hiveName))
{
if (key != null) {
using (RegistryKey key2 = key.OpenSubKey("{<YourAppGUID>}"))
{
if (key2 != null) {
using (RegistryKey key3 = key2.OpenSubKey("LocalServer32"))
{
if (key3 != null) {
return key3.GetValue("").ToString();
}
}