Проблема с запуском System.Diagnostics.Process под Windows 7 - PullRequest
5 голосов
/ 29 октября 2010

Я пытаюсь запустить приложение (операционная система, мое приложение и приложение, которое я хочу запустить, все 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. process - это System.Diagnostics.Process, созданный с помощью простого «new Process ();»
  2. путь - полный путь к файлу .exe «c: /path/to/my.exe».
  3. enableRaisingEvents false
  4. windowStyle развернуто (но пробовали другие).

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

alt text

Там написано:

Ошибка приложения Неожиданное исключение произошло для программы (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:

alt text

Это означает, что «Программа не может быть запущена из-за отсутствия ddip.dll… попробуйте переустановить bla bla».

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

alt text

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

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

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

Есть идеи?

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

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

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

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

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

Нам не нужен админ или любой другойвещь такая, но, видимо, Vista / 7 нужно это знать.

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

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

Ответы [ 6 ]

8 голосов
/ 29 октября 2010

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

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

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

5 голосов
/ 29 октября 2010

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

3 голосов
/ 05 декабря 2010

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

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

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

if (System.Environment.OSVersion.Version.Major >= 6)  // UAC's around...
{
   processStartInfo.Verb = "runas";
}
1 голос
/ 04 декабря 2010

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

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

1 голос
/ 01 декабря 2010

У меня были подобные проблемы в прошлом.Я решил это, выполнив приложение 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(); ...}
0 голосов
/ 07 декабря 2010

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

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

...