Подтвердить что ты не робот

В Windows, что явно происходит при двойном щелчке по файлу в проводнике Windows?

TL; DR

Каковы точные, низкоуровневые вызовы ядра и ОС, которые выполняются, когда пользователь дважды щелкает или выбирает файл и нажимает клавишу Enter из проводника Windows?


Подробнее

Это может показаться довольно странным вопросом, но мне любопытно очень "подробные" подробности открытия файла из проводника Windows.

В частности, то, что я хотел бы знать, - это точные, низкоуровневые вызовы ядра и ОС, которые выполняются, когда пользователь дважды щелкает или выбирает файл и нажимает клавишу Enter из проводника Windows.

Причина, по которой я спрашиваю, заключается в том, что у меня есть приложение, которое позволяет пользователям просматривать и искать файлы на основе метаданных, хранящихся в базе данных. Когда пользователь нажимает кнопку Open, которую я предоставил, я запускаю процесс, в котором корневой файл представляет собой путь к выбранному файлу. Кроме того, стоит упомянуть, что эти файлы находятся в сетевом ресурсе.

Это работало годами, однако недавно моя компания перешла на новый сервер Active Directory, и теперь приложение разбито на очень небольшое количество пользователей (1-2%.) Самое странное, что эти пользователи не могут открыть этот файл из моего приложения, но они могут перейти к местоположению и открыть его из проводника Windows. Когда мое приложение пытается открыть файл, оно получает очень общее исключение, заявляя, что файл не может быть найден.

Я проверил тройной путь, который использует приложение (для нескольких файлов), и путь не является неправильным. Я подтвердил, что мои пользователи подключены к этим сетевым дискам и открывают файлы. Все правильно настроено и должно работать, но мое приложение (или System.Process) не может "видеть" или открывать эти файлы.

Что делает приложение Windows Explorer по-другому, чем использование 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, но он не должен/не должен применяться к этому вопросу. Мое приложение просто пытается открыть PDF файлы и некоторые инженерные файлы чертежей. Ничего необычного, и он не должен требовать доступа администратора. Кроме того, я не считаю, что требуется аутентификация пользователя, поскольку большинство пользователей никогда не получают это сообщение, и они уже проверили себя в сети, выполнив вход в систему и просмотрев ее в сетевом расположении.

4b9b3361

Ответ 1

Каковы точные, низкоуровневые вызовы ядра и ОС, которые выполняются, когда пользователь дважды щелкает или выбирает файл и нажимает клавишу Enter из проводника Windows?

Вы можете проверить это самостоятельно. Вот как я это сделал: пример кода программы С#

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

    }        
}

Теперь вы можете запустить это приложение из заранее определенного местоположения. Затем вы можете использовать приложение ProcMon из SysInternals для наблюдения за вызовами низкого уровня. Вот снимок csv файла, который был сгенерирован ProcMon на моей машине. Я поместил фильтр, чтобы включить 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"
...

Полная версия csv доступна на pastebin. Каждая строка в файле csv соответствует вызову низкого уровня, плюс есть другой пух, который был исключен из-за строгого фильтра на пути.

Ответ 2

Очень распространенный режим отказа и присутствует в вашем коде, не правильно устанавливает ProcessStartInfo.WorkingDirectory. Подмножество программ полагается на проводник, устанавливая рабочий каталог по умолчанию в каталог, который содержит файл, и падает, когда он не установлен. Они сделают что-то неразумно, как попытку открыть файл конфигурации без указания полного имени пути, который работает только в том случае, если рабочий каталог установлен правильно.

Вы исправляете это следующим образом:

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

Предполагается, что вы не делаете ту же ошибку, что и не указывать полное имя пути для файла.

Ответ 3

Вопрос "TL; DR" является кратким и точным, но я не уверен, что ответ на этот вопрос поможет решить вашу проблему. Ответ Hans Passant, вероятно, гораздо полезнее. Тем не менее я попытаюсь предоставить небольшую информацию.

В Windows есть несколько уровней, и в этом случае двумя интересными слоями являются API оболочки Windows и API системных служб. Вы используете Process.Start() таким образом, чтобы называть ShellExecuteEx в Windows Shell. Windows Shell предоставляет абстракцию поверх Windows, где у вас есть рабочий стол (который действительно является папкой на каком-то диске), и файлы обрабатываются как документы с значками и глаголами для работы с этими документами. В вашем случае вы используете глагол Open.

Шлюз Windows довольно сложный и может быть расширен, что делает ShellExecuteEx для определенного пути, а глагол - легко ответить. Это зависит от того, что зарегистрировано на локальной машине. Однако, если файл является файлом PDF, а глагол Open, вы ожидаете, что оболочка будет запускать любое приложение, связанное с расширением .PDF в реестре.

В Windows 7 вы можете исследовать и изменять привязки файлов в Панели управления > Программы > Программы по умолчанию > Установить ассоциации. Я подозреваю, что если программа, связанная с расширением .PDF, отсутствует, вы можете получить FileNotFoundException, но я не подтвердил это.

Если оболочка решает, что приложение должно быть выполнено, он в какой-то момент вызовет уровень системных служб и воспользуется функцией CreateProcess, чтобы создать новый процесс. Для файла PDF (в зависимости от регистрации для .PDF) будет создан процесс, выполняющий Acrobat.exe с одним аргументом командной строки (указанным вами файлом).

Чтобы устранить проблему, вы можете в командной строке написать file.pdf (файл должен существовать) и посмотреть, сможет ли оболочка открыть файл PDF.

Ответ 4

Можете ли вы попробовать что-то подобное, используя 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);