Проблема с запуском System.Diagnostics.Process под Windows 7

Я пытаюсь запустить приложение (операционная система, мое приложение и приложение, которое я хочу запустить, все 32-разрядные) из.NET 3.51.

Код, запускающий процесс, используется для других приложений, но есть тот, который вызывает у нас головную боль. Если мы "дважды щелкнем" по значку приложения, оно будет работать, как и ожидалось, что означает, что оно отлично работает как приложение на компьютере. Двойной щелчок на.exe напрямую, тоже работает.

Операционная система - Windows 7 32-битная (Домашняя и / или Профессиональная).

Наше приложение.NET скомпилировано с x86, чтобы избежать проблем.

Код, который запускает "Процессы", находится внутри созданной нами DLL (также 32-битной), в основном это простая DLL, которая содержит некоторый "Общий код" по всем направлениям, общие методы, функции и вещи, которые мы используем в нашем коде. Один из этих методов выглядит так:

public static bool FireUpProcess( Process process, string path, bool enableRaisingEvents,
        ProcessWindowStyle windowStyle, string arguments )
    {
        if ( process != null )
        {
            try
            {
                process.StartInfo.FileName = @path;
                if ( arguments != null )
                {
                    if ( arguments != String.Empty )
                    {
                        process.StartInfo.Arguments = arguments;
                    }
                }
                process.StartInfo.WindowStyle = windowStyle;
                process.EnableRaisingEvents = enableRaisingEvents;
                process.Start();
            }
            catch
            {
                try
                {
                    process.Kill();
                }
                catch ( InvalidOperationException )
                {
                } // The process is not even created

                return false;
            }
        }
        else
        {
            return false;
        }
        return true;
    }

Я не знаю, кто написал этот метод, но он работает около шести лет с различными приложениями, поэтому я предполагаю, что это "хорошо". Однако у нас есть клиент с программным обеспечением, которое не запускается при прохождении этого аргумента.

Аргументы:

  1. процесс - это System.Diagnostics.Process, созданный с помощью простого "new Process();"
  2. путь - это полный путь к.exe "c:/path/to/my.exe".
  3. enableRaisingEvents имеет значение false
  4. windowStyle развернуто (но пробовал другие).

Это дает дерьмовый MessageBox... который я счастливо увековечил. Это на испанском, но перевод должен быть легким:

альтернативный текст

Это говорит:

Ошибка приложения Произошло непредвиденное исключение для программы (0x0eedfade) в…

Гугл 0x0eedfade дает странные результаты, которые выглядят страшно, но правда в том, что если я иду к.exe, который я пытаюсь запустить, и дважды щелкаю по нему, он работает отлично.

Для записи: если я пытаюсь запустить другие вещи (например, Notepad.exe, Adobe Acrobat Reader), это работает, но Firefox не открывается и не выдает ошибку.

Такое поведение "что-то работает, а некоторые нет" заставляет меня поверить, что может быть проблема с механизмом безопасности Windows 7 или аналогичным, которого я не знаю.

Что я пропускаю или делаю неправильно?

ОБНОВЛЕНИЕ: Хорошо; Я получил копию программного обеспечения. Это грязное программное обеспечение, но оно работает. Теперь, когда я могу отладить, я вижу, что программа выдает ошибку при запуске с моим FireUpProcess метод.

Как и предполагалось, я добавил код WorkingDirectory, но вот код:

    public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle)
    {
        if (process != null)
        {
            try
            {
                if ( !String.IsNullOrEmpty(@path) )
                {
                    process.StartInfo.FileName = @path;
                    process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);
                    process.StartInfo.WindowStyle = windowStyle;
                    // Suscribe to the exit notification
                    process.EnableRaisingEvents = enableRaisingEvents;
                    // Disable to prevent multiple launchs
                    Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);
                    process.Start(); // HERE The program reports the following:

альтернативный текст

Это означает, что "Программа не может быть запущена, потому что ddip.dll отсутствует... попробуйте переустановить Bla Bla".

Дело в том, что если я выполню тот же @path из командной строки, программа откроется идеально:

альтернативный текст

Это открывает программу. И то же самое происходит, если я нажимаю на "ярлык", который находится в меню "программы". В этом ярлыке нет никаких параметров, это простой вызов исполняемого файла.

Итак, вопрос сейчас: в чем разница между моим кодом и другими методами?

Должно быть что-то другое, что заставляет мой процесс не запускаться.

Есть идеи?

ОБНОВЛЕНИЕ И РЕШЕНИЕ

Я сделал это, используя один из приведенных ниже ответов. Оказывается, никто не указал мне прямо на решение, но все они дали мне хорошие идеи здесь и там.

Я добавил манифест приложения в наше приложение (оно должно было существовать с возраста Vista, не знаю, почему его не было на первом месте). Манифест приложения, который я добавил с помощью VStudio 2008 add file -> манифест приложения.

В этом я удостоверился, что у нас есть это:

<requestedExecutionLevel level=“asInvoker” uiAccess=“false” />

Нам не нужен админ или что-то подобное, но, видимо, Vista/7 должна это знать.

После этого процесс корректно запускается.

примечание: UseShellExecute по умолчанию имеет значение true (как предлагают некоторые), вы должны явно включить его в false, если вы этого хотите.

6 ответов

Решение

Если у exe есть манифест, вы должны установить для UseShellExecute значение true для объекта процесса, прежде чем вызывать Start. В любом случае это неплохая идея.

Вы не устанавливаете свойство process.StartInfo.WorkingDirectory. Существует множество плохо написанных программ, предполагающих, что рабочим каталогом будет каталог, в котором хранится EXE-файл. Как минимум добавьте эту строку:

 process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);

Исключение, однако, довольно странное. Я определенно рекомендую вам сказать клиенту обновить его инструменты защиты от вредоносных программ.

Как указала Кейт Грегори, если вы хотите "эмулировать" пользователя двойным щелчком по значку, вы должны установить для UseShellExecute значение true. Установка этих флагов заставляет код использовать совершенно другой путь, используя базовую функцию Windows ShellExecute.

Теперь я добавлю к этому, что если вы работаете на Windows-оборудованной Windows (Vista, 7, 2008, ...), вам, возможно, следует также попытаться использовать глагол runas, как описано здесь и здесь.

С.NET это будет:

if (System.Environment.OSVersion.Version.Major >= 6)  // UAC's around...
{
   processStartInfo.Verb = "runas";
}

У меня были подобные проблемы в прошлом. Я решил это, выполнив приложение cmd следующим образом:

public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle) 
{ 
    //if path contains " ", surround it with quotes.
    //add /c and the path as parameters to the cmd process. 
    //Any other parameters can be added after the path.

    ProcessStartInfo psi = new ProcessStartInfo("cmd", "/c" + path ));            
    psi.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);          
    psi.WindowStyle = windowStyle;          
    // Suscribe to the exit notification          
    process.EnableRaisingEvents = enableRaisingEvents;          
    // Disable to prevent multiple launchs          
    Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);          
    process.Start(); ...}

Если это возможно, я бы попытался использовать Process Monitor от Sysinternals. При запуске вы можете отменить выбор реестра и сетевой активности на панели инструментов (5 значков справа). Тогда вы видите только активность процесса и диска. Поскольку это похоже на проблему с не найденным файлом, вам следует использовать диалоговое окно "Фильтр" (значок 6. слева), выбрать "Имя процесса" в раскрывающемся списке (по умолчанию используется архитектура) и ввести имя исполняемого файла, на которое не получилось. Это сильно ограничит захваченный вывод, чтобы вы могли видеть, что происходит. Затем запустите execuable и отметьте в столбце "Result" столбец "NAME NOT FOUND". Это места, где файл был найден, но не найден. Если вы знаете оскорбительное имя dll, вы можете найти его с помощью Ctrl+F, как обычно, чтобы найти его. Затем вы можете сравнить различные пути поиска из вашего рабочего приложения и когда он был запущен из вашего приложения.

Может ли быть так, что переменная окружения PATH имеет другое значение внутри вашего процесса? Это может быть добавлением. (текущий каталог) помогает исправить путь поиска DLL. Или приложение запускается из другой учетной записи пользователя? Это также может быть новая функция, которая, когда приложение устанавливает объекты в Programm Files, но не имеет прав (это может сделать только администратор), Windows перенаправляет записи в профиль пользователя. Это безопасный и прозрачный способ стать более безопасным. Но это может вызвать, например, при первом запуске приложения, например, файл конфигурации, который будет развернут в профиле администратора, когда он запускает приложение не с согласия диалогового окна UAC. Тогда другие пользователи также могут запустить приложение, но потерпеть неудачу, потому что дополнительный файл конфигурации находится в профиле Администраторов, а не в Программных файлах, как ожидается для всех.

Я верю, что Ханс Пассант на правильном пути. В дополнение к тому, что он сказал, убедитесь, что ddip.dll и исполняемый файл находятся в одном каталоге. Это не всегда так, поскольку существуют другие способы связывания сборок вне корзины. А именно событие GAC и AssemblyResolve. Учитывая вашу ситуацию, я не вижу причин, по которым GAC участвует. Проверьте код exe, который запускается для любых перехватов в событии AssemblyResolve. Если он подключен, вам может потребоваться обновить реализацию, чтобы позволить другому процессу запустить его.

Поскольку вы получаете исключение в отношении отсутствующей DLL, у меня мало уверенности в ответах относительно проблем с разделителями путей. Тем не менее, у вас есть код приложения, поэтому убедитесь, что он ссылается на ddip.dll. Это даст вам большую уверенность в том, что вы на самом деле ссылаетесь на правильный.exe, и поэтому это не просто проблема с разделителем пути в командной строке (например, неправильно интерпретированные пробелы).

Другие вопросы по тегам