Context Shell Menus - Get identifier on click - c#

I have created a context shell menu for / on .txt files.
Its 'action' is similar to that of 'Edit with notepad' option.
I am able to open 'notepad' on clicking the menu using this code -
subKey.SetValue("", "C:\\Windows\\System32\\notepad.exe");
//subKey is the newly created sub key - The key creation part works fine.
How will I be able to use a feature similar to that of the 'Edit with notepad' feature? Or is it at least possible to get the name of the '.txt' file on which this event was triggered?
Note: By 'Edit with notepad', I mean viewing the selected file's contents in notepad.

The shell (explorer.exe) will substitute %1 with the file name. So you basically write:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\txtfile\shell\openwithnotepad]
#="Open with &Notepad"
[HKEY_CLASSES_ROOT\txtfile\shell\openwithnotepad\command]
#="\"C:\\Windows\\System32\\notepad.exe\" \"%1\""
The file name will be passed to C:\Windows\System32\notepad.exe as a command line argument. For example if you open D:\blah.txt, then notepad will receive D:\blah.txt as the first argument.
In C#, you basically use either Environment.GetCommandLineArgs() or args in Main to retrieve the file path.
An example:
string[] commandLineArgs = Environment.GetCommandLineArgs();
string fileToOpen = null;
if (commandLineArgs.Length > 1)
{
if (File.Exists(commandLineArgs[1]))
{
fileToOpen = commandLineArgs[1];
}
}
if (fileToOpen == null)
{
// new file
}
else
{
MyEditor.OpenFile(fileToOpen);
}

Related

Opening a Link/File through button click event

I am still new to the WPF/XAML coding and while learning I encountered another problem. I decided I want to add buttons on the UserControl, that I would like to make them do a few different things. On one of them, I want to open the local default browser and open a webpage link, and in another button, I want to start a local exe/rpm file from a directory in my project called "tools".
For opening the link I tried - WebBrowserTask which is an unrecognized event/task
For the running of the application - Process.Start("thelocation/thefile.exe/rdp"). After that, I tried guiding it to the proper path, but my project doesn't recognize the folder and files inside.
Both tries were unsuccessful.
Try this:
public void DoSomething
{
const string webpageUrl = "https://stackoverflow.com/questions/55778625/";
const string localFile = #"C:\Windows\notepad.exe";
var localTools = $#"{AppDomain.CurrentDomain.BaseDirectory}Tools\SomeTools.exe";
Process.Start(webpageUrl);
Process.Start(localFile);
Process.Start(localTools);
}
to opening an web page your address must be start with http://...

Directory right click

I'm designing a C# WinForms program that when the user right clicks on a directory and selects the item which I added to shell context menu (which opens the .exe for my application), it runs in the background based on where the user right clicks.
I've already figured out how to install it and add it to the correct context menu, but I can't seem to figure out the most crucial part of the program. I've already looked here, but that doesn't answer my question and the answer it gives just leads to another question.
I also realize that command line arguments exist, and that is how this question is answered. When I go onto Microsoft's website about using command line arguments, it is only about using an actual command line, which I am not using.
So my question is:
How exactly do I get the directory path when a user right clicks a folder and choose the shell context menu which I added?
If I have to use a command line in the background, that is fine I just need to be able to get and send the directory path to my program.
Here is relevant code for how I use the entered directory. In essence source is the directory path that I want when the user right clicks.
private void recursiveCheck(string source)
{
string[] directories = Directory.GetDirectories(source);
foreach(string directory in directories)
{
string test = new DirectoryInfo(directory).Name;
if (test.Length >= 3 && (test.Substring(test.Length - 3).Equals("val", StringComparison.InvariantCultureIgnoreCase) || (test.Substring(test.Length - 3).Equals("ash", StringComparison.InvariantCultureIgnoreCase)))
{
if (Directory.Exists(directory + "\\STARTUP"))
testing_dir(directory);
else
{
MessageBox.Show("Error! Startup folder does not exist in: " + test);
Application.Exit();
}
}
else
recursiveCheck(directory);
}
}
I assume you have added your application to the context menu of folders in registry:
HKEY_CLASSES_ROOT
Directory
shell
OpenWithMyApp → (Default): Open With My App
command → (Default): "c:\myapp.exe" "%V"
The key point is in %V. It will be the folder name which you right clicked on it and it will be passed to your application as command line argument.
Then in your application, it's enough to have something like this:
[STAThread]
static void Main()
{
string folderName = null ;
if (Environment.GetCommandLineArgs().Length > 1)
folderName = Environment.GetCommandLineArgs()[1];
MessageBox.Show(folderName);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(new Form1());
}

Register context menu verbs for specific file types

I'm registering extended verbs for all video file types on my system by doing something like this:
foreach (var ext in FileTypes.VideoTypes)
{
var progId = Registry.GetValue($#"HKEY_CLASSES_ROOT\.{ext}", null, null);
if (progId == null)
{
continue;
}
Registry.SetValue(
$#"HKEY_CURRENT_USER\SOFTWARE\Classes\{progId}\shell\dlsub",
null,
"Download subtitle");
Registry.SetValue(
$#"HKEY_CURRENT_USER\SOFTWARE\Classes\{progId}\shell\dlsub\command",
null,
#"""D:\myapp.exe"" ""%1""");
}
Resulting in something like this (mpeg_auto_file for mkv):
[HKEY_CLASSES_ROOT\mpg_auto_file\shell\dlsub]
#="Download subtitle"
[HKEY_CLASSES_ROOT\mpg_auto_file\shell\dlsub\command]
#="\"D:\\myapp.exe\" \"%1\""
and mplayerc.mp4 for mp4:
[HKEY_CLASSES_ROOT\mplayerc.mp4\shell\dlsub]
#="Download subtitle"
[HKEY_CLASSES_ROOT\mplayerc.mp4\shell\dlsub\command]
#="\"D:\\myapp.exe\" \"%1\""
The problem is that the registered verb shows up for mkv (and a couple of other filetypes), but the context menus for the other file types (like mp4) are unaffected. Adding my verb to HKEY_CLASSES_ROOT\*\shell does work for these filetypes, but this is obviously not what I want!
Any ideas on the difference between these filetypes? Perhaps it has something to do with the registered ProgID (all mplayerc types do not seem to work...).
The default value (aka ProgId) that can be found for specific file extension doesn't always point to correct class (the one that will affect menu entries). During my tests, even on fresh copy of Windows 10 - WMP11.AssocFile.AVI is a ProgId for .avi file extension, however when added entry in WMP11.AssocFile.AVI\Shell\ (either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER) it didn't affect menu at all. I was about to give up but then i found that HKEY_CLASSES_ROOT\.avi\OpenWithProgids store few more values, including WMP11.AssocFile.AVI but also other that starts with word App, i.e. AppX6eg8h5sxqq90pv53845wmnbewywdqq5h. By editing Shell\ for that one, i was able to add menu entry. The downside was - it also affected other file extensions that are somehow linked with AppX6eg8h5sxqq90pv53845wmnbewywdqq5h. I couldn't accept solution that would force me to iterate through all classes found in OpenWithProgids, plus my menu entry had to be shown only for very specific file extensions and not the other. I decided to go with HKEY_CLASSES_ROOT\*\shellex and DLLs that create menu entry dynamically, based on clicked file type (check for extension).

How can I open a file location or open a folder location in MonoDevelop Gtk#?

I want to open a file's location and select the file in explorer on Mac, Ubuntu from MonoDevelop.
This code is working on Windows (but it is not working on Mac and Ubuntu):
System.Diagnostics.Process.Start("explorer.exe", "/select, " + fileaddress);
Dim dir_path As String = "/media/os/test"
' Windows path example: dir_path = "C:\test"
Process.Start("file://" & dir_path)
Tested and worked on Ubuntu and Windows XP.
Source: http://www.stevenbrown.ca/blog/archives/156
By 2020-10, in mono 6.10, the above method didn't work on Ubuntu 20.04. The below approach solved the problem.
System.Diagnostics.Process.Start("mimeopen", "/var/tmp");
You can use 'open' on Mac, like this
System.Diagnostics.Process.Start("open", $"-R \"{File_Path_You_Wanna_Select}\"");
Here -R means reveal, to select in the Finder instead of opening.
To find more usage for open, just type open in terminal.
Using Process.Start() you bypass the .NET framework and move into the platform you're running onto, executing an arbitrary process.
On Windows you want to open the Windows Explorer, on Mac you want to open Finder and on Ubuntu it's simply called File Browser.
There is no Environment.OpenFileBrowser(string path) method in the framework, so you will have to let your program determine which platform it is running on, and open the approperiate file viewer.
See How to check the OS version at runtime e.g. windows or linux without using a conditional compilation statement to perform the former.
You are calling an OS specific (Windows) method. That won't work cross-platform.
Try the following inside a function/method:
Example - inside click event:
protected void OnOpen (object sender, EventArgs e)
{
using(FileChooserDialog chooser =
new FileChooserDialog(null,
"Select document to open...",
null,
FileChooserAction.Open,
"Open Selected File",
ResponseType.Accept,
"Discard & Return to Main Page",
ResponseType.Cancel))
{
if (chooser.Run () == (int)ResponseType.Accept)
{
System.IO.StreamReader file = System.IO.File.OpenText (chooser.Filename);
/* Copy the contents to editableTxtView <- This is the Widget Name */
editableTxtView.Buffer.Text = file.ReadToEnd ();
/* If you want to read the file into explorer, thunar, Notepad, etc.,
* you'll have to research that yourself. */
//Close file - - KEEP IT CLEAN - - & deAllocated memory!!
file.Close ();
}
}
}
The file has now been copied into an editable (Default) or read only (set in properties pad) textviewer Gtk widget. From there you should be able to manipulate it as you so choose.

How to get the (.lnk) shortcut filepath in a program which started by the shortcut?

I have a c# program which open *.postfix file.
If a user runs a (.lnk)shortcut which points to my type of file, my program will open the target.
So, how could my program know it is started by a (.lnk)shortcut (and get it's file path)?
In some circumstances,i need to replace the .lnk file.
Thanks!
Edited
First, thanks to guys who answered my question.
By following #Anders answer, i find out my problem lays here.
I made some changes to windows registry, so browser knows to throw customized protocol string to certain program.
some thing like this..
[InternetShortcut]
URL=myProtocol://abcdefg.....
That's maybe why i lost lpTitle. :(
I'm going to try this way:
Whenever my program invoked, of course fed with %1, program checks current opened explorer(Window), and try to get it's current path with IWebBrowserApp. With that path and desktop of course, scan and analyze *.lnk to determine which one to replace.
I think this will probably work, but not be sure. I will try.
continued
In native code you can call GetStartupInfo, if the STARTF_TITLEISLINKNAME bit is set in STARTUPINFO.dwFlags then the path to the .lnk is in STARTUPINFO.lpTitle. I don't know if there is a .NET way to get this info, you probably have to P/Invoke...
You don't. There's no way to do it. End of story.
So this has been brought to my attention due to a recent downvote. There's an accepted answer showing an idea that gets the path to the launching shortcut most of the time. However my answer is to the whole. OP wants the link to the shortcut so he can change it. That is what can't be done most of the time.
Most likely case is the shortcut file exists in the start menu but is unwritable. However other cases involve the shortcut coming from another launching application that didn't even read it from a disk but from a database (I've seen a lot of corporate level restricted application launch tools). I also have a program that launches programs from shortcuts not via IShellLink but by parsing the .lnk file (because it must not start COM for reasons) and launching the program contained. It doesn't pass STARTF_TITLEISLINKNAME because it's passing an actual title.
If you're using Visual Studio Setup Project to build an installer and do the file type association, you should follow these instructions http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Open up your solution in Visual studio.
Add a Setup Project to your solution by file , add project,New project, Setup & Deployment projects,Setup project
Right-click on your setup project in the "Solution Explorer" window,Select view,then select file types.
you'll see the "file types" window displayed in Visual studio.At the top of the window will be "File types on target machine"
Right-click on "File types on target machine".the menu will pop up with Add "file type" Click on this.
you'll see "New document Type#1" added,and "&open"underneath it.
The "new document type#1" can be anything you want - change it to something descriptive.although the user never sees this,never use something common- be as unique as possible,Because you can overlay current file associations without even realizing it.For example,you might think"pngfile" might be a useful name- but using that will now send all"*.png" files to your application,instead of to an image viewer.A good practice maybe "YourCompantName.Filetype",where your company name is your name of your company's name, and "Filetype" is a descriptive text of your file.
In the "properties" window for your new type,you will need to change a few properties.:
Command:Change to the application that you want to run.If you click on the "..." and you will proberly want to locate and use the "primary Output..." File
Description: This is the description of the file type(if it doesn't describe it's self"
Extensions:This your list of extensions for you chosen Program.Separate each one with a ","
Icon:This will associate the icon with your file type,This shows up in the window explorer.
Now we move to that "&open ".This is an action that is available if your right-click on the file.The default action("&Open" is currently set as the default) is what happens when you double click on the file.Right click on your "New document type#1" to add actions,but for the moment,lets define our "&open" action
Click on "&Open".You will see in the properties window "Name","Arguments","Verbs". Verb is hidden from the user,but is the key that is stored in the registry.Leave it same as the name,But without the "&".The default for"Arguments" is "%1",Which means to pass the full path and filename to your application.You can add other stuff here as well,if you need to pass flags to your application to do special stuff.All this infomaton is getting passed to your application on the command line,so you'll need to be familiar with the "Environment.CommandLine" object.
If you need to set a different action as your default,just right click on the action and "set as default"
Basically, you'll pass the file path as an argument to your program. Then if it's a console application or Windows Forms , you should check the arguments in Program.Main
static void Main(string[] args)
{
//if file association done with Arguments %1 as per forum post above
//you file path should be in args[0]
string filePath = null;
if(args != null && args.Length > 0)
filePath = args[0];
}
For a WPF application you'll need to handle that in the StartUp event for your Application
void App_Startup(object sender, StartupEventArgs e)
{
string filePath = null;
if ((e.Args != null) && (e.Args.Length > 0))
{
filePath = e.Args[0];
}
}

Categories

Resources