I am trying to figure out how to check if a webcam/video capture device is already being used by another application without actually activating it.
My current approach is to use the AForge.NET library and using the .IsRunning property of the VideoCaptureDevice object like this:
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo videoDevice in videoDevices)
{
VideoCaptureDevice camera new AForge.Video.DirectShow.VideoCaptureDevice(videoDevice.MonikerString);
Debug.Print(camera.IsRunning)
}
I guess the IsRunning property only works on VideoCaptureDevices that have been started using the library and I need lower-level DirectShow access to the device.
While there are many ways to use DirectShow in C#, I have been unable to find a way to check the state even using DirectShow in C++. Is there some magic I need to perform here?
Thanks
Tobias Timpe
I'm not entirely sure if this will be helpful to you, but I found your question because I wanted to write a custom app to control my busylight. This is very much 'Works On My Machine' certified - it's not an attempt to give a general answer. However, I figure it may help you, and possibly the next person who comes across this page while googling...
private static bool IsWebCamInUse()
{
using (var key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged"))
{
foreach (var subKeyName in key.GetSubKeyNames())
{
using (var subKey = key.OpenSubKey(subKeyName))
{
if (subKey.GetValueNames().Contains("LastUsedTimeStop"))
{
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long) subKey.GetValue("LastUsedTimeStop") : -1;
if (endTime <= 0)
{
return true;
}
}
}
}
}
return false;
}
When using System.Media, there is something called SystemSounds where you can easily play a couple of operating system sounds:
System.Media.SystemSounds.Asterisk.Play();
System.Media.SystemSounds.Beep.Play();
System.Media.SystemSounds.Exclamation.Play();
System.Media.SystemSounds.Hand.Play();
System.Media.SystemSounds.Question.Play();
Unfortunately, there are only these five options, and in Windows 10, three of them are the same while one of them doesn't even play anything.
What I really want to do is play the Notification sound, as defined in the Sound panel (seen here):
Does anyone know how to do this?
Solution found. Code here:
using System.Media;
using Microsoft.Win32;
public void PlayNotificationSound()
{
bool found = false;
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(#"AppEvents\Schemes\Apps\.Default\Notification.Default\.Current"))
{
if (key != null)
{
Object o = key.GetValue(null); // pass null to get (Default)
if (o != null)
{
SoundPlayer theSound = new SoundPlayer((String)o);
theSound.Play();
found = true;
}
}
}
}
catch
{ }
if (!found)
SystemSounds.Beep.Play(); // consolation prize
}
You can browse the keys in the registry editor to see the other sounds. Also, this example is coded to work for Windows 10, and I'm not sure what the registry structure is for other versions of Windows, so you'll need to double check what OS the user is using if you're trying to code for multiple platforms.
I'm writing a windows form application (c#) and I need to detect whether the user have "Microsoft-Edge" installed in his/her machine or not.
I'm currently using this registry location:
[HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\Microsoft.MicrosoftEdge_20.10240.16384.0_neutral__8wekyb3d8bbwe]
"Path"="C:\\Windows\\SystemApps\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
With a regex after the "Microsoft.MicrosoftEdge". If the "path" exist then I know edge is installed.
Is there a better way to detect edge? would it be better if I detect that I'm running on Windows 10 and by default Win10 come with edge? What is the best way for that?
In case you want to have a small program getting that version number:
static void Main(string[] args)
{
string EdgeVersion = string.Empty;
//open the registry and parse through the keys until you find Microsoft.MicrosoftEdge
RegistryKey reg = Registry.ClassesRoot.OpenSubKey(#"Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages");
if (reg != null)
{
foreach (string subkey in reg.GetSubKeyNames())
{
if (subkey.StartsWith("Microsoft.MicrosoftEdge"))
{
//RegEx: (Microsoft.MicrosoftEdge_)(\d +\.\d +\.\d +\.\d +)(_neutral__8wekyb3d8bbwe])
Match rxEdgeVersion = null;
rxEdgeVersion = Regex.Match(subkey, #"(Microsoft.MicrosoftEdge_)(?<version>\d+\.\d+\.\d+\.\d+)(_neutral__8wekyb3d8bbwe)");
//just after that value, you need to use RegEx to find the version number of the value in the registry
if ( rxEdgeVersion.Success )
EdgeVersion = rxEdgeVersion.Groups["version"].Value;
}
}
}
Console.WriteLine("Edge Version(empty means not found): {0}", EdgeVersion);
Console.ReadLine();
}
Thank you for the registry link for finding the version number.
If you're on the desktop or mobile version of Windows 10 then Edge is pre-installed and can't be uninstalled.
To detect if running on Windows 10 use the System.Environment.OSVersion property or the Version Helper functions. (See also https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx)
If you want to detect the default browser you should see How to determine the Windows default browser (at the top of the start menu)
Relevant to 15.11.2016:
The only way that I found working is to use this registry location:
[HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\Microsoft.MicrosoftEdge_20.10240.16384.0_neutral__8wekyb3d8bbwe]
"Path"="C:\\Windows\\SystemApps\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
With a regex after the "Microsoft.MicrosoftEdge".
If the "path" exist then I know edge is installed.
In reference to other answers: my installation of Windows 10 does not have this key: Microsoft.MicrosoftEdge_20.10240.16384.0_neutral__8wekyb3d8bbwe
In:
[HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\]
Instead, it has the following keys:
Microsoft.MicrosoftEdge_38.14393.0.0_neutral__8wekyb3d8bbwe
Microsoft.MicrosoftEdge_40.15063.674.0_neutral__8wekyb3d8bbwe
The following code could be used to detect if Edge is installed:
class Program
{
static void Main(string[] args)
{
var edgeFound = false;
using (var key = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(#"Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\"))
{
if (key != null)
{
foreach (var subkey in key.GetSubKeyNames())
{
if (subkey.StartsWith("Microsoft.MicrosoftEdge_"))
{
edgeFound = true;
break;
}
}
}
}
Console.Write(edgeFound);
Console.ReadLine();
}
}
What is the best way to find out if reportviewer and WindowsInstaller-KB893803-v2-x86 is installed on a PC? Is there a way to find out what public key to use to find out if a specific program is installed on a PC? (Tried this, didn't work)
Best Way To Determine If .NET 3.5 Is Installed
This is how to check if .NET 3.5 is installed, but i take it you need a another public key to know if report viewer is installed, but I don't know how to get the public key.
All I can think of is to check if the installation directory exists on the computer, would that be an acceptable way to check?
You could check in the Registry
public bool IsInstalled()
{
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
return registryBase.OpenSubKey("Software\\Microsoft\\ReportViewer\\v2.0.50727") != null;
}
return false;
}
In my machine (Win7 & Server 2012), the registry key is different.
bool exist = false;
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
exist = registryBase.OpenSubKey("Software\\Wow6432Node\\Microsoft\\.NETFramework\\v2.0.50727\\AssemblyFoldersEx\\ReportViewer v10") != null;
}
You could also query the GAC for the assemblies, as shown in this SO question.
I did a Regshot diff on a MS Report Viewer version 10 install to find the key because neither of the others posted here were working.
Here is the actual diff results on a fresh windows server VM.
Anyways, the key I found for this version was:
SOFTWARE\Wow6432Node\Microsoft\ReportViewer\v10.0
The code I used:
public bool IsInstalledReportViewer()
{
try
{
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
// check the two possible reportviewer v10 registry keys
return registryBase.OpenSubKey(#"Software\Microsoft\ReportViewer\v2.0.50727") != null
|| registryBase.OpenSubKey(#"Software\Wow6432Node\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\ReportViewer v10") != null
|| registryBase.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\ReportViewer\v10.0") != null;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
// put proper exception handling here
}
return false;
}
How to get the applications installed in the system using c# code?
Iterating through the registry key "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" seems to give a comprehensive list of installed applications.
Aside from the example below, you can find a similar version to what I've done here.
This is a rough example, you'll probaby want to do something to strip out blank rows like in the 2nd link provided.
string registry_key = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using(Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach(string subkey_name in key.GetSubKeyNames())
{
using(RegistryKey subkey = key.OpenSubKey(subkey_name))
{
Console.WriteLine(subkey.GetValue("DisplayName"));
}
}
}
Alternatively, you can use WMI as has been mentioned:
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
But this is rather slower to execute, and I've heard it may only list programs installed under "ALLUSERS", though that may be incorrect. It also ignores the Windows components & updates, which may be handy for you.
I wanted to be able to extract a list of apps just as they appear in the start menu. Using the registry, I was getting entries that do not show up in the start menu.
I also wanted to find the exe path and to extract an icon to eventually make a nice looking launcher. Unfortunately, with the registry method this is kind of a hit and miss since my observations are that this information isn't reliably available.
My alternative is based around the shell:AppsFolder which you can access by running explorer.exe shell:appsFolder and which lists all apps, including store apps, currently installed and available through the start menu. The issue is that this is a virtual folder that can't be accessed with System.IO.Directory. Instead, you would have to use native shell32 commands. Fortunately, Microsoft published the Microsoft.WindowsAPICodePack-Shell on Nuget which is a wrapper for the aforementioned commands. Enough said, here's the code:
// GUID taken from https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FOLDERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FOLDERID_AppsFolder);
foreach (var app in (IKnownFolder)appsFolder)
{
// The friendly app name
string name = app.Name;
// The ParsingName property is the AppUserModelID
string appUserModelID = app.ParsingName; // or app.Properties.System.AppUserModel.ID
// You can even get the Jumbo icon in one shot
ImageSource icon = app.Thumbnail.ExtraLargeBitmapSource;
}
And that's all there is to it. You can also start the apps using
System.Diagnostics.Process.Start("explorer.exe", #" shell:appsFolder\" + appModelUserID);
This works for regular Win32 apps and UWP store apps. How about them apples.
Since you are interested in listing all installed apps, it is reasonable to expect that you might want to monitor for new apps or uninstalled apps as well, which you can do using the ShellObjectWatcher:
ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
Edit: One might also be interested in knowing that the AppUserMoedlID mentioned above is the unique ID Windows uses to group windows in the taskbar.
2022: Tested in Windows 11 and still works great. Windows 11 also seems to cache apps that aren't installed per se, portable apps that don't need installing, for example. They appear in the start menu search results and can also be retrieved from shell:appsFolder as well.
I agree that enumerating through the registry key is the best way.
Note, however, that the key given, #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", will list all applications in a 32-bit Windows installation, and 64-bit applications in a Windows 64-bit installation.
In order to also see 32-bit applications installed on a Windows 64-bit installation, you would also need to enumeration the key #"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".
You can take a look at this article. It makes use of registry to read the list of installed applications.
public void GetInstalledApps()
{
string uninstallKey = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(uninstallKey))
{
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
lstInstalled.Items.Add(sk.GetValue("DisplayName"));
}
catch (Exception ex)
{ }
}
}
}
}
While the accepted solution works, it is not complete. By far.
If you want to get all the keys, you need to take into consideration 2 more things:
x86 & x64 applications do not have access to the same registry.
Basically x86 cannot normally access x64 registry. And some
applications only register to the x64 registry.
and
some applications actually install into the CurrentUser registry instead of the LocalMachine
With that in mind, I managed to get ALL installed applications using the following code, WITHOUT using WMI
Here is the code:
List<string> installs = new List<string>();
List<string> keys = new List<string>() {
#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
#"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};
// The RegistryView.Registry64 forces the application to open the registry as x64 even if the application is compiled as x86
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64), keys, installs);
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64), keys, installs);
installs = installs.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();
installs.Sort(); // The list of ALL installed applications
private void FindInstalls(RegistryKey regKey, List<string> keys, List<string> installed)
{
foreach (string key in keys)
{
using (RegistryKey rk = regKey.OpenSubKey(key))
{
if (rk == null)
{
continue;
}
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
installed.Add(Convert.ToString(sk.GetValue("DisplayName")));
}
catch (Exception ex)
{ }
}
}
}
}
}
it's worth noting that the Win32_Product WMI class represents products as they are installed by Windows Installer. not every application use windows installer
however "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" represents applications for 32 bit. For 64 bit you also need to traverse "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" and since not every software has a 64 bit version the total applications installed are a union of keys on both locations that have "UninstallString" Value with them.
but the best options remains the same .traverse registry keys is a better approach since every application have an entry in registry[including the ones in Windows Installer].however the registry method is insecure as if anyone removes the corresponding key then you will not know the Application entry.On the contrary Altering the HKEY_Classes_ROOT\Installers is more tricky as it is linked with licensing issues such as Microsoft office or other products.
for more robust solution you can always combine registry alternative with the WMI.
string[] registryKeys = new string[] {
#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" };
public class InstalledApp
{
public string DisplayName { get; set; }
public string DisplayIcon { get; set; }
public string Version { get; set; }
public string InstallLocation { get; set; }
}
private void AddInstalledAppToResultView(RegistryHive hive, RegistryView view, string registryKey,Dictionary<string,InstalledApp> resultView)
{
using (var key = RegistryKey.OpenBaseKey(hive, view).OpenSubKey(registryKey))
{
foreach (string subKeyName in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subKeyName))
{
var displayName = subkey.GetValue("DisplayName");
var displayIcon = subkey.GetValue("DisplayIcon");
if (displayName == null || displayIcon == null)
continue;
var app = new InstalledApp
{
DisplayName = (string)displayName,
DisplayIcon = (string)displayIcon,
InstallLocation = (string)subkey.GetValue("InstallLocation"),
Version = (string)subkey.GetValue("DisplayVersion")
};
if(!resultView.ContainsKey(app.DisplayName))
{
resultView.Add(app.DisplayName,app);
}
}
}
}
}
void Main()
{
var result = new Dictionary<string,InstalledApp>();
var view = Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32;
AddInstalledAppToResultView(RegistryHive.LocalMachine, view, registryKeys[0],result);
AddInstalledAppToResultView(RegistryHive.CurrentUser, view, registryKeys[0],result);
AddInstalledAppToResultView(RegistryHive.LocalMachine, RegistryView.Registry64, registryKeys[1],result);
Console.WriteLine("==============" + result.Count + "=================");
result.Values.ToList().ForEach(item => Console.WriteLine(item));
}
Iterate through "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" keys and check their "DisplayName" values.
Use Windows Installer API!
It allows to make reliable enumeration of all programs. Registry is not reliable, but WMI is heavyweight.
The object for the list:
public class InstalledProgram
{
public string DisplayName { get; set; }
public string Version { get; set; }
public string InstalledDate { get; set; }
public string Publisher { get; set; }
public string UnninstallCommand { get; set; }
public string ModifyPath { get; set; }
}
The call for creating the list:
List<InstalledProgram> installedprograms = new List<InstalledProgram>();
string registry_key = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
if (subkey.GetValue("DisplayName") != null)
{
installedprograms.Add(new InstalledProgram
{
DisplayName = (string)subkey.GetValue("DisplayName"),
Version = (string)subkey.GetValue("DisplayVersion"),
InstalledDate = (string)subkey.GetValue("InstallDate"),
Publisher = (string)subkey.GetValue("Publisher"),
UnninstallCommand = (string)subkey.GetValue("UninstallString"),
ModifyPath = (string)subkey.GetValue("ModifyPath")
});
}
}
}
}
As others have pointed out, the accepted answer does not return both x86 and x64 installs. Below is my solution for that. It creates a StringBuilder, appends the registry values to it (with formatting), and writes its output to a text file:
const string FORMAT = "{0,-100} {1,-20} {2,-30} {3,-8}\n";
private void LogInstalledSoftware()
{
var line = string.Format(FORMAT, "DisplayName", "Version", "Publisher", "InstallDate");
line += string.Format(FORMAT, "-----------", "-------", "---------", "-----------");
var sb = new StringBuilder(line, 100000);
ReadRegistryUninstall(ref sb, RegistryView.Registry32);
sb.Append($"\n[64 bit section]\n\n{line}");
ReadRegistryUninstall(ref sb, RegistryView.Registry64);
File.WriteAllText(#"c:\temp\log.txt", sb.ToString());
}
private static void ReadRegistryUninstall(ref StringBuilder sb, RegistryView view)
{
const string REGISTRY_KEY = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
using var subKey = baseKey.OpenSubKey(REGISTRY_KEY);
foreach (string subkey_name in subKey.GetSubKeyNames())
{
using RegistryKey key = subKey.OpenSubKey(subkey_name);
if (!string.IsNullOrEmpty(key.GetValue("DisplayName") as string))
{
var line = string.Format(FORMAT,
key.GetValue("DisplayName"),
key.GetValue("DisplayVersion"),
key.GetValue("Publisher"),
key.GetValue("InstallDate"));
sb.Append(line);
}
key.Close();
}
subKey.Close();
baseKey.Close();
}
Your best bet is to use WMI. Specifically the Win32_Product class.
Might I suggest you take a look at WMI (Windows Management Instrumentation).
If you add the System.Management reference to your C# project, you'll gain access to the class `ManagementObjectSearcher', which you will probably find useful.
There are various WMI Classes for Installed Applications, but if it was installed with Windows Installer, then the Win32_Product class is probably best suited to you.
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
I used Nicks approach - I needed to check whether the Remote Tools for Visual Studio are installed or not, it seems a bit slow, but in a seperate thread this is fine for me. - here my extended code:
private bool isRdInstalled() {
ManagementObjectSearcher p = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach (ManagementObject program in p.Get()) {
if (program != null && program.GetPropertyValue("Name") != null && program.GetPropertyValue("Name").ToString().Contains("Microsoft Visual Studio 2012 Remote Debugger")) {
return true;
}
if (program != null && program.GetPropertyValue("Name") != null) {
Trace.WriteLine(program.GetPropertyValue("Name"));
}
}
return false;
}
My requirement is to check if specific software is installed in my system. This solution works as expected. It might help you. I used a windows application in c# with visual studio 2015.
private void Form1_Load(object sender, EventArgs e)
{
object line;
string softwareinstallpath = string.Empty;
string registry_key = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (var key = baseKey.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (var subKey = key.OpenSubKey(subkey_name))
{
line = subKey.GetValue("DisplayName");
if (line != null && (line.ToString().ToUpper().Contains("SPARK")))
{
softwareinstallpath = subKey.GetValue("InstallLocation").ToString();
listBox1.Items.Add(subKey.GetValue("InstallLocation"));
break;
}
}
}
}
}
if(softwareinstallpath.Equals(string.Empty))
{
MessageBox.Show("The Mirth connect software not installed in this system.")
}
string targetPath = softwareinstallpath + #"\custom-lib\";
string[] files = System.IO.Directory.GetFiles(#"D:\BaseFiles");
// Copy the files and overwrite destination files if they already exist.
foreach (var item in files)
{
string srcfilepath = item;
string fileName = System.IO.Path.GetFileName(item);
System.IO.File.Copy(srcfilepath, targetPath + fileName, true);
}
return;
}