I want to create a setup to deploy software.My first window of installation is to check master software(other software) is installed in that computer,because i need to add a supporting file to master software's installation folder.
Is that possible in visual studio setup deployment project?
Every software you install, must create entry in Registry.So you can read the particular entry in registry from Visual studio Setup project.
Retrieve a Value from the Registry
how to retrieve the MediaPath value for your computer from the
registry,
The MediaPath value for your computer is located under the following registry subkey:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
You can retrieve this value by using a launch condition. To do this, follow these steps:
In Visual Studio .NET, point to Editor on the View menu, and then
click Launch Conditions.
In the Launch Conditions Editor, click Search Target Machine.
On the Action menu, click Add Registry Search.
By default, Search for RegistryEntry1 is added.
On the View menu, click Properties Window to select the Properties
window for the registry search that you created in previous step.
Change the Name property value to Search for MediaPath.
Change the Property property value to MEDIA_PATH.
When you run the setup project, the MediaPath registry value is retrieved to your
MEDIA_PATH property.
To search HKEY_LOCAL_MACHINE in the registry, click the Root
property, and then click vsdrrHKLM in the drop-down list box for the
property value.
To search the SOFTWARE\Microsoft\Windows\CurrentVersion subkey, type
SOFTWARE\Microsoft\Windows\CurrentVersion in the RegKey property
value text box.
To search for the MediaPath value, type MediaPath in the Value
property value text box.
For More See Hare
Below code is working fine for me
/// <summary>
/// To check software installed or not
/// </summary>
/// <param name="controlPanelDisplayName">Display name of software from control panel</param>
private static bool IsApplictionInstalled(string controlPanelDisplayName)
{
string displayName;
RegistryKey key;
// search in: CurrentUser
key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
if (null != key)
{
foreach (string keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (controlPanelDisplayName.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
}
// search in: LocalMachine_32
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
if (null != key)
{
foreach (string keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (controlPanelDisplayName.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
}
// search in: LocalMachine_64
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
if (null != key)
{
foreach (string keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (controlPanelDisplayName.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
}
// NOT FOUND
return false;
}
Related
So to my final programming project I need to rename a value inside Registry through C#, this is what I wrote so far:
public bool RenameSubKey(string parentKey, string subKeyName, string newSubKeyName)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
rk64.OpenSubKey(parentKey);
//copy all the values
foreach (string valueName in rk64.OpenSubKey(subKeyName).GetValueNames())
{
object objValue = rk64.OpenSubKey(subKeyName).GetValue(valueName);
RegistryValueKind valKind = rk64.OpenSubKey(subKeyName).GetValueKind(valueName);
rk64.CreateSubKey(newSubKeyName).SetValue(valueName, objValue, valKind);
}
rk64.DeleteSubKeyTree(subKeyName); // Deletes old value
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(parentKey, false))
{
rk.OpenSubKey(parentKey);
//copy all the values
foreach (string valueName in rk.OpenSubKey(subKeyName).GetValueNames())
{
object objValue = rk.OpenSubKey(subKeyName).GetValue(valueName);
RegistryValueKind valKind = rk.OpenSubKey(subKeyName).GetValueKind(valueName);
rk.CreateSubKey(newSubKeyName).SetValue(valueName, objValue, valKind);
}
rk.DeleteSubKeyTree(subKeyName); // Deletes old value
return true;
}
}
It needs to be able to rename a 32-bit Registry value as well as a 64-bit Registry value (the application is 32-bit). Rename function simply means to create new value with the new name, copy all the data from the old one to the new one and delete the old one.
Let's take an example: There's a ListView presents all the installed application on the PC and I want to change the value UninstallString to !UninstallString with the press of a button so the users won't be able to uninstall the selected application in the ListView. The app might be 64-bit (meaning the Registry values are 64-bit and it requires a little different approach) or it can be 32-bit - Hence comes the if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess).
So in the example I place SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip as my path and I want to rename the value UninstallString to !UninstallString, but it quits on the foreach with an error says System.NullReferenceException: 'Object reference not set to an instance of an object.' Microsoft.Win32.RegistryKey.OpenSubKey(...) returned null.
First of all, let me say, this requieres elevated privileges, the changes are because you want to enter the registry and write in them so you need to actually tell that when you are opening the sub key. Either in 64 or 32 bit. Im not sure about the If, as pointed out before by the general, but this will work at least for 32 bits path
public static bool RenameSubKey(string parentKey, string key, string newValue)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(parentKey, RegistryKeyPermissionCheck.ReadWriteSubTree);
rk64.SetValue(key, newValue);
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(parentKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
rk.SetValue(key, newValue);
return true;
}
}
Thanks to #nalnpir I fixed the rename Registry value function:
public static bool RenameSubKey(string path, string keyName, string newKeyName)
{
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
RegistryKey rk64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(path, RegistryKeyPermissionCheck.ReadWriteSubTree);
object objValue = rk64.GetValue(keyName);
RegistryValueKind valKind = rk64.GetValueKind(keyName);
rk64.SetValue(newKeyName, objValue, valKind);
rk64.DeleteValue(keyName);
return true;
}
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(path, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
object objValue = rk.GetValue(keyName);
RegistryValueKind valKind = rk.GetValueKind(keyName);
rk.SetValue(newKeyName, objValue, valKind);
rk.DeleteValue(keyName);
return true;
}
}
Now I see that I didn't access it the right way (as he enlightened me) and thus was the error.
private void button1_Click(object sender, EventArgs e)
{
int i = (Int32)Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Beerbaum", "TCP_Listening_Delay", null);
MessageBox.Show(i.ToString());
}
In the Registry there is a QWORD-Value(64-Bit) called TCP_Listening_Delay and its value is dec:5000
When I press the button it should open a MessageBox which should display 5000, but it doesn't. All it does is giving me,
"NullReferenceException was unhandled".
Registry.GetValue(String, String, Object) 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 null if the specified key
does not exist.
Returns
null if the subkey specified by keyName does not exist; otherwise, the
value associated with valueName, or defaultValue if valueName is not
found.
However i think your problem is you are probably trying to read 64/32 bit registry hive from a 32/64 bit application
RegistryView Enumeration : On the 64-bit version of Windows, portions
of the registry are stored separately for 32-bit and 64-bit
applications. There is a 32-bit view for 32-bit applications and a
64-bit view for 64-bit applications.
You can specify a registry view when you use the OpenBaseKey and
OpenRemoteBaseKey(RegistryHive, String, RegistryView) methods, and the
FromHandle property on a RegistryKey object.
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (var subKey = baseKey.OpenSubKey("blah", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl))
{
if (subKey != null)
{
var value = subKey.GetValue("Somekey");
}
}
}
64 bit Registry Key not updated by 32 bit application
I want to check for the installation of a third party application during the installation of my .NET Windows Form application or when it is opened. My Windows Form application doesn't require the third party application to run but it does need it for a feature to work. For example, My Windows Form application opens up the third party application such as a mail program.
I don't know if Click Once is the right strategy for this? I would need it to check for the prerequisite during installation and if it's not there notify the user to install it first. If Click Once isn't the right strategy for this is there another way? Maybe I need to install my Windows Form application first then when it is opened it checks for the third party application? The problem with that is, the installation path could vary from machine to machine. I'm not really sure how to go about this.
This link explains how to include prerequisites in Click Once but that's not what I want to do.
Another link that talks about including the prerequisites but not just detecting them.
One possible solution is to check registry with this method that returns bool value indicating whether the registry record with application name exists :
public static bool IsApplictionInstalled(string p_name)
{
string displayName;
RegistryKey key;
// search in: CurrentUser
key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
// 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 = subkey.GetValue("DisplayName") as string;
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
// 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 = subkey.GetValue("DisplayName") as string;
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}
// NOT FOUND
return false;
}
I would to get installed version of an application (say, MyApp) using C#.
I will do this much,
1. Create a 'Set Up' for MyApp of version 5.6
2. Install MyApp.
I will create another application (say VersionTracker)to get the version of installed applications. So if I pass the name 'MyApp' I would like to get the version as '5.6'. If another application say Adobe Reader is installed in my system, I want to get the version of Adobe Reader if I pass 'Adobe Reader'.
I need to know how to build 'VersionTracker'
The first and the most important thing is that not all applications do save their version somewhere in the system. To be honest, only a few of them do that. The place where you should look are the Windows Registry. Most of installed applications put their installation data into the following place:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
However, it's not that easy - on 64bit Windows, the 32bit (x86) applications save their installation data into another key, which is:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
In these keys there are many keys, some of them have got "easy-readable" name, such as Google Chrome, some of them got names such as {63E5CDBF-8214-4F03-84F8-CD3CE48639AD}. You must parse all these keys into your application and start looking for the application names. There are usually in DisplayName value, but it's not always true. The version of the application is usually in DisplayVersion value, but some installers do use another values, such as Inno Setup: Setup Version, ... Some application do have their version written in their name, so it's possible that the application version is already in the DisplayName value.
Note: It's not easy to parse all these registry keys and values and to "pick" the correct values. Not all installers save the application data into these keys, some of them do not save the application version there, etcetera. However, it's usual that the application use these registry keys. [Source: StackOverflow: Detecting installed programs via registry, browsing my own registry]
Alright, so now when you know where you should look, you have to program it all in C#. I won't write the application for you, but I'll tell you what classes you should use and how to. First, you need these:
using System;
using Microsoft.Win32;
To get to your HKEY_LOCAL_MACHINE, create a RegistryKey like this:
RegistryKey baseRegistryKey = Registry.LocalMachine;
Now you need to define subkeys:
string subKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// or "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
Now you need to go to the subkey, so create a new RegistryKey:
RegistryKey uninstallKey = baseRegistryKey.OpenSubKey(subKey);
Now you need to go thru all the subkeys that are there, so first we get the names of all the subkeys:
string[] allApplications = uninstallKey.GetSubKeyNames();
Now you must go thru all the subkeys yourself, one by one, by creating a new registry key (you don't have to, but I'll do it):
RegistryKey appKey = baseRegistryKey.OpenSubKey(subKey + "\\" + applicationSubKeyName);
where applicationSubKeyName is the name of the subkey you're currently checking. I recommend foreach statement, which helps you (you must however have some experience with C# already, I'm not going to tell you how to use foreach here).
Now check the application's name and compare it with name of your desired application (you cannot rely on the subkey name, because, as I already said, they can be called for example {63E5CDBF-8214-4F03-84F8-CD3CE48639AD}, so you must check the name here):
string appName = (string)appKey.GetValue("DisplayName");
If it's the correct application (you must check it yourself), find the version:
string appVersion = (string)appKey.GetValue("DisplayVersion");
Et voilà, you have the version. At least there's like a 60 - 80% chance you have...
Remember! If some key or value doesn't exist, the method returns null. Remember to check if the returned value is null everytime, otherwise your application will crash.
Where to find more? The Code Project: Read, write and delete from registry with C#
I really hope I helped you. And if you wanted to know something else and I didn't understand your question, then, please, ask better next time. :)
///
/// Author : Muhammed Rauf K
/// Date : 03/07/2011
/// A Simple console application to create and display registry sub keys
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// it's required for reading/writing into the registry:
using Microsoft.Win32;
namespace InstallationInfoConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Registry Information ver 1.0");
Console.WriteLine("----------------------------");
Console.Write("Input application name to get the version info. (for example 'Nokia PC Suite'): ");
string nameToSearch = Console.ReadLine();
GetVersion(nameToSearch);
Console.WriteLine("----------------------------");
Console.ReadKey();
}
///
/// Author : Muhammed Rauf K
/// Date : 03/07/2011
/// Create registry items
///
static void Create()
{
try
{
Console.WriteLine("Creating registry...");
// Create a subkey named Test9999 under HKEY_CURRENT_USER.
string subKey;
Console.Write("Input registry sub key :");
subKey = Console.ReadLine();
RegistryKey testKey = Registry.CurrentUser.CreateSubKey(subKey);
Console.WriteLine("Created sub key {0}", subKey);
Console.WriteLine();
// Create two subkeys under HKEY_CURRENT_USER\Test9999. The
// keys are disposed when execution exits the using statement.
Console.Write("Input registry sub key 1:");
subKey = Console.ReadLine();
using (RegistryKey testKey1 = testKey.CreateSubKey(subKey))
{
testKey1.SetValue("name", "Justin");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void GetVersion(string nameToSearch)
{
// Get HKEY_LOCAL_MACHINE
RegistryKey baseRegistryKey = Registry.LocalMachine;
// If 32-bit OS
string subKey
//= "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// If 64-bit OS
= "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
RegistryKey unistallKey = baseRegistryKey.OpenSubKey(subKey);
string[] allApplications = unistallKey.GetSubKeyNames();
foreach (string s in allApplications)
{
RegistryKey appKey = baseRegistryKey.OpenSubKey(subKey + "\\" + s);
string appName = (string)appKey.GetValue("DisplayName");
if(appName==nameToSearch)
{
string appVersion = (string)appKey.GetValue("DisplayVersion");
Console.WriteLine("Name:{0}, Version{1}", appName, appVersion);
break;
}
}
}
static void ListAll()
{
// Get HKEY_LOCAL_MACHINE
RegistryKey baseRegistryKey = Registry.LocalMachine;
// If 32-bit OS
string subKey
//= "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// If 64-bit OS
= "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
RegistryKey unistallKey = baseRegistryKey.OpenSubKey(subKey);
string[] allApplications = unistallKey.GetSubKeyNames();
foreach (string s in allApplications)
{
RegistryKey appKey = baseRegistryKey.OpenSubKey(subKey + "\\" + s);
string appName = (string)appKey.GetValue("DisplayName");
string appVersion = (string)appKey.GetValue("DisplayVersion");
Console.WriteLine("Name:{0}, Version{1}", appName, appVersion);
}
}
}
}
Next code base on similar solution is working for me:
var version = GetApplicationVersion("Windows Application Driver");
string GetApplicationVersion(string appName)
{
string displayName;
// search in: CurrentUser
var key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (var keyName in key.GetSubKeyNames())
{
var subKey = key.OpenSubKey(keyName);
displayName = subKey.GetValue("DisplayName") as string;
if (appName.Equals(displayName, StringComparison.OrdinalIgnoreCase))
return subKey.GetValue("DisplayVersion").ToString();
}
// search in: LocalMachine_32
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (var keyName in key.GetSubKeyNames())
{
var subKey = key.OpenSubKey(keyName);
displayName = subKey.GetValue("DisplayName") as string;
if (appName.Equals(displayName, StringComparison.OrdinalIgnoreCase))
return subKey.GetValue("DisplayVersion").ToString();
}
// search in: LocalMachine_64
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (var keyName in key.GetSubKeyNames())
{
var subKey = key.OpenSubKey(keyName);
displayName = subKey.GetValue("DisplayName") as string;
if (appName.Equals(displayName, StringComparison.OrdinalIgnoreCase))
return subKey.GetValue("DisplayVersion").ToString();
}
// NOT FOUND
return null;
}
I'd like to to associate a file extension to the current executable in C#.
This way when the user clicks on the file afterwards in explorer, it'll run my executable with the given file as the first argument.
Ideally it'd also set the icon for the given file extensions to the icon for my executable.
Thanks all.
There doesn't appear to be a .Net API for directly managing file associations but you can use the Registry classes for reading and writing the keys you need to.
You'll need to create a key under HKEY_CLASSES_ROOT with the name set to your file extension (eg: ".txt"). Set the default value of this key to a unique name for your file type, such as "Acme.TextFile". Then create another key under HKEY_CLASSES_ROOT with the name set to "Acme.TextFile". Add a subkey called "DefaultIcon" and set the default value of the key to the file containing the icon you wish to use for this file type. Add another sibling called "shell". Under the "shell" key, add a key for each action you wish to have available via the Explorer context menu, setting the default value for each key to the path to your executable followed by a space and "%1" to represent the path to the file selected.
For instance, here's a sample registry file to create an association between .txt files and EmEditor:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\.txt]
#="emeditor.txt"
[HKEY_CLASSES_ROOT\emeditor.txt]
#="Text Document"
[HKEY_CLASSES_ROOT\emeditor.txt\DefaultIcon]
#="%SystemRoot%\\SysWow64\\imageres.dll,-102"
[HKEY_CLASSES_ROOT\emeditor.txt\shell]
[HKEY_CLASSES_ROOT\emeditor.txt\shell\open]
[HKEY_CLASSES_ROOT\emeditor.txt\shell\open\command]
#="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" \"%1\""
[HKEY_CLASSES_ROOT\emeditor.txt\shell\print]
[HKEY_CLASSES_ROOT\emeditor.txt\shell\print\command]
#="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" /p \"%1\""
Also, if you decide to go the registry way, keep in mind that current user associations are under HKEY_CURRENT_USER\Software\Classes. It might be better to add your application there instead of local machine classes.
If your program will be run by limited users, you won't be able to modify CLASSES_ROOT anyway.
If you use ClickOnce deployment, this is all handled for you (at least, in VS2008 SP1); simply:
Project Properties
Publish
Options
File Associatons
(add whatever you need)
(note that it must be full-trust, target .NET 3.5, and be set for offline usage)
See also MSDN: How to: Create File Associations For a ClickOnce Application
Here's a complete example:
public class FileAssociation
{
public string Extension { get; set; }
public string ProgId { get; set; }
public string FileTypeDescription { get; set; }
public string ExecutableFilePath { get; set; }
}
public class FileAssociations
{
// needed so that Explorer windows get refreshed after the registry is updated
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
private const int SHCNE_ASSOCCHANGED = 0x8000000;
private const int SHCNF_FLUSH = 0x1000;
public static void EnsureAssociationsSet()
{
var filePath = Process.GetCurrentProcess().MainModule.FileName;
EnsureAssociationsSet(
new FileAssociation
{
Extension = ".binlog",
ProgId = "MSBuildBinaryLog",
FileTypeDescription = "MSBuild Binary Log",
ExecutableFilePath = filePath
},
new FileAssociation
{
Extension = ".buildlog",
ProgId = "MSBuildStructuredLog",
FileTypeDescription = "MSBuild Structured Log",
ExecutableFilePath = filePath
});
}
public static void EnsureAssociationsSet(params FileAssociation[] associations)
{
bool madeChanges = false;
foreach (var association in associations)
{
madeChanges |= SetAssociation(
association.Extension,
association.ProgId,
association.FileTypeDescription,
association.ExecutableFilePath);
}
if (madeChanges)
{
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
}
}
public static bool SetAssociation(string extension, string progId, string fileTypeDescription, string applicationFilePath)
{
bool madeChanges = false;
madeChanges |= SetKeyDefaultValue(#"Software\Classes\" + extension, progId);
madeChanges |= SetKeyDefaultValue(#"Software\Classes\" + progId, fileTypeDescription);
madeChanges |= SetKeyDefaultValue($#"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\"");
return madeChanges;
}
private static bool SetKeyDefaultValue(string keyPath, string value)
{
using (var key = Registry.CurrentUser.CreateSubKey(keyPath))
{
if (key.GetValue(null) as string != value)
{
key.SetValue(null, value);
return true;
}
}
return false;
}
There may be specific reasons why you choose not to use an install package for your project but an install package is a great place to easily perform application configuration tasks such registering file extensions, adding desktop shortcuts, etc.
Here's how to create file extension association using the built-in Visual Studio Install tools:
Within your existing C# solution, add a new project and select project type as Other Project Types -> Setup and Deployment -> Setup Project (or try the Setup Wizard)
Configure your installer (plenty of existing docs for this if you need help)
Right-click the setup project in the Solution explorer, select View -> File Types, and then add the extension that you want to register along with the program to run it.
This method has the added benefit of cleaning up after itself if a user runs the uninstall for your application.
To be specific about the "Windows Registry" way:
I create keys under HKEY_CURRENT_USER\Software\Classes (like Ishmaeel said)
and follow the instruction answered by X-Cubed.
The sample code looks like:
private void Create_abc_FileAssociation()
{
/***********************************/
/**** Key1: Create ".abc" entry ****/
/***********************************/
Microsoft.Win32.RegistryKey key1 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key1.CreateSubKey("Classes");
key1 = key1.OpenSubKey("Classes", true);
key1.CreateSubKey(".abc");
key1 = key1.OpenSubKey(".abc", true);
key1.SetValue("", "DemoKeyValue"); // Set default key value
key1.Close();
/*******************************************************/
/**** Key2: Create "DemoKeyValue\DefaultIcon" entry ****/
/*******************************************************/
Microsoft.Win32.RegistryKey key2 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key2.CreateSubKey("Classes");
key2 = key2.OpenSubKey("Classes", true);
key2.CreateSubKey("DemoKeyValue");
key2 = key2.OpenSubKey("DemoKeyValue", true);
key2.CreateSubKey("DefaultIcon");
key2 = key2.OpenSubKey("DefaultIcon", true);
key2.SetValue("", "\"" + "(The icon path you desire)" + "\""); // Set default key value
key2.Close();
/**************************************************************/
/**** Key3: Create "DemoKeyValue\shell\open\command" entry ****/
/**************************************************************/
Microsoft.Win32.RegistryKey key3 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key3.CreateSubKey("Classes");
key3 = key3.OpenSubKey("Classes", true);
key3.CreateSubKey("DemoKeyValue");
key3 = key3.OpenSubKey("DemoKeyValue", true);
key3.CreateSubKey("shell");
key3 = key3.OpenSubKey("shell", true);
key3.CreateSubKey("open");
key3 = key3.OpenSubKey("open", true);
key3.CreateSubKey("command");
key3 = key3.OpenSubKey("command", true);
key3.SetValue("", "\"" + "(The application path you desire)" + "\"" + " \"%1\""); // Set default key value
key3.Close();
}
Just show you guys a quick demo, very easy to understand. You could modify those key values and everything is good to go.
The code below is a function the should work, it adds the required values in the windows registry. Usually i run SelfCreateAssociation(".abc") in my executable. (form constructor or onload or onshown) It will update the registy entry for the current user, everytime the executable is executed. (good for debugging, if you have some changes).
If you need detailed information about the registry keys involved check out this MSDN link.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd758090(v=vs.85).aspx
To get more information about the general ClassesRoot registry key. See this MSDN article.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
public enum KeyHiveSmall
{
ClassesRoot,
CurrentUser,
LocalMachine,
}
/// <summary>
/// Create an associaten for a file extension in the windows registry
/// CreateAssociation(#"vendor.application",".tmf","Tool file",#"C:\Windows\SYSWOW64\notepad.exe",#"%SystemRoot%\SYSWOW64\notepad.exe,0");
/// </summary>
/// <param name="ProgID">e.g. vendor.application</param>
/// <param name="extension">e.g. .tmf</param>
/// <param name="description">e.g. Tool file</param>
/// <param name="application">e.g. #"C:\Windows\SYSWOW64\notepad.exe"</param>
/// <param name="icon">#"%SystemRoot%\SYSWOW64\notepad.exe,0"</param>
/// <param name="hive">e.g. The user-specific settings have priority over the computer settings. KeyHive.LocalMachine need admin rights</param>
public static void CreateAssociation(string ProgID, string extension, string description, string application, string icon, KeyHiveSmall hive = KeyHiveSmall.CurrentUser)
{
RegistryKey selectedKey = null;
switch (hive)
{
case KeyHiveSmall.ClassesRoot:
Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(ProgID);
break;
case KeyHiveSmall.CurrentUser:
Microsoft.Win32.Registry.CurrentUser.CreateSubKey(#"Software\Classes\" + extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(#"Software\Classes\" + ProgID);
break;
case KeyHiveSmall.LocalMachine:
Microsoft.Win32.Registry.LocalMachine.CreateSubKey(#"Software\Classes\" + extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(#"Software\Classes\" + ProgID);
break;
}
if (selectedKey != null)
{
if (description != null)
{
selectedKey.SetValue("", description);
}
if (icon != null)
{
selectedKey.CreateSubKey("DefaultIcon").SetValue("", icon, RegistryValueKind.ExpandString);
selectedKey.CreateSubKey(#"Shell\Open").SetValue("icon", icon, RegistryValueKind.ExpandString);
}
if (application != null)
{
selectedKey.CreateSubKey(#"Shell\Open\command").SetValue("", "\"" + application + "\"" + " \"%1\"", RegistryValueKind.ExpandString);
}
}
selectedKey.Flush();
selectedKey.Close();
}
/// <summary>
/// Creates a association for current running executable
/// </summary>
/// <param name="extension">e.g. .tmf</param>
/// <param name="hive">e.g. KeyHive.LocalMachine need admin rights</param>
/// <param name="description">e.g. Tool file. Displayed in explorer</param>
public static void SelfCreateAssociation(string extension, KeyHiveSmall hive = KeyHiveSmall.CurrentUser, string description = "")
{
string ProgID = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.FullName;
string FileLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;
CreateAssociation(ProgID, extension, description, FileLocation, FileLocation + ",0", hive);
}
The file associations are defined in the registry under HKEY_CLASSES_ROOT.
There's a VB.NET example here that I'm you can port easily to C#.
There are two cmd tools that have been around since Windows 7 which make it very easy to create simple file associations. They are assoc and ftype. Here's a basic explanation of each command.
Assoc - associates a file extension (like '.txt') with a "file type."
FType - defines an executable to run when the user opens a given "file type."
Note that these are cmd tools and not executable files (exe). This means that they can only be run in a cmd window, or by using ShellExecute with "cmd /c assoc." You can learn more about them at the links or by typing "assoc /?" and "ftype /?" at a cmd prompt.
So to associate an application with a .bob extension, you could open a cmd window (WindowKey+R, type cmd, press enter) and run the following:
assoc .bob=BobFile
ftype BobFile=c:\temp\BobView.exe "%1"
This is much simpler than messing with the registry and it is more likely to work in future windows version.
Wrapping it up, here is a C# function to create a file association:
public static int setFileAssociation(string[] extensions, string fileType, string openCommandString) {
int v = execute("cmd", "/c ftype " + fileType + "=" + openCommandString);
foreach (string ext in extensions) {
v = execute("cmd", "/c assoc " + ext + "=" + fileType);
if (v != 0) return v;
}
return v;
}
public static int execute(string exeFilename, string arguments) {
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.FileName = exeFilename;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = arguments;
try {
using (Process exeProcess = Process.Start(startInfo)) {
exeProcess.WaitForExit();
return exeProcess.ExitCode;
}
} catch {
return 1;
}
}