How to raise the event while double click on any file - c#

I want to write/capture the event when I double click on my file located in Windows folder. Assume that we have some txt file located in D:\MyTest\Example1.txt
When I double click on the file, the file should not open whereas it should fire an event/trigger/service to execute some tasks.
I tried with FileSystemWatcher in C#. But, when I double click on the file, the file is getting opened.(It should not).
A simple requirement for your better understanding given below.
When you double click on any txt file in Windows, it should invoke a simple batch file (Example: a.bat) to display the today's date.
Conditions: When you double click on the file, the .bat file should run without opening the actual txt file.

FileSystemWatcher monitor specific path for any file add/remove/modification and not for file execution.
There are different solution based on your needs :
The simplest solution is to register your program for own file extension. by double clicking on file your program got executed and you can just log it and do nothing any more or open the requested file using actual program. for example "Notepad.exe 1.txt"
Write a hook module and load it into explorer's process and watch for file execution but the chief drawback of this solution is third party apps or tricks to open a file that make no sense in your program. for example using CMD.exe or PowerShell.exe to open text file because you monitor specific program.
You can inject your hook module into all executables but it is possible to make performance issues.
The beset solution is to write MiniFilter driver to monitor file system but it need to good system, user mode, c++ and driver development knowledge.
It's possible to implement a virtual file system and control everything over it and again it need to driver development but there is good C# ports for existing libraries, the best one for C# is Dokan .Net
Describe the simplest way to implement :
Write simple program without any form like this :
static void Main(string[] args)
{
if (!args.Any())
return;
foreach (string argument in args)
{
if (Path.GetExtension(argument) != "txt")
continue;
if (Path.GetDirectoryName(argument) == #"D:\MyTest\")
{
// Call your service event here
return;
}
Process.Start("Notepad.exe", argument);
}
}
Register your program for own file extension (in your case .txt) using registry configuration. Here is Microsoft documentation and maybe this topic help you.
Now by double clicking on a .txt file your program got executed and path of the file(s) passed to your program as arguments. program check each file and if you want you can call something or notify your service using different mechanisms like Pipes or Messages or etc.
If the file is not match you want the original application called (in my sample code "nodepad.exe") and the file open normal.

Related

Opening application with file C# Winforms

So I'm making a Notepad replica in my spare time just for fun, the core of the project is all done. However, I can't open my application from a file. For example, if you had a .txt file, you double click it and it would open the app (by default its Notepad).
I already know how to set the default application, but the code does not support opening the files yet, it can only open files from the menu inside the program.
How would I go about making it so that my application can be opened by files?
in you void Main(string[] args) method, the args will contain the path to the file that was opened with your application. You can also get them anywhere in the application by calling string[] Environment.GetCommandLineArgs(). Print the argument in a message box to see what arguments have been passed.
Here's some code you might want to use for that:
//In a form
public void MyButton_Clicked(object sender, EventArgs e)
{
string[] args = Environment.GetCommandLineArgs();
MessageBox.Show(string.Join(Environment.NewLine, args));
}
I like your question. Once you provide support for opening type files, and you find that your application is still not working, perhaps this might be useful: you can check under registry section HKEY_CLASSES_ROOT for the extension and action details. It talks about default applications, but it gets into more details.
Here's the page:
Finding the default application for opening a particular file type on Windows

How to run a program using is extension association only.

I would like to create a program that will allow a user to select a file they wish to open using an openFileDialog and then on return, my program will open that file in whatever program is associated with that file in the registry.
Apart from searching the registry for determining the location etc of the executing program, is there an simpler way as in using Process or similar?
You can still use Process.Start(filePath) for this functionality. You are not required to use a path to an executable.
For example, if you write
Process.Start("test.txt");
Windows will open test.txt in whatever program is currently associated with text files (e.g. notepad).

How to monitor windows service text output

For my windows service, I have a procedure that outputs log entries to a text file. That all works well, but I can not see it live. As soon as I open the file to see the log, it stops writing to it, because the service can't write to an open file, I'm assuming.
My question: Is there a way to monitor this text output with something like the console? This solution will only be used for debugging purposes. I don't want a GUI or anything like that--just something simple to watch what my logger is doing.
Right now to write to the text file I'm doing:
RecordDataToLog("Log this");
private void RecordDataToLog(string txtData)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(logFileDir, true))
file.WriteLine(txtData);
}
I tried to use Console like this, but it didn't work--no console window showed.
Console.WriteLine("Log this");
Or is there another text editor or text file type that supports writing to an open file?
I opened the file with notepad and Notepad++ and was still able to write to the file with StreamWriter, so it must be the editor you are opening the file with. Notepad doesn't refresh the contents at all. You need to reopen the file. Notepadd++ should prompt you and ask if you want to reload.
PowerShell v3 includes an option on the Get-Content cmdlet to open a file and print new content as it is added, similar to tail on *nix OSes:
Get-Content "C:\path\to\log\file" -Wait
You will reduce your pain in this area significantly by using a logging framework, such as log4net or NLog.
These will allow you to configure multiple output formats in a separate configuration file. I've converted a home-grown logging system to log4net. Took about half a day to do this - and this was a relatively large commercial application.
You can use Notepad++.
If you start it in the command-line by writing
notepad++.exe -ro "MyLogFile.txt"
then it will open the file in read-only mode.
You can use the Get-Content cmdlet from PowerShell to tail your log file
You can use also the "monitor" tool of NotePad++ (it's an icon with an eye).. doing so NotePad will automatically show you the updated file every time it will be modified by your app

Within Windows, what explicitly happens when I double-click on a file in Windows Explorer?

TL;DR
What are the exact, low-level kernel & OS processes that are being executed when a user either double-clicks or selects a file and presses the Enter key from within Windows Explorer?
Details
This may seem like a rather odd question, but I'm curious about the very nitty-gritty details of opening a file from Windows Explorer.
Specifically, what I would like to know are the exact, low-level kernel & OS processes that are being executed when a user either double-clicks or selects a file and presses the Enter key from within Windows Explorer.
The reason I ask is because I have an application that allows for users to browse and search for files based off of meta-data stored in a database. When a user clicks the Open button that I've provided, I start a process where the root file is the path to the file that has been selected. Also, it is worth mentioning that these files are on a network share.
This has worked for years, however, recently my company has migrated to a new Active Directory server and now the application is broken for a very small handful of users (1-2%.) The really odd thing is that these users cannot open this file from my application, but they can browse to the location and open it from Windows Explorer. When my application attempts to open the file, it gets a very generic exception stating that the file couldn't be found.
I've triple checked the path that the application is using (for multiple files) and the path is not incorrect. I've verified that my users have, and are, connected to these network drives before opening the files. Everything is setup correctly and should work but my application (or System.Process) can't "see" or open these files.
What is the Windows Explorer application doing differently than using System.Process from within an application?
For those who must have code before answering, here is the exceptionally terse code that I use to open a file. Again, this has worked for years and, as best I know, is how you let Windows open a file from within .Net.
//From my Button-Click Event...
string file = e.Cell.Value.ToString();
try
{
Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.Verb = "Open";
p.Start();
}
catch (Exception ex)
{
MessageBox.Show("A problem has occurred while trying to open the doccument."
+ "Please make sure that the file below exists and that you have permission "
+ "to view it."
+ Environment.NewLine + Environment.NewLine
+ file
+ Environment.NewLine + "---------------" + Environment.NewLine +
ex.Message
);
//ex.Message states "The system cannot find the file specified"
}
One more thing. I found this question on SO but it doesn't/shouldn't apply to this question. My app is simply trying to open PDFs and some engineering drawing files. Nothing fancy, and it shouldn't require admin access. Also, I don't believe any user authentication should be required since most users never get this message and they've already validated themselves on the network by logging in and browsing to the network location.
What are the exact, low-level kernel & OS calls that are being executed when a user either double-clicks or selects a file and presses the Enter key from within Windows Explorer?
You can test it yourself. Here is how I did it: a sample C# program code
class Program
{
static void Main(string[] args)
{
}
}
Now you can run this application from a predifined location. You can then use a ProcMon application from SysInternals to observe the low-level calls. Here is a snapshot of csv file that was generated by ProcMon on my machine. I have put a filter only to include path to the file, which was c:\test.exe
"Time of Day","Process Name","PID","Operation","Path","Result","Detail"
"14:57:55.3495633","Explorer.EXE","2568","CreateFile","C:\Test.exe","SUCCESS","Desired Access: Generic Read, Disposition: Open, Options: Open Requiring Oplock, Attributes: N, ShareMode: Read, AllocationSize: n/a, OpenResult: Opened"
"14:57:55.3498808","Explorer.EXE","2568","FileSystemControl","C:\Test.exe","SUCCESS","Control: FSCTL_REQUEST_FILTER_OPLOCK"
"14:57:55.3507711","Explorer.EXE","2568","CreateFile","C:\Test.exe","SUCCESS","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened"
...
Full version of csv is available on pastebin. Every line in the csv file corresponds to a low level call, plus there is other fluff which was excluded due to the strict filter on path.
A very common failure mode, and present in your code, is not setting the ProcessStartInfo.WorkingDirectory properly. A subset of programs rely on Explorer setting the default working directory to the directory that contains the file and fall over when it isn't set. They'll do something unwise like trying to open a config file without specifying the full path name, that only works if the working directory is set correctly.
You fix it like this:
Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(file);
p.Start();
Which assumes that you don't make the same mistake of not specifying the full path name for file.
You "TL;DR" question is brief and to the point but I'm not sure answering that question will solve your problem. Hans Passant's answer is probably much more useful. Nevertheless I will try to provide a little information.
Windows has several layers and in this case the two interesting layers are the Windows Shell API and the System Services API. You are using Process.Start() in a way that will call ShellExecuteEx in the Windows Shell. The Windows Shell provides an abstraction on top of Windows where you have a desktop (which really is a folder on some disk) and files are treated as documents with icons and verbs to operate on these documents. In your case you are using the Open verb.
The Windows Shell is quite complex and can be extended so what ShellExecuteEx is doing for a particular path and verb is note easy to answer. It depends on the what is registered on the local machine. However, if the file is a PDF file and the verb is Open you would expect that the shell would run whatever application is associated with the .PDF extension in the registry.
In Windows 7 you can examine and modify the file assocations at Control Panel > Programs > Default Programs > Set Associations. I suspect that if the program associated with the .PDF extension is missing you may get FileNotFoundException but I haven't verified that.
If the shell decides that an application should be executed it will at some point call the System Services layer and use the CreateProcess function to create a new process. For a PDF file (depending on the registration for .PDF) a process executing Acrobat.exe with a single command line argument (the file you specified) will be created.
To troubleshoot the issue you can at a command prompt write file.pdf (the file should exist) and see if the shell is able to open a PDF file.
Can you try something like this using FileSystemInfo.FullName?
string file = e.Cell.Value.ToString();
var fileInfo = new FileInfo(Path.Combine(System.IO.Path.GetDirectoryName(file) + file));
if (!fileInfo.Exists)
{
throw new FileNotFoundException(fileInfo.FullName + " was not found");
}
System.Diagnostics.Process.Start(fileInfo.FullName);

Is there a way in c# to know when the user has finished editing a file with an application?

This is what I'm trying to do :
Download a file (txt, doc, xls, whatever) from a server
Open the file with the appropriate application using System.Diagnostics.Process.Start(path to file)
Monitor for file changes using a FileSystemWatcher.
Each time the file is changed, upload the file back to the server
Continue monitoring until the user has finished editing the file
Delete the local copy of the file
Exit the application
I'm stuck at step 5. How can I know whether a user has finished working on a file ?
I cannot rely on the file being locked (notepad doesn't lock txt files for example).
I cannot rely on a process having exited or not (an example is Notepad++ for txt files : the file could be open in a tab. When you close the tab, you've finished editing the file, but the process is still running)
Any idea/points on how to do that in C# ?
You've excluded the two ways you could go about detecting the file being in use: file locking, and the process you start exiting.
The only alternative I an think of is to display a dialog to ask the user when they've finished editing.
Edit: For what it's worth - FileZilla has this type of behaviour. You can choose to edit a file on the remote server, it downloads the file, launches the default editor, and (in the background) shows a "If you've finished editing - Click OK" button.
This gives me the opportunity to cancel an edit, if I've mucked up the file and saved it.
This is really hard to do - we've tried various things but never found anything that was foolproof. If you know the program you have launched then, in theory, you can find the file handles it uses and see when it stops using the one you're interested in.....but if you rely on Windows to resolve the default application to launch even this becomes tricky.
We copy editable files into a temp folder named with the date and rely on users uploading them back when they have finished their edit session. We then clean up previous days folders on application startup.
You could check the date of last change of the file. This date gets set when you save changes to the file. Mind though that this field is not very reliable since one can set it to any value (with appropriate tools).

Categories