При запуске программы на C # все сообщения отправляются на стандартный вывод, но стандартная ошибка ничего не содержит - PullRequest
0 голосов
/ 30 августа 2018

Мой вопрос отличается от идентифицированного . Очевидно, я вызвал метод "BeginErrorReadLine" (я отмечаю его в коде ниже).

Я хочу разобрать результат, выданный Handle


Командная строка

При запуске в среде командной строки выводится что-то вроде:

> handle64 -p [PID]

Nthandle v4.11 - Ручка просмотра

Copyright (C) 1997-2017 Марк Руссинович

Sysinternals - www.sysinternals.com

10: файл C: \ Windows

1С: Файл C: \ Windows \ SysWOW64

[PID] - любой ID запущенного процесса

Выход отделен.

Первые 5 строк (включая пустые строки) переходят к стандартной ошибке, последние 2 строки - к стандартному выходу.

Так что я могу удалить заголовок, перенаправив:

> handle64 -p [PID] 2> nul

10: файл C: \ Windows

1С: Файл C: \ Windows \ SysWOW64


Приложение Winform

Затем я пытаюсь реализовать эту команду в приложении winform на C #:

Stream streamOut, streamErr;

var p = Process.Start(new ProcessStartInfo
{
    FileName = "handle64.exe",
    Arguments = "-p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});

p.OutputDataReceived += (sender, e) =>
{
    streamOut.Write("Output => " + e.Data);
};

p.ErrorDataReceived += (sender, e) =>
{
    streamErr.Write("Error => " + e.Data);
};

p.BeginOutputReadLine();
p.BeginErrorReadLine(); // !!!
p.WaitForExit();

Тогда я обнаружил, что все идет к стандартному выводу.


Вопрос

Хорошо, я могу разделить заголовок и тело по коду.

Вопрос в том, почему вывод программы ведет себя по-разному в двух средах?

Можно ли заставить результат в приложении winform вести себя так же, как в командной строке?


Обновление

Что касается комментария Дэмиена, я пытаюсь запустить программу через 'cmd', к сожалению, я получаю тот же результат:

var p = Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = "/C handle64.exe -p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});

...

В окне вывода:

Вывод =>

Output => Nthandle v4.11 - Ручка просмотра

Вывод => Copyright (C) 1997-2017 Марк Руссинович

Выходные данные => Sysinternals - www.sysinternals.com

Вывод =>

Вывод => 10: Файл C: \ Windows

Вывод => 1С: Файл C: \ Windows \ SysWOW64

Ошибка =>

Ответы [ 4 ]

0 голосов
/ 05 сентября 2018

Я внес некоторые изменения в ваш код:

Stream streamOut, streamErr;

var p = Process.Start(new ProcessStartInfo
{
    FileName = "handle64.exe",
    Arguments = "-p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardInput = true, // even if no writing to std::in, still need this
    RedirectStandardError = true,
});

p.OutputDataReceived += (sender, e) =>
{
    streamOut.Write("Output => " + e.Data);
};
p.BeginOutputReadLine();

p.ErrorDataReceived += (sender, e) =>
{
    streamErr.Write("Error => " + e.Data);
};

p.BeginErrorReadLine(); 

p.WaitForExit();
p.StandardInput.Close(); // call this before WaitForExit
p.WaitForExit();
0 голосов
/ 04 сентября 2018

Не ответ на ваш вопрос, а просто предложение достичь того, что вы пытаетесь сделать (т.е. получить информацию о дескрипторе только в приложении Winform):

Ручка

имеет переключатель -nobanner, вы можете использовать его для пропуска информации об авторских правах.

handle64.exe -pid 11624 -nobanner
0 голосов
/ 05 сентября 2018

Как сказал Дэмиен: CreateNoWindow = false ,

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

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

В верхней части класса добавить:

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

Тогда ваш код становится:

var p = Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = "/C handle64.exe -p [PID]",
    CreateNoWindow = false,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});
p.WaitForInputIdle();
IntPtr windowHandle = p.MainWindowHandle;
if(windowHandle == 0) throw new Exception("This did not work");
// use win32 API's to hide window (May still flicker)
ShowWindow(windowHandle,0);
// ...

Я не могу проверить это, так как сейчас я работаю только с Linux.
Если исключение не сработало, вы можете увидеть мерцание окна, но у вас должен быть правильный вывод.

Другой способ, которым я знаю, заключается в том, чтобы вставить обработчики в насос сообщений Win32 и ответить на конкретный процесс, сообщив ему то, что ему нужно знать, и подумать, что у него есть правильное окно, когда его нет. Я не буду публично публиковать любой код, связанный с этой техникой. Любые ошибки могут привести к нестабильной работе Windows.

0 голосов
/ 03 сентября 2018

Это просто пример, иллюстрирующий проблему, на которую я ссылался в своих комментариях. Это не исправление, поскольку я не верю, что существует тривиальный способ исправить это. Я создал Main в моей скретч-программе (называемой PlayAreaCSCon). Если он вызывается без параметров, он действует аналогично тому, что я подозреваю Handle64.exe. При вызове с параметром он содержит код, похожий на ваш собственный, но затем запускает свою копию без параметров:

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace PlayAreaCSCon
{
    class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.Out.WriteLine("Hello");
                if (GetConsoleWindow() == IntPtr.Zero)
                {
                    Console.Out.WriteLine("No Console window");
                }
                else
                {
                    Console.Error.WriteLine("We have a console window");
                }
            }
            else
            {
                Process p = Process.Start(new ProcessStartInfo
                {
                    FileName = "PlayAreaCSCon.exe",
                    Arguments = "",
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                });

                TextWriter streamOut = Console.Out;
                TextWriter streamErr = Console.Error;
                p.OutputDataReceived += (sender, e) =>
                {
                    streamOut.WriteLine("Output => " + e.Data);
                };

                p.ErrorDataReceived += (sender, e) =>
                {
                    streamErr.WriteLine("Error => " + e.Data);
                };

                p.BeginOutputReadLine();
                p.BeginErrorReadLine(); // !!!
                p.WaitForExit();
            }
        }
    }
}

В командной строке у меня есть следующий сеанс:

C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe
Hello
We have a console window

C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe a
Error =>
Output => Hello
Output => No Console window
Output =>

Так что даже здесь, если Handle64.exe вызывает GetConsoleWindow или какую-либо морально эквивалентную функцию, она может обнаружить, что она не подключена к консоли, и демонстрировать другое поведение. Единственный способ, которым вы могли бы позволить ему получить окно консоли, это установить для CreateNoWindow значение false, что, как я понимаю, вы, вероятно, не захотите делать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...