I am working on a program that can read, write, and export files, these functions all work fine and are almost perfected. What I would like to do now is to be able to choose a file and tell it to "Open With" (In the Right-Click Context Menu on Windows XP) and have my application be able to handle the file given. I have no idea on where to start or where to look so I thought I'd ask here. Thanks.
You might take a look at this Windows KB article:
"How To Associate a File Extension with Your Application (Win32)"
http://support.microsoft.com/kb/185453
It looks like it gives example code for how to do this in VBScript (?), but it looks like it goes through the Registry paths you need to look at.
Hey, I believe this is defined in the registry. E.g. MSAccess is defined as:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit]
#="&Edit"
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit\command]
#="\"C:\\Programmer\\Microsoft Office\\OFFICE11\\MSACCESS.EXE\" /NOSTARTUP \"%1\""
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit\ddeexec]
#="[SetForeground][ShellOpenDatabase \"%1\"]"
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit\ddeexec\Application]
#="Msaccess"
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit\ddeexec\IfExec]
#="[SHELLNOOP]"
[HKEY_CLASSES_ROOT\Access.Application.11\shell\Edit\ddeexec\Topic]
#="ShellSystem"
A GUI also exists in Folder settings -> File types.
Br. Morten
Bring up the run dialog box, and enter: regedit (Registry Editor)
Go to: HKEY_CLASSES_ROOT\*\shell and create a subkey named: "Open With YourApp", create another subkey under the newly created one named "command". On its Default value, enter the path to your exe, then add "%1" at the end for the parameter.
In program.cs, add the indicated lines below:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var mainForm = new MainForm();
// Add these lines:
// ----------------------------------------------
string[] args = Environment.GetCommandLineArgs();
if (args.Count() >= 2)
mainForm.LoadFile(args[1]);
// ----------------------------------------------
Application.Run(mainForm);
}
}
Where LoadFile(string filePath) is your method that handles the file that is passed in from outside.
Related
The .NET Shell extension framework called SharpShell is great; I've developed a right-click file Shell ContextMenu "quite easily" that works selecting both files and directories.
Now I would like to develop a Shell ContextMenu by righ-clicking on an empty space (that is, on the Desktop or on a white spot while I'm inside a folder).
Is it possible do that still using SharpShell? Or do I need to move to a different solution?... and in 2nd case... what do you suggest?
Thanks
The two solutions presented below work, but in the meantime I have found that there is an easier solution that is actually already used in the samples that come with SharpShell.
See the CopyDirectoryLocationHandler class as an example of a context menu handler that is registered for the directory background (and the desktop):
[ComVisible(true)]
[COMServerAssociation(AssociationType.Class, #"Directory\Background")]
public class CopyDirectoryLocationHandler : SharpContextMenu
{
// ...
}
If you want the handler to only handle clicks on the desktop background, use this code instead:
[ComVisible(true)]
[COMServerAssociation(AssociationType.Class, #"DesktopBackground")]
public class CopyDirectoryLocationHandler : SharpContextMenu
{
// ...
}
Old obsolete answer:
You can use SharpShell for this purpose without problem. There are two possible approaches:
Register the Shell Extension to handle the folder background
yourself
or
Modify SharpShell to handle the registration of the
extension for the folder background for you.
Register the Shell Extension to handle the folder background yourself
Your shell extension is a COM server and as such is identified to the system via a GUID. This GUID is then used at places in the registry to register the COM extension for different purposes. When we manually want to register the extension for a purpose such as extending the context menu for folder backgrounds, it is best when our extension has a fixed GUID.
Currently your class looks like this:
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
public class MyContextMenuExtension : SharpContextMenu
{
When compiling, the compiler will automatically generate a GUID to use for that class. But we can specify a specific one to use like this:
[Guid("A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0")]
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
public class MyContextMenuExtension : SharpContextMenu
{
Do not use the same GUID as shown here but create your own unique one in Visual Studio via Menu Tools > Create GUID. Use a different GUID for every shell extension you write.
Then recompile the dll and install and register it again (using regasm or the SharpShell Server Manager tool.
Then create a text file named "registry.reg" with the following content (use your own specific GUID). Instead of "MyContextMenuExtension" specify the name of your extension.
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\MyContextMenuExtension]
#="{A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0}"
Install the "registry.reg" file by double clicking. Your extension should now be active when you open the context menu for a folder background or the Desktop.
Instead of using the *.reg file, you can also make the changes manually using registry editor or if you have an installer instruct the installer to make those registry changes.
Modify SharpShell to handle the registration of the extension for the folder background for you
Make the following changes to the SharpShell source code:
In the file AssociationType.cs add a new enum value to the AssociationType enumeration:
/// <summary>
/// Create an association to the unknown files class.
/// </summary>
UnknownFiles,
/// <summary>
/// Create an association to the background of folders and the desktop
/// </summary>
DirectoryBackground
In the file ServerRegistrationManager.cs add a new private string constant:
/// <summary>
/// The 'directory' special class.
/// </summary>
private const string SpecialClass_Directory = #"Directory";
/// <summary>
/// The 'directory background' special class.
/// </summary>
private const string SpecialClass_DirectoryBackground = #"Directory\Background";
Also in the file ServerRegistrationManager.cs in the method CreateClassNamesForAssociations in the big switch statement add a new case like this:
case AssociationType.Directory:
// Return the directory class.
return new[] { SpecialClass_Directory };
case AssociationType.DirectoryBackground:
// Return the directory background class.
return new[] { SpecialClass_DirectoryBackground };
Finally you only have to tell your own extension class to use this new enumeration value:
[Guid("A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0")]
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
[COMServerAssociation(AssociationType.DirectoryBackground)]
public class MyContextMenuExtension : SharpContextMenu
{
I have used SharpShell some time ago, forgotten it since then (because it works flawlessly). I have used it on files and folders, so your question intrigued me. A little research on the tool led me to the answer No(unfortunately).
The binding is done through the com server associations on SharpShell. And by looking at the documentation of the com server associations I am not seeing the way to your desired functionality.
PS: I encourage you to leave a comment on the documentation page, or contact directly with the author of the library. He seems to be really helpful(I've contacted him before).
I'm new to C# and I have been trying to play a sound using SoundPlayer class. So in my solution in visual studio (2015 community), I created a folder called Music and drag'n'dropped a wav file there. In properties, I found the file path and then used in the SoundPlayer constructor. Right now, it's on the desktop.
My problem is that I'll be moving the actual program (it's just console app) to another computer (with different user name...which I don't know). So is there a way C# can determine the new location (directory) for the file so that I don't get an error?
SoundPlayer spPlayer = new SoundPlayer (#"C:\Users\tvavr\Desktop\Dango\mr_sandman.wav");
spPlayer.Play();
This is the code that works. Now, how am I supposed to change that path?
Thx for your answers.
use dynamic path as following :
SoundPlayer spPlayer = new SoundPlayer (Application.ExecutablePath +#"\mr_sandman.wav");
where Application.ExecutablePath will get your application folder dynamically
This is a design decision that only you can answer. When you write console applications that require you to load a file, you have several options
Option #1: Have the path specified in the argument list of the program when it is executed
Assume the name of your program is playsong, you run it like this:
playsong C:/path-to-music-file/song.wav
You get the name of the song file from the argument list of Main. The first item in args is the filename:
static void Main(string[] args) {
SoundPlayer spPlayer = new SoundPlayer(args[1]);
spPlayer.Play();
}
Option #2: Access the song file by hard coded path
static void Main() {
SoundPlayer spPlayer = new SoundPlayer("C:/playsong/songs/song.wav");
spPlayer.Play();
}
Option #3: Access the song file relative to the program location
static void Main() {
SoundPlayer spPlayer = new SoundPlayer(Application.ExecutablePath + "/songs/song.wav");
spPlayer.Play();
}
If you later want to change this into a Graphical User Interface (GUI) program, you would bring up the OpenFileDialog box which lets the user choose the file.
.NET has built-in tools to access locations like current user's desktop:
System.Environment.SpecialFolder.Desktop
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C# Windows 'Open With >' Context menu behaviour
How do I do this? Like if I right click on a file and click open with, then my program how do I do stuff to that file :/.
I use the following code to pass the first argument (the one that contains the file name) to my gui application:
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(args.Length == 0 ? new Form1(string.Empty) : new Form1(args[0]));
}
}
I test to see if there is an argument. If not and a user starts your program without one then you may get an exception in any code that tries to use it.
This is a snippet from my Form1 that deals with the incoming file:
public Form1(string path) {
InitializeComponent();
if (path != string.Empty && Path.GetExtension(path).ToLower() != ".bgl") {
//Do whatever
} else {
MessageBox.Show("Dropped File is not Bgl File","File Type Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
path = string.Empty;
}
//.......
}
You will see that I am checking the extension sent in - my app only works with one extension type - .bgl - so if the user tries to open some other file extension then I stop them. In this case I am dealing with a dropped file. This code will also allow a user to drag a file over my executable (or related icon) and the program will execute wit hthat file
You might also consider creating a file association between your file extension and your program if you have not already. This in conjunction with the above will allow the user to double click on your file and have your application open it.
The path to the file being opened is passed as a command line argument to your application. You need to read that argument and open the file from that path.
There are two ways to do this:
The easiest way is to loop through the values of the args array passed as the single parameter to the Main method:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
}
The second way to do it is to use the Environment.GetCommandLineArgs method. This is useful if you want to extract the arguments at some arbitrary point within your application, rather than inside of the Main method.
I have a C# WinForm App that I created to store files in a seperate secure location on the hard drive. I am trying to add functionality to the program by adding a right-click context menu so when a user right-clicks a file (or group of files) in windows, my program is there in the context for them to select. No problem there, I have that part worked out. What I need is to programmatically get that list of files and send it to the program so they are listed in the listbox already.
I am already doing something similar with a multiselect in an OFD, but I dont want them to have to open the program, select browse, find the files and select them when they already have them selected in windows.
There are a ton of programs out that have this functionality (like properties plus, textpad, etc...) I just need a shove in the right direction to help me figure this out.
Thanks in advance,
Dave
If I'm correctly understanding what you've already implemented, then all the files should appear as arguments on the program's command line. You just need a way of extracting each of those file paths and displaying them in your list view.
In C#, the following code will display a message box containing each argument on the command line:
static void Main(string[] args)
{
foreach(string arg in args)
{
MessageBox.Show(arg);
}
}
But in case you don't want to access these in the Main method, you can also use the Environment class, which provides the static GetCommandLineArgs method. It returns the same array of strings containing the arguments, and you can loop through it the same way.
Here is an article on how to customise Right-Click Menu Options in Windows
Then just as #CodyGray says use the string[] args in your Main method of you program to get the filenames
I am gathering all the arguments and sending them to an ArrayList.
static void Main(string[] args)
{
ArrayList myAL = new ArrayList();
foreach (string arg in args)
{
myAL.Add(arg);
}
ALRec nalr = new ALRec();
nalr.getArrList(myAL);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
sending it to ALRec Class
class ALRec
{
ArrayList MyArrLst = new ArrayList();
public void getArrList(ArrayList AL)
{
MyArrLst = AL;
}
}
Why is it starting multiple instances of my App?
I assume this is a shared resource somewhere in Windows. Rather than making a copy for each app, is there a way to use this icon just like all Winforms apps use it?
How is this specified for Winforms apps by default? I don't see any reference of any icons in code or project settings. Just that it uses the "default icon".
It is stored as a resource in the System.Windows.Forms.dll assembly. You could get a copy with Reflector. Open the assembly, open the Resources node, all the way down to "wfc.ico". Right-click, Save As. Not sure why you'd want to use it, given that it is the default.
You set a custom icon for your application with Project + Properties, Application tab, Icon setting. Each form has its own Icon property.
If you have Visual Studio 2010 installed then there is a large collection of icons (potentially including the application icon/s), check out the following directory:
%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\VS2010ImageLibrary\1033
There may be a similar directory for previous VS versions, take a look if needs be.
EDIT:
On doing a search in the folder of the unzipped file for app there are two notable results:
Application.ico and ApplicationGeneric.ico + its *.png counterpart.
If you have VS 2010 and any of the icons in here are suitable, I believe you don't need to copy a single one - you should be able to include the file indirectly (as a shared/linked file) when adding using the Existing Item... dialog; you do this by selecting the arrow next to Add button and selecting the Add As Link option.
What I can't see working as desired is simply overwriting these files in an attempt to apply a global change.
It is stored as a resource in the System.Windows.Forms.dll assembly. You could get a copy with reflection as folow:
public static class FormUtils
{
private static Icon _defaultFormIcon;
public static Icon DefaultFormIcon
{
get
{
if (_defaultFormIcon == null)
_defaultFormIcon = (Icon)typeof(Form).
GetProperty("DefaultIcon", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null, null);
return _defaultFormIcon;
}
}
public static void SetDefaultIcon()
{
var icon = Icon.ExtractAssociatedIcon(EntryAssemblyInfo.ExecutablePath);
typeof(Form)
.GetField("defaultIcon", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
.SetValue(null, icon);
}
}
public static class FormExtensions
{
internal static void GetIconIfDefault(this Form dest, Form source)
{
if (dest.Icon == FormUtils.DefaultFormIcon)
dest.Icon = source.Icon;
}
}
So as you can see in the code you have in this way the same Icon.Handle. The same reference.
Form.DefaultIcon is an internal lazy loaded static property in class Form.
You can also override the default Winforms icon for your application. In Program.cs i use:
FormUtils.SetDefaultIcon();
This function will then override the default icon with the icon specified in your Application properties, the icon of your executable.
You can just use the Save method:
C#:
string IcoFilename = "C:\\Junk\\Default.ico";
using (System.IO.FileStream fs = new System.IO.FileStream(IcoFilename, System.IO.FileMode.Create))
{
this.Icon.Save(fs);
}
Visual Basic:
Dim strFilename As String = "C:\Junk\Default.ico"
Using fs As New System.IO.FileStream(strFilename, IO.FileMode.Create)
Me.Icon.Save(fs)
End Using
I had a problem which was similar, but different. Rather than needing to get the default icon, I needed to check to see whether the icon on a form was set or if it was left as the default. While I could have used reflection to get it, I ended up using a simpler solution:
private static Icon defaultIcon = new Form().Icon;
// ...
if(this.Icon == defaultIcon)
{
// ...
}