Associate File Type and Icon - c#

Ok, I have looked all over and I am having a difficult time trying to figure out how to associate a custom file type with my C# application. I am using Visual Studio 2008 and am limited to .NET 2.0 due to company deployment.
Basically all I really want to do is be able to allow the user to double click my custom file type or drag and drop it on the app icon and it load the data, as well as display a custom icon on the file itself. I can open the file via a dialog box and everything works great.
Trying to read Micosoft's online documents is hard to understand and does not really give me all the details that I need. If anyone out there know's where I can find a good tutorial or can explain it I would appreciate it.
Thank you
Patrick

I wrote this up in the newsgroups a few years ago. Skimming through it, I find that it's not the clearest I've ever written, but it's fairly complete. For what it's worth, I've reprinted it below:
First you need to create a subkey under HKEY_CLASSES_ROOT that will hold the commands that start your application. You should name this key something semi-descriptive. Your file extension[s] will be mapped to this key. For example, TXT files are mapped to a key named txtfile, by default. The benefit of using this setup is that if you have multiple extensions that your app can handle, you can map them all to this key. For example, many
image editting apps create a subkey called something like "imagefile", and map .bmp, .jpg, .gif, etc. to that key. We'll call your key "JoeBlowFile". Next, you need to set the "default" value for your new JoeBlowFile key to a text string describing to the user just what type of file they have. This is what shows up in Windows Explorer under "Type". Again, to use the TXT file example, a good string here would be "Text File" or "Text Document". (It is the latter by default.) Your string might be "Joe Blow Data".
Now, under your new key, you can create another subkey, called "DefaultIcon". This, as its name suggests, sets the icon that is used with files of this type. You should create a custom icon that pictorially represents documents handled by your program. You can save this icon as an ICO file in your app's directory, but even better, you can include it as a resource in either your EXE or DLL. Either way, you'll then need to set the subkey's default value to a string representing the full path and filename of the ICO, EXE, or DLL. If there is more than one icon in the file (particularly likely if you include it as a resource in your EXE or DLL), you'll also need to add a comma, and either a zero-based positive index number representing which icon you'd like to use, or a negative resource ID, using the negative of whatever ID you've assigned your icon in your resource script. So yours could be, for example "C:\Program Files\JoeBlow\JoeBlow.exe, 2".
A note for C# developers on the above paragraph. Unfortunately, C# projects can't have resource scripts. Resources added to .NET applications by adding them to the project and designating them an "Embedded Resource" are included in a new .NET-specific format that's not compatible with previous methods. The only icon you can correctly embed in your application using C# on VS.NET is the application icon, accessible from the project properties. If you need additional icons—e.g. an
icon to represent a document file handled by your app rather than to represent the app itself—you'll need to either include the ICO files themselves, compile a DLL with C++ with your icons embedded, or create and compile a resource script and include it in your project from the project properties.
Whether or not you choose to use the DefaultIcon key, you now need to create a subkey named "shell" under your JoeBlowFile key. Under the shell key, you'll create individual keys for each of the commands you'd like the user to be able to perform on your file type from the context menu (right-click menu). These items are called "verbs". For consistency, one of them should be "open"—this key, if it exists, will be the default (i.e. when a user double clicks on a file of your type, the open command will be performed). Instead, you can set the default value for the "shell" key equal to the verb you'd like to perform by default. You can optionally set the default value for each verb key to the text that you would like to appear in the context menu when a user right-clicks on a file of your type. An ampersand (&) can be used within this text to designate that the following character will be underlined, which means that the user can press the key corresponding to that character to select that command from the context menu. For instance, for the "open" key, you could put "Open with &Joe Blow's app" as the default value. That text then, with an underlined J, will appear in the context menu for files of that type, and a user can press the letter J to start Joe Blow's app.
The only thing you have to do, though, with the "open" (and subsequent) keys, is create
another key as a subkey of that one called "command". The default value for the command key must be set to a string representing just that—the command required to perform that action. For instance, the default string in the command key under the "open" key might be ""C:\Program Files\JoeBlow\JoeBlow.exe" "%1"". Note the quotation marks around the path\filename for your app and around the %1. They are only neccessary around the path\filename of your app if there are any spaces in the path or filename, but they are absolutely a requirement around the %1 for 32-bit apps. The %1 is just like %1 in old MS-DOS batch (.bat) files. %1 is replaced with the first parameter on the command line, which in this case becomes the file name of the file your app is supposed to open. Because you do not know in advance if the path or filename containing the file you're supposed to
open will contain spaces, you must put the quotes around %1.
Other required parameters for your app should also be included. For instance, the default value in the "command" key, under the "print" key might be ""C:\Program Files\JoeBlow\JoeBlow.exe" "%1" /print", or ""C:\Program Files\JoeBlow\JoeBlow.exe" /print "%1"". It's up to you how you want to process command line parameters in your app.
A note on replaceable parameters like "%1", mentioned above. Apparently, the "%1" parameter /may/ be replaced with the short filename to be opened. This isn't always the case, and I haven't figured out what criteria Windows uses to determine which it will pass—short or long. It may be that if the executable path listed in the registry is a long filename, Windows will replace %1 with the long filename to start, but if the executable path is a short filename, or can be interpreted as one, Windows will replace %1 with the short filename. If you want to be sure that you always get the long filename, use "%L" instead. You can use an uppercase L (as I've done) or a lowercase one, but I prefer to use uppercase because lowercase "l" looks way too much like the number "1".
What's more, if your program knows how to deal with Shell Item IDs, you can get that instead of the long filename with the "%i" parameter. Again, upper- or lowercase "i" are equally suitable, but I find uppercase "I" harder to distiguish from lowercase "l" and the number "1". If you don't know what a Shell Item ID is, it's okay. You'll probably never need to use one.
You're finally done with the JoeBlowFile key. The rest is relatively simple. You simply need to create (if it doesn't already exist) another subkey under HKEY_CLASSES_ROOT, and name it the same as the extension of your document type. To use the txtfile example, the name would be ".txt" (with the dot, but without the quotes). Yours (Joe Blow's) might be ".jbf" (for Joe Blow File). The default value for this key must now be set to the name of the first key your created, which in the example we've using is "JoeBlowFile".
That's it. You're done in the registry. Do remember that you'll have to make sure your app
proccesses the command line in a manner consistent with the commands you set under the "shell" key. Window's won't open that file for you automatically when your app starts... you have to do it.
Graphically, it looks like this:
HKEY_CLASSES_ROOT
| +--.jbf = JoeBlowFile
|
+--JoeBlowFile = Joe Blow Data
|
+--DefaultIcon = C:\Program Files\JoeBlow\JoeBlow.exe, 2
|
+--Shell
|
+--open = Open with &Joe Blow's App
| |
| +--command = "C:\Program Files\JoeBlow\JoeBlow.exe" "%1"
|
+--print
|
+--command = "C:\Program Files\JoeBlow\JoeBlow.exe" "%1" /print
If you don't already know how to modify the registry, look in MSDN for all the functions
beginning with "Reg", including RegOpenKeyEx, RegCreateKeyEx, and RegSetValueEx. You can also do it the wimpy way by creating a ".reg" file and simply use ShellExecuteEx() to call "regedit.exe /s" on it. (The /s keeps Regedit from popping up a message box asking "Are you sure you want to add the information in [name of file.reg] to the registry?") The format of the a REG file is simple and straight forward. Here is an example REG file to add the "JoeBlow" example from above:
REGEDIT4
[HKEY_CLASSES_ROOT\.jbf]
#="JoeBlowFile"
[HKEY_CLASSES_ROOT\JoeBlowFile]
#="Joe Blow Data"
[HKEY_CLASSES_ROOT\JoeBlowFile\DefaultIcon]
#="C:\\Program Files\\JoeBlow\\JoeBlow.exe, 2"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell]
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\open]
#="Open with &Joe Blow's app"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\open\command]
#="\"C:\\Program Files\\JoeBlow\\JoeBlow.exe\" \"%1\""
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\print]
#="&Print"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\print\command]
#="\"C:\\Program Files\\JoeBlow\\JoeBlow.exe \"%1\" /print"
Make sure that you include "REGEDIT4" as the first line of the file, or it won't work. Also
make sure to press enter on the last line, or that line won't be read in. Altogether, adding your program to the registry this way is not as convenient as it sounds, because you'll have to modify your REG file if your app is installed anywhere except to C:\Program Files\JoeBlow.
The above instructions were aimed at a user programming directly to the Win32 API using C or
C++. For C# on .NET, it's rather a bit easier. See the Registry class, or you can even do much of it graphically using a deployment project in VS.NET.
To add native-accessible resources to a .NET assembly, you will need a resource script. A resource script is a plain text file, like a code file. In fact, it is code; declarative code that is compiled by the resource compiler, rc.exe. A sample resource script follows:
#include <windows.h>
#define IDI_APP 100
#define IDI_FILE 200
#define ID_VERSION 1
IDI_APP ICON "Resources\\Application.ico"
IDI_FILE ICON "Resources\\JowBlowFile.ico"
ID_VERSION VERSIONINFO
FILEVERSION 1, 0, 19, 186 // change this to your version
PRODUCTVERSION 1, 0, 19, 186 // change this to your version
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP {
BLOCK "StringFileInfo" {
BLOCK "040904B0" { // 0x409 = U.S. English, 0x04B0 = dec 1200 = Unicode
VALUE "CompanyName", "Joe Blow, Inc.\0"
VALUE "FileDescription", "Joe Blow's App\0"
VALUE "FileVersion", "1.0.19.186\0" // change this to your version
VALUE "InternalName", "JoeBlow\0"
VALUE "LegalCopyright", "Copyright © 2008-2009 Joe Blow Incorporated\0"
VALUE "OriginalFilename", "JoeBlow.exe\0"
VALUE "ProductName", "Joe Blow\0"
VALUE "ProductVersion", "1.0.19.189\0" // change this to your version
}
}
BLOCK "VarFileInfo" {
VALUE "Translation", 0x409 /*U.S. English*/, 1200 /*Unicode*/
}
}
The biggest drawback to doing this is that you have to add the version information manually to your resource script (unless you want to just forgo the version information altogether). In my applications, I add a custom build step that runs a program I wrote that updates the version information directly in the executable so that I don't have to manually update the version number in the resource script, but that program is not suitable for public release and is otherwise beyond the scope of this post.
Now you need to invoke the resource compiler to build this resource script into a binary resource file. Save this script as JoeBlow.rc, then start a Visual Studio Command Prompt. It's under Tools in the Visual Studio start menu folder. If you don't have Visual Studio installed, I believe you get rc.exe as part of the SDK. Microsoft also seems to be offering the latest version here.
Once at a VS cmd prompt (or otherwise have rc.exe in your path), just type:
rc JoeBlow.rc
Simple as that. The above resource script should compile without errors, given that the icons I've include exist. This will create a new file in the same directory called JoeBlow.res. Now, assuming you are using Visual Studio, all you have to do is edit the project properties to include this resource file.
These directions are for Visual Studio 2005 or 2008. I don't remember how to do this, or even if you can, in older versions, and I haven't tried out 2010, yet, but it's probably similar. Right-click on the project in Solution Explorer and select Properties (or select Properties from the Project menu on the main menu bar). On the Application tab, which is the first tab you should see, at the bottom is a Resources group box. Here, you have two options: "Icon and manifest", or "Resource File". Select the latter option. This will enable the text box where you can type (or browse to) your new resource file, JoeBlow.res.
Lastly, just build your project, and presto, you have embedded icons in native PE format accessible to the shell when browsing files associated to your app. Now if you set the value of HKEY_CLASSES_ROOT\JoeBlowFile\DefaultIcon to either C:\Program Files\JoeBlow\JoeBlow.exe,1 (using the zero-based index number), or C:\Program Files\JoeBlow\JoeBlow.exe,-200 (using the negative of the resource identifier, #defined above as IDI_FILE), your icon will show up in Explorer for .jbf files.
To get your new icons to show up immediately upon installation, you may need to refresh the shell's icon cache. I've found instructions on how to do that here. The basic gist is to change the shell icon size (at HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics) from its current value to a different one and back again, broadcasting a WM_SETTINGCHANGE message after each change.
Good luck. Let me know if you need anything else.

This CodeProject article has some source code demonstrating file association by code.

Here is a discussion about how to use command-line utilities assoc and ftype to do this. You could invoke the command shell during a program deployment (or when the application is run) to do this.

Related

Something changes files name in Windows when there are whitespaces (Windows Shell arguments)

I am developing an application based on C# WPF.
This application uses system register to capture the Explorer Context Menu actions. In other words: the Explorer Context Menu presents an additional Item customized for my application, a bit like NotePad++ (see image 1).
I click on the right button on a file and my application is launched correctly. Naturally, the file name is passed to the application as argument% 1 from the command line. The image 2 shows how I configured the registers for the context menu.
The problem is that if the file name does not contain spaces, everything is fine. If instead it contains spaces, I find the file name in capital letters and truncated.
Case 1 OK
File name: dummy.txt
String captured in %1: dummy.txt
Case 2 KO
File name: paths - Copia.txt
String captured in %1: PACE0~1.TXT
In the following two examples, the first correct and working, the second is the scenario in which I have the problems described.
Image 1
Image 2
Does anyone know a way to avoid this?
Footnotes
Unfortunately I know very little about the Windows system and this is causing me a lot of headaches. I have no idea what the cause of the problem might be.
Keep in mind that I may have misplaced the question: I myself am doubtful that I have provided the information necessary to solve the problem.
Try and change the registry entries to "C:\Program Files (x86)\Polito\Kyactus\Kyactus.exe" "%1" -- enclose both the path to the program and the %1 in quotes, but for each use a different pair.

C# windows explorer right click function [duplicate]

I'm currently writing an application where I need to modify the context menu of windows explorer so that I can call a method within the application to be used on all files/folders that are seen in windows explorer.
As there are already quite a few posts on stackoverflow (and also tutorials) on how to add the context menu for specific file types I know already that that is done usually by assigning the application to the right parts of the registry entry for those file types.
As I don't want to limit myself to only specific filetypes my question is: IS there any way
to assign this new context menu item to ALL filetypes (aside from going through each registry entry
beginning with . and assigning the application to them there)?
Yes, the * class:
Create the key:
HKEY_CLASSES_ROOT\*\shell\Open with MyThing
Create the sub key:
HKEY_CLASSES_ROOT\*\shell\Open with MyThing\command
Set the default value to your command line:
C:\foo\myThing.exe "%1"
(You can add fixed values here also: C:\foo\myThing.exe "%1" /ranfromshell)
To set an optional icon create the string value Icon in:
HKEY_CLASSES_ROOT\*\shell\Open with MyThing
You can put the path to an icon, dll or exe here - Windows will extract the appropriate icon & display it.
Example
For:
.Reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\shell\Open with MyThing]
"Icon"="C:\\foo\\myThing.exe"
[HKEY_CLASSES_ROOT\*\shell\Open with MyThing\command]
#="C:\\foo\\myThing.exe \"%1\""

How to add my application to the context menu for .docx file types [duplicate]

I've developed an application that load an image using the context menu of window (right click on the file) and for the moment is working, but the reg key is on
HKEY_CLASSES_ROOT\*
and it works with all files.
I want that the menu item on the context menu should be displayed only with .jpg files.
How can I do that? Which registry keys should I use?
Identify the file type (ProgID) for .jpg files
This can be done by checking the default value of HKEY_CLASSES_ROOT\.jpg. It could be anything based on what you've installed, but for the purposes of this example, we'll call it jpegfile, a common default.
Set the context menu item (verb) properties for that file type
You can set per-user context menu items in HKEY_CURRENT_USER\Software\Classes\jpegfile\shell. This key has a list of verbs for the file type. There is a similar key in HKEY_LOCAL_MACHINE\Software\Classes\jpegfile\shell, and these are the system defaults for the file type. You can put a verb key there too, but if the same key exists in HKCU, it will be overridden, so be advised.
Set the command value
The bare minimum key value that needs to be set to get it to work is the default value of the command subkey. You need to set that with the path to your application, like so: HKEY_CURRENT_USER\Software\Classes\jpegfile\shell\open_with_myapp\command would be set to "c:\path\to\myapp.exe" "%1". Now a context menu for .jpg files will have a "open_with_myapp" item which will launch your app when clicked, and pass the file name of the selected file as a parameter. Of course, how your application processes parameters is up to you, so you'd need to set the parameter string to something your app can process.
Set other verb properties
I'd imagine you're probably going to want the context menu item to read something a little more friendly than the key name. You can have the context menu display whatever label you want for your item by setting the default value of that key (open_with_myapp).
That's your basic overview. Definitely check out my answer to this question about associating a file, which has a similar answer:
Create registry entry to associate file extension with application in C++
There's another key on the registry that works independently of user's default programs: HKEY_CLASSES_ROOT\SystemFileAssociations. Since nobody mentioned it on this question... No need to check ProgID before adding the context menu item. Example:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\SystemFileAssociations\.mkv\shell\subtitle]
#="Search subtitles..."
[HKEY_CLASSES_ROOT\SystemFileAssociations\.mkv\shell\subtitle\command]
#="\"D:\\Tools\\subsearch.exe\" \"%1\""
Reference: https://learn.microsoft.com/en-us/windows/desktop/shell/app-registration#registering-verbs-and-other-file-association-information
Additional Considerations:
The HKEY_CLASSES_ROOT subtree can be written to but in general is a view formed by merging
HKEY_CURRENT_USER\Software\Classes
file type registration visible to the current user only
HKEY_LOCAL_MACHINE\Software\Classes
globally register a file type on a particular computer
You can register to those classes instead/aswell
The (ProgID) defined verbs have priority over the same ones defined in ...\SystemFileAssociations\ , but are dependent on that particular Application, When that application uninstalls, it would normally delete its registry entry, along with what modifications/additions you may have done under that key. Or if the default (ProgID) is changed, your modifications will no longer be in effect.
The ...\SystemFileAssociations\ registrations are stable even when users change/uninstall the default programs.
Will publish my working solution derived from the previous answer (and one of its author's other answer).
It also adds an icon. I used it for all file types and didn't have administrator's privileges. The subitem * didn't exist in my registry, I created it myself.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*]
[HKEY_CURRENT_USER\Software\Classes\*\shell]
[HKEY_CURRENT_USER\Software\Classes\*\shell\open_with_notepad_pp]
#="Open with Notepad++"
"icon"="C:\\portable\\npp.7.9\\notepad++.exe"
[HKEY_CURRENT_USER\Software\Classes\*\shell\open_with_notepad_pp\command]
#="\"C:\\portable\\npp.7.9\\notepad++.exe\" \"%1\""
UPDATE
Replace * with something like .svg and only for this extension the menu item will be shown.

Is it worth it to lookup the default application in the registry when opening a file from a C# application?

I'm building an application (a side project which is likely to enlist the help of the stackoverflow community on more than one occasion) which will need to open a variety of file types (i.e. open Word documents in Word, not natively in my application).
I've been playing with some code for looking up the default application for the file type in the registry and passing this to Process.Start(). There seem to be two issues with this approach:
1) The application name is quoted in some instances, and not in others.
2) Process.Start() requires that the application path and it's arguments are passed separately (i.e. Process.Start("notepad.exe", #"C:\myfile.txt"); rather than Process.Start(#"notepad.exe C:\myfile.txt");).
This means when I retrieve the path from the registry, I have to split it (after determining if I need to split on quotes or spaces) to determine what part is the application path and what parts are arguments, then pass those separately to Process.Start().
The alternative seems to be to just pass the filename, as in Process.Start(#"C:\myfile.txt"), but I think this only works if the application is in the Path environment variable.
Which way is better? In the case of the registry, is there a common solution for how to do the argument parsing?
Thanks for any and all help!
Update:
I guess the short answer is 'No.'
It seems like I was really going the overkill route, and that passing just the filename will work whenever there's an associated value in the registry. I.e. anything I find in the registry myself, Process.Start() already knows how to do.
I did discover that when I try this with a "new" filetype, I get a Win32Exception stating "No application is associated with the specified file for this operation." Fredrik Mörk mentions in a comment that this doesn't occur for him in Vista. What's the proper way to handle this?
If the extension is registered to be opened with a certain application, it doesn't need to be in the PATH in order to run.
The application does not need to be in the PATH if you only specify the filename. The following code worked fine for me:
System.Diagnostics.Process.Start(#"C:\Users\Dan\Desktop\minors.pdf");
You typically do not need to lookup the program for registered types, and the program does not typically need to be in the PATH environment variable. Usually the command in the registry contains the full path. This is how the command for .kml files (Google Earth) looks (in my computer):
C:\Program Files\Google\Google Earth\googleearth.exe "%1"
Given that, you can safely just use Process.Start together with the document file names. Should it be that the file type is not registered you will invoke the default Windows behaviour for this (asking you which program to use, and so on).

How can I make an application open when a user double clicks on its associated file?

I am creating an application that uses a certain file format as its data source. I want this application to open whenever the user double clicks on this file, like how MS Word will open when a user double clicks on a Word document. How do I accomplish this? Also how would I populate the data fields using the file that the user selected. Would I use args[] from the program.cs class? I am using c# to code this application.
N.B. I want this association to be made when the application is installed on the host machine without the user doing anything.
FIRST, you need to set up file association, so that your file type is associated with your application and opening the file type will run your application.
You can do the file association programatically, there is some detail here as mentioned:
http://www.codeproject.com/KB/dotnet/System_File_Association.aspx
You can also do it via your Setup project for you application if you have one. This is an easier path for "newbies". Details for using visual studio to get the setup project to add the file association and also set the icon for the file are here:
http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Otherwise if you use InnoSetup, Wix etc then I suppose you could just see instructions for those installers to create the association for you.
SECOND, you need to have your application accept command line arguments. The opened file(s) is(are) passed as a command line argument(s). You need to process the arguments to get the file path/name(s) and open the given file(s). There is a nice description of this here with code:
C# Command Line arguments problem in Release build
In your case, rather than MessageBox.Show(s) in the form shown handler, you would call your bespoke argument parsing method.
For a simple application which only accepts files names to open as arguments, this could be as simple as
foreach (string filePathName in Args)
DoNamedFileOpen(filePathName);
Your code can also have a method that might extract from the file the values for the datafields you are interested in etc.
This is a nice simple approach to the issue of have file associations set on installation of your application, with icons, and having your application handle the opening of those files.
Of course, there are plenty of other options, like run-time file association (asking the user if they want the association), detecting "broken" associations, etc.
This question is a long time here but I hope this is useful for new searches
See this. Or this if you want API information.
ClickOnce supports file associations as of .NET 3.5 SP1, too. In the project's properties, switch to the Publish tab and click the Options button. There's a File Associations section in that dialog that allows you to specify file extensions, descriptions and custom icons.
First, you have to associate the filetype extention with your executeable. On Windows you do this via the registry (search "filetype association windows"). In this question you find some interesting hints: Filetype association with application (C#) Script to associate an extension to a program
Your program has to react on the command line arguments or parameters. In Java, it is indeed the string array of the main method. I would gess, it's the same in C#.
If you don't need to do it pro programatically, right click on the icon, click open with ..., then select 'always use this program ...'.
This is something usually handled by your setup program .. I've used INNO setup for example, and it's trivially simple to arrange for it to adjust user's registry to launch your app when associated file extension is double clicked/opened. It'll even take care of MIME types for you as well as clearing these things on uninstall, which is a very nice thing to do
I managed to solve this issue. I used WIX to create an install file and asked it to associate the file with the application when it installs.

Categories

Resources