在Windows中,当我在Windows资源管理器中双击文件时会发生什么?

时间:2012-09-27 13:47:06

标签: c# .net windows windows-explorer

TL; DR

什么是精确的低级内核&当用户双击或选择文件并从Windows资源管理器中按下Enter键时,正在执行的OS调用?


详情

这似乎是一个相当奇怪的问题,但我对从Windows资源管理器中打开文件的非常“细节”细节感到好奇。

具体来说,我想知道的是精确的低级内核&当用户双击或选择文件并从Windows资源管理器中按下Enter键时,正在执行的OS调用。

我问的原因是因为我有一个应用程序允许用户根据存储在数据库中的元数据浏览和搜索文件。当用户单击我提供的Open按钮时,我启动一个进程,其中根文件是已选择文件的路径。此外,值得一提的是这些文件位于网络共享上。

这已经工作了多年,但是,最近我的公司已经迁移到一个新的Active Directory服务器,现在该应用程序被一小部分用户破解(1-2%)。真的很奇怪的是这些用户无法从我的应用程序打开此文件,但他们可以浏览到该位置并从Windows资源管理器中打开它。当我的应用程序尝试打开该文件时,它会得到一个非常通用的异常,指出无法找到该文件。

我已经三次检查了应用程序正在使用的路径(对于多个文件)并且路径不正确。我已经验证我的用户在打开文件之前已经连接到这些网络驱动器。一切都设置正确,应该可以,但我的应用程序(或System.Process)无法“看到”或打开这些文件。

什么是Windows资源管理器应用程序与在应用程序中使用System.Process的做法不同?


对于那些在回答之前必须拥有代码的人,这里是我用来打开文件的特别简洁的代码。同样,这已经工作多年了,据我所知,你是如何让Windows从.Net中打开文件的。

//From within 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"
}

还有一件事。我在SO上找到了this question但它没有/不应该适用于这个问题。我的应用程序只是试图打开PDF和一些工程图纸文件。没什么好看的,它不应该要求管理员访问。此外,我不认为应该要求任何用户身份验证,因为大多数用户从未收到此消息,并且他们已经通过登录并浏览到网络位置在网络上验证了自己。

4 个答案:

答案 0 :(得分:6)

一种非常常见的故障模式,并且存在于您的代码中,并未正确设置ProcessStartInfo.WorkingDirectory。程序的一个子集依赖于Explorer将默认工作目录设置为包含该文件的目录,并在未设置时覆盖。他们会做一些不明智的事情,比如试图在没有指定完整路径名的情况下打开配置文件,这只有在工作目录设置正确的情况下才有效。

你这样修理:

Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(file);
p.Start();

假设您没有为文件指定完整路径名而犯同样的错误。

答案 1 :(得分:6)

  

什么是确切的低级内核&用户双击或选择文件并在Windows资源管理器中按Enter键时正在执行的OS调用?

您可以自己测试一下。我是这样做的:一个示例C#程序代码

class Program
{
    static void Main(string[] args)
    {

    }        
}

现在,您可以从预定位置运行此应用程序。然后,您可以使用SysInternals中的ProcMon应用程序来观察低级别调用。这是由我的机器上的ProcMon生成的csv文件的快照。我只放了一个过滤器,将path包含在文件中,即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"
...

pastebin上提供完整版csv。 csv文件中的每一行都对应一个低级别的调用,另外还有其他的漏洞由于路径上的严格过滤而被排除。

答案 2 :(得分:2)

你“TL; DR”问题很简短,但我不确定回答这个问题会解决你的问题。 Hans Passant的回答可能更有用。不过,我会尝试提供一些信息。

Windows有几个层,在这种情况下,两个有趣的层是 Windows Shell API和系统服务 API。您正在使用Process.Start()以在Windows Shell中调用ShellExecuteEx的方式。 Windows Shell在Windows上提供了一个抽象,您可以在其中拥有一个桌面(实际上是某个磁盘上的文件夹),并将文件视为带有图标和动词的文档来操作这些文档。在您的情况下,您使用的是Open动词。

Windows Shell非常复杂,可以扩展,因此ShellExecuteEx正在为特定路径执行操作,而动词很容易回答。这取决于本地计算机上注册的内容。但是,如果文件是PDF文件且动词为Open,您可能希望shell运行与注册表中.PDF扩展名相关联的任何应用程序。

在Windows 7中,您可以在控制面板>中检查和修改文件关联。 计划> 默认程序> 设置关联。我怀疑如果缺少与.PDF扩展程序相关联的程序,您可能会FileNotFoundException,但我尚未验证。

如果shell决定应该执行某个应用程序,它将在某个时刻调用System Services层并使用CreateProcess函数创建一个新进程。对于PDF文件(取决于.PDF的注册),将创建使用单个命令行参数(您指定的文件)执行Acrobat.exe的进程。

要解决问题,您可以在命令提示符下写file.pdf(该文件应该存在)并查看shell是否能够打开PDF文件。

答案 3 :(得分:0)

你可以使用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);