在C#中运行程序时,所有消息都会转到标准输出,但标准错误不包含任何内容

在C#中运行程序时,所有消息都会转到标准输出,但标准错误不包含任何内容,c#,process,command-line-interface,stdout,stderr,C#,Process,Command Line Interface,Stdout,Stderr,我的问题与我的不同。显然,我已经调用了“BeginErrorReadLine”方法(我在下面的代码中对其进行了标记) 我想解析 命令行 在命令行环境中运行时,它将输出如下内容: >handle64-p[PID] nHandle v4.11-句柄查看器 版权所有(C)1997-2017 Mark Russinovich Sysinternals-www.Sysinternals.com 10:FileC:\Windows 1C:FileC:\Windows\SysWOW64 [PID]是任何

我的问题与我的不同。显然,我已经调用了“BeginErrorReadLine”方法(我在下面的代码中对其进行了标记)

我想解析


命令行

在命令行环境中运行时,它将输出如下内容:

>handle64-p[PID]

nHandle v4.11-句柄查看器

版权所有(C)1997-2017 Mark Russinovich

Sysinternals-www.Sysinternals.com

10:FileC:\Windows

1C:FileC:\Windows\SysWOW64

[PID]是任何正在运行的进程ID

输出是分开的

前5行(包括空行)进入标准错误,最后2行进入标准输出

因此,我可以通过重定向来剥离标题:

>handle64-p[PID]2>nul

10:FileC:\Windows

1C:FileC:\Windows\SysWOW64


Winform应用程序

然后我尝试在C#winform应用程序中实现此命令:

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应用程序中的结果与命令行中的结果相同


更新

对于Damien的评论,我尝试通过“cmd”运行,不幸的是,我得到了相同的结果:

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

...
在输出窗口中:

输出=>

输出=>nHandle v4.11-句柄查看器

输出=>版权(C)1997-2017 Mark Russinovich

输出=>Sysinternals-www.Sysinternals.com

输出=>

输出=>10:FileC:\Windows

输出=>1C:FileC:\Windows\SysWOW64

错误=>


这只是一个例子来说明我在评论中提到的问题。这不是一个解决办法,因为我不相信有一个微不足道的方法来解决这个问题。我已经在我的scratch程序中创建了
Main
(称为
PlayAreaCcon
)。如果在没有参数的情况下调用它,它的行为方式与我所怀疑的
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
是封闭源代码,因此很难确认这是它正在执行的特定检查。呼叫方对此没有任何非琐碎的解决方案。

不是您问题的答案,只是一个建议,以实现您正在尝试的操作(即仅在Winform应用程序中获取句柄信息):

handle工具具有
-nobanner
开关,您可以使用该开关跳过版权信息

handle64.exe -pid 11624 -nobanner
如Damien所述: 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变得不稳定。

我对您的代码做了一些更改:

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();

如果您最终将所有内容写入同一个流,为什么您认为输出应该在程序中分开?@Dmytro不是我的程序,而是他们的程序,称为“句柄”。你可以通过链接下载。我只是在我的程序中运行它。因此,流是由该流编写的。我认为同一个程序通常会将消息写入同一个流。我实际上是在询问您的程序,该程序会跟踪错误消息和输出消息。我几乎可以肯定,如果您的描述是准确的,那么这就是目标应用程序所做的决定。可以确定您是否实际连接到一个交互式控制台(尽管在.NET中不是很容易),并使用它突然决定“嘿,我要把所有东西都发送到标准输出”,如果您没有。如果您用另一个具有已知结果的程序替换
handle64
程序,会发生什么情况?例如,C++ >代码>