I am writing a C# application and it takes files as argument, I added it to shell context menu with code listed below;
if (((CheckBox)sender).CheckState == CheckState.Checked)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME + "\\command");
if (key == null)
{
key = Registry.CurrentUser.CreateSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME + "\\command");
key.SetValue("", Application.ExecutablePath + " \"%1\"");
}
}
else if (((CheckBox)sender).CheckState == CheckState.Unchecked)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME);
if (key != null)
{
Registry.CurrentUser.DeleteSubKeyTree("Software\\Classes\\*\\shell\\" + KEY_NAME);
}
It is working good, but if I select multiple files, multiple instances of application running.
for example if I select 5 files 5 application is opening, how can I fix this?
Detect if an instance of your application is already running on startup.
If it does, send the command line arguments to the running instance and exit the new instance.
Related
This question already has an answer here:
Uninstalling program
(1 answer)
Closed 4 years ago.
If I run the code below I'm pretty sure I'm supposed to get the Product Name and GUID (ex. App Path | {xxx}) for the application. But I'm only getting the path and no GUID is shown. Can someone help me?
// search in: LocalMachine_64
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine(subkey.GetValue("UninstallString"));
//string prdctId = uninstlString.Substring((uninstlString.IndexOf("{")));
string prdctId = uninstlString.Substring(12);
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + prdctId + " /quiet /norestart";
uninstallProcess.StartInfo.UseShellExecute = true;
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
This is the image that I got running the code
I believe the UninstallString value is what gets executed when uninstalling an application via Add/Remove Programs. As your console output shows, it's the path to an executable.
The way you are retrieving the product ID...
string prdctId = uninstlString.Substring(12);
...therefore, is incorrect because you are taking a partial path. What you need to pass to MsiExec.exe /x is the product code, which is the registry key name itself, i.e....
string prdctId = keyName;
If you were invoking that command line from Command Prompt I'm pretty sure the curly brackets would necessitate putting quotes around the product code; I'm not sure if you'll need to do so when invoking the executable directly, but it can't hurt...
uninstallProcess.StartInfo.Arguments = " /x \"" + prdctId + "\" /quiet /norestart";
I'm trying to uninstall a program with this code.. But it doesn't seem to work. I've tried the other answers but didn't seem to work either.. Can someone help me with this? I'm trying to uninstall the program by a given name(displayName)
For example I give the displayName = Appname then this code should uninstall the Appname program from my computer.
public static void UninstallApplictionInstalled(string p_name)
{
string displayName;
string uninstlString;
RegistryKey key;
ProcessStartInfo info = new ProcessStartInfo();
Process uninstallProcess = new Process();
string temp;
// search in: CurrentUser
key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
// search in: LocalMachine_32
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
// search in: LocalMachine_64
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
//string prdctId = uninstlString.Substring((uninstlString.IndexOf("{")));
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
}
Only this pops up..
Duplicates: Welcome to Stackoverflow. Just to mention to you that I see this question asked in at least 3 different flavors. We will have to close some of your questions since the duplication scatters replies and can waste a lot of time if people answer the (seemingly) unanswered duplicates.
In short: please don't post the same question several times. Here are the other questions:
MsiExec.exe product id uninstall
MSI installer option- uninstalling an application
C#: Using C# for this can be clunky - no matter how you do it. I would not push a command line to msiexec.exe, but go directly via the MSI API. This API can be accessed via Win32 functions or COM automation.
Uninstall Appraches for MSI: For your reference, there is a myriad of ways to kick of an MSI
uninstall:
Uninstalling an MSI file from the command line without using msiexec.
Section 14 from the link above shows how to uninstall using C++ - if that is an option. However:, there are changes in the Visual Studio 2017 templates again, so it might need a tune-up to work "out-of-the-box".
However, I would use the MSI API - as already stated - and I would recommend you go via the native Win32 functions and that you use DTF (Deployment Tools Foundation) which is part of the WiX toolkit. It is a .NET wrapper for the MSI API - which will save you a lot of boilerplate code, at the expense of having to deploy the DTF DLL: Microsoft.Deployment.WindowsInstaller.dll along with your product. I do not know if this is acceptable. I have code that does not depend on DTF if need be, but it is much longer.
Mock-up C# Sample. Project reference to Microsoft.Deployment.WindowsInstaller.dll needed. Then try the below code in a fresh C# .NET project. You can get that DLL by installing the WiX toolkit - the open source toolkit to create MSI files. After installation check in %ProgramFiles(x86)%\WiX Toolset v3.11\bin (adjust for WiX version - current as of September 2018).
Installer GUI: Important note first: the setup's UI level is set via the Installer.SetInternalUI function. If you run in silent mode, then you need to run the executable elevated for the uninstall to work properly, or an access exception occurs. When you run in Full GUI mode, you need to elevate the install yourself - provided you have the rights to do so.
Run Elevated: How to check for admin rights: Check if the current user is administrator.
using System;
using Microsoft.Deployment.WindowsInstaller;
namespace UninstallMsiViaDTF
{
class Program
{
static void Main(string[] args)
{
// Update this name to search for your product. This sample searches for "Orca"
var productcode = FindProductCode("orca");
try
{
if (String.IsNullOrEmpty(productcode)) { throw new ArgumentNullException("productcode"); }
// Note: Setting InstallUIOptions to silent will fail uninstall if uninstall requires elevation since UAC prompt then does not show up
Installer.SetInternalUI(InstallUIOptions.Full); // Set MSI GUI level (run this function elevated for silent mode)
Installer.ConfigureProduct(productcode, 0, InstallState.Absent, "REBOOT=\"ReallySuppress\"");
// Check: Installer.RebootInitiated and Installer.RebootRequired;
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
Console.ReadLine(); // Keep console open
}
// Find product code for product name. First match found wins
static string FindProductCode(string productname)
{
var productcode = String.Empty;
var productname = productname.ToLower();
foreach (ProductInstallation product in ProductInstallation.AllProducts)
{
if (product.ProductName.ToLower().Contains(productname))
{
productcode = product.ProductCode;
break;
}
}
return productcode;
}
}
}
I Have a Three EXE's
EXE1 build with 3.5 net framework
EXE2 build with 4.5 net framework
EXE3 build with 4.6 net framework
I want to run exe after detect which.Net version already installed and according to that start exe
if 3.5 installed
RUN(EXE1)
if 4.5 installed
RUN(EXE2)
if 4.6 installed
RUN(EXE3)
i think about wix setup, iexpress but didnt get any thing so how can we do this ?
or its is possible? if yes then how and if no then so can we do this with the help of third party software?
so I need a way to run exe as per platform because each platform has
their own .Net framework
there is 2 way: using bath file to detect .net version after that run exe for this version
or build a porogram exe depend .net 2 after that this exe decide witch file must run
Update:
this samples give you version of .net freamwork are inistaled
for.net 4 and older
private static void GetVersionFromRegistry()
{
// Opens the registry key for the .NET Framework entry.
using (RegistryKey ndpKey =
RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
{
// As an alternative, if you know the computers you will query are running .NET Framework 4.5
// or later, you can use:
// using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
// RegistryView.Registry32).OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
foreach (string versionKeyName in ndpKey.GetSubKeyNames())
{
if (versionKeyName.StartsWith("v"))
{
RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
string name = (string)versionKey.GetValue("Version", "");
string sp = versionKey.GetValue("SP", "").ToString();
string install = versionKey.GetValue("Install", "").ToString();
if (install == "") //no install info, must be later.
Console.WriteLine(versionKeyName + " " + name);
else
{
if (sp != "" && install == "1")
{
Console.WriteLine(versionKeyName + " " + name + " SP" + sp);
}
}
if (name != "")
{
continue;
}
foreach (string subKeyName in versionKey.GetSubKeyNames())
{
RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
name = (string)subKey.GetValue("Version", "");
if (name != "")
sp = subKey.GetValue("SP", "").ToString();
install = subKey.GetValue("Install", "").ToString();
if (install == "") //no install info, must be later.
Console.WriteLine(versionKeyName + " " + name);
else
{
if (sp != "" && install == "1")
{
Console.WriteLine(" " + subKeyName + " " + name + " SP" + sp);
}
else if (install == "1")
{
Console.WriteLine(" " + subKeyName + " " + name);
}
}
}
}
}
}
}
and for get .net 4.5 and upper
using System;
using Microsoft.Win32;
public class GetDotNetVersion
{
public static void Get45PlusFromRegistry()
{
const string subkey = #"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
{
if (ndpKey != null && ndpKey.GetValue("Release") != null) {
Console.WriteLine(".NET Framework Version: " + CheckFor45PlusVersion((int) ndpKey.GetValue("Release")));
}
else {
Console.WriteLine(".NET Framework Version 4.5 or later is not detected.");
}
}
}
// Checking the version using >= will enable forward compatibility.
private static string CheckFor45PlusVersion(int releaseKey)
{
if (releaseKey >= 460798) {
return "4.7 or later";
}
if (releaseKey >= 394802) {
return "4.6.2";
}
if (releaseKey >= 394254) {
return "4.6.1";
}
if (releaseKey >= 393295) {
return "4.6";
}
if ((releaseKey >= 379893)) {
return "4.5.2";
}
if ((releaseKey >= 378675)) {
return "4.5.1";
}
if ((releaseKey >= 378389)) {
return "4.5";
}
// This code should never execute. A non-null release key should mean
// that 4.5 or later is installed.
return "No 4.5 or later version detected";
}
}
// Calling the GetDotNetVersion.Get45PlusFromRegistry method produces
// output like the following:
// .NET Framework Version: 4.6.1
and by this sample you can run exe file
using System;
using System.Diagnostics;
using System.ComponentModel;
namespace MyProcessSample
{
class MyProcess
{
public static void Main()
{
Process myProcess = new Process();
try
{
myProcess.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
myProcess.StartInfo.FileName = "C:\\HelloWorld.exe";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
// This code assumes the process you are starting will terminate itself.
// Given that is is started without a window so you cannot terminate it
// on the desktop, it must terminate itself or you can do it programmatically
// from this application using the Kill method.
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
Update2:
by this Update you get latest version of .net at batch File
#echo off
setlocal
#SET INSTALLUTILDIR=
#for /F "tokens=1,2*" %%i in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" /v "Version"') DO (
if "%%i"=="Version" (
SET .NetVer=%%k
)
)
#for /F "tokens=1,2*" %%i in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v "Version"') DO (
if "%%i"=="Version" (
SET .NetVer=%%k
)
)
ECHO The most current version of Net in use is %.NetVer%
and by this code you can run program but dont forget the bat file must be in folder the exe files are there
start myProgram.exe
exit
If you use Windows Installer (such as through wix), you can use the MsiNetAssemblySupport property to condition a custom action that launches your executable. If you use wix specifically, the WixNetfxExtension can be asked to set other properties that may be easier to use. Here is wix's list of .NET properties.
However I suspect this is the wrong approach. It should be much easier to write a single .NET executable that targets the lowest framework version you support, and include a .config file1 with a supportedRuntime element that enables it to run on a wider spread of frameworks. (See How to: Configure an App to Support .NET Framework 4 or 4.5.
Also, depending on what the executable does, you may be better off writing a C++ executable, a C++ DLL (so it can interact with Windows Installer), or even leveraging native Windows Installer functionality instead of custom actions. (If applicable, the last option is ideal.)
1Note that Windows Installer EXE custom action support for temporary files will only extract a single file to the temp folder, so your .config file would not be found in these configurations. Alternate approaches would be required; various Windows Installer tools have their own approaches for mitigating this problem.
I will check my Windows os name (Windows 8 Pro) in c# but it gives an error, what's wrong?
RegistryKey reg = Registry.LocalMachine.OpenSubKey(#"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion", true);
string currentKey;
currentKey = reg.GetValue("ProductName", true).ToString();
textBox1.Text = currentKey;
You can use Environment.OSVersion for this.
Edit:
Getting the OS name is answered here: Stackoverflow OS Friendly name
I'll just quote MSDN:
Registry.GetValue()-Method
Retrieves the value associated with the specified name, in the specified registry key. If the name is not found in the specified key, returns a default value that you provide, or a null reference (Nothing in Visual Basic) if the specified key does not exist.
This means that the value you are trying to get is not available.
Edit possible Solution:
Source: How to get the “friendly” OS Version Name?
private string GetOSName()
{
var name = (from x in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get().OfType<ManagementObject>()
select x.GetPropertyValue("Caption")).First();
return name != null ? name.ToString() : "Unknown";
}
And to check whether OS is 32 or 64bit use following code:
private string GetOSBitness()
{
if (Environment.Is64BitOperatingSystem == true)
return " x64";
else
return " x86";
}
Above code will return (at least on my system):
Microsoft Windows 7 Professional x64
You can get the commercial name of your operating system, including service pack information by querying the Windows Management Instrumentation interface:
public static string GetOSNameAndVersion()
{
string str = Environment.OSVersion.ToString();
try
{
var obj2 = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem")
.Get()
.Cast<System.Management.ManagementObject>()
.First<System.Management.ManagementObject>();
str = ((string)obj2["Caption"]).Trim();
string spMaj = obj2["ServicePackMajorVersion"].ToString();
string spMin = obj2["ServicePackMinorVersion"].ToString();
string osVer = obj2["Version"].ToString();
if (((spMaj != "") && (spMaj != "0")) || ((spMin != "") && (spMin != "0")))
{
str = str + " SP " + spMaj;
if ((spMin != "") && (spMin != "0"))
{
str = str + "." + spMin;
}
}
if (Environment.Is64BitOperatingSystem)
{
str = str + " x64";
}
else
{
str = str + " x86";
}
str = str + " (" + osVer + ")";
}
catch
{
// TODO: Implement your own exception handling here
// the way it is, the method will fall back on to the Environment.OSVersion
// if the query fails
}
if (str.StartsWith("Microsoft"))
{
str = str.Substring("Microsoft".Length + 1);
}
return str;
}
Hacking at the registry is probably the wrong solution.
But why is it failing? Since you use Registry.LocalMachine, the HKLM is wrong. Remove the HKLM. That's a clear error.
On top of that watch out for registry redirection. Perhaps your process is 32 bit but the value you are looking for is in the 64 bit view of the registry. Use the RegistryView enumeration to gain access to the 64 bit view.
Your program is subject to what I presume to be a NullReferenceException because the program cannot find the registry sub-key because the path that you have supplied is incorrect.
You do not need to specify the hive in the hive path because your relative path is already the local hive. Exclude the hive from the path like like this:
Registry.LocalMachine.OpenSubKey(
#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", true);
Depending on your programs' access privileges and operating system configuration your program may still throw an exception due to your program having insufficient access permissions.
My application has a menu bar from which a user can choose from two applications to run (IE and my own custom exe). When the user chooses IE, it should be set as a startup application and if the other app is chosen, the corresponding should become the startup application.
I tried to write the values to the registry using the following, but it does not write any new entry for the startup app (looked inside regedit) and neither does it throw any error.
MenuItem menuoption = (MenuItem)sender;
RegistryKey startupapp = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
//if IE
if (menuoption == menu_IE)
{
startupapp.SetValue("iexplore -k" + url, Assembly.GetExecutingAssembly().Location); //Have to store ProgramFilesx86/InternetExplorer here or is this correct?
startupapp.DeleteValue("MyCustomEXE.exe", false); //Have to delete MyCustomEXE as starup **only if** it is already set as starup
Process.Start("iexplore", "-k " + url);
}
else if (menuoption == menu_myapp) //If myexe
{
startupapp.SetValue("MyCustomEXE.exe", Assembly.GetExecutingAssembly().Location);
startupapp.DeleteValue("iexplore", false);
Process.Start("MyCustomEXE.exe", url);
}