Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top