简体   繁体   English

如何获取父进程标准输出?

[英]How to grab parent process standard output?

I'm writing an utility ( http://reg2run.sf.net ) which in case execution without arguments works as windows application (shows OpenFileDialog, etc), otherwise - as console application. 我正在编写一个实用程序( http://reg2run.sf.net ),如果没有参数的执行作为Windows应用程序(显示OpenFileDialog等),否则 - 作为控制台应用程序。

So, in first case I don't want to show a console window, that's why project is Windows Application. 因此,在第一种情况下,我不想显示控制台窗口,这就是为什么项目是Windows应用程序。 But in second - I need to show it, and it's created with 但在第二个 - 我需要展示它,它是用它创建的

if (ptrNew == IntPtr.Zero)
{
    ptrNew = GetStdHandle(-11);
}
if (!AllocConsole())
{
    throw new ExternalCallException("AllocConsole");
}
ptrNew = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (!SetStdHandle(-11, ptrNew))
{
    throw new ExternalCallException("SetStdHandle");
}
StreamWriter newOut = new StreamWriter(Console.OpenStandardOutput());
newOut.AutoFlush = true;
Console.SetOut(newOut);
Console.SetError(newOut);

And what I want - is to grab parent process standard output and use it, if it exists (in case execution via cmd.exe or Far Manager). 我想要的是 - 获取父进程标准输出并使用它,如果它存在(如果通过cmd.exe或远程管理器执行)。 How can I do it? 我该怎么做?

I tried 我试过了

static Process GetParentProc()
{
int pidParent = 0;
int pidCurrent = Process.GetCurrentProcess().Id;

IntPtr hSnapshot = CreateToolhelp32Snapshot(2, 0);
if (hSnapshot == IntPtr.Zero)
{
    return null;
}

PROCESSENTRY32 oProcInfo = new PROCESSENTRY32();
oProcInfo.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));

if (!Process32First(hSnapshot, ref oProcInfo))
{
    return null;
}
do
{
    if (pidCurrent == oProcInfo.th32ProcessID)
    {
        pidParent = (int)oProcInfo.th32ParentProcessID;
    }
}
while (pidParent == 0 && Process32Next(hSnapshot, ref oProcInfo));

if (pidParent > 0)
{
    return Process.GetProcessById(pidParent);
}
else
{
    return null;
}

and

StreamWriter newOut = GetParentProc().StandardInput;

but got InvalidOperationException: StandardIn has not been redirected. 但得到了InvalidOperationException:StandardIn尚未重定向。 Because of 因为

GetParentProc().StartInfo.RedirectStandardOutput = false

There are several approaches for applications that need to choose whether to act as console or GUI applications, depending on context, on Windows: 对于需要在Windows上根据上下文选择是否充当控制台或GUI应用程序的应用程序,有几种方法:

  1. Have two separate applications, and have one conditionally start the other. 有两个单独的应用程序,并有一个有条件地启动另一个。
  2. A variant of the above strategy, have two applications, one called 'app.com' (ie just rename a console EXE with COM extension) and the other called 'app.exe', so that command-line invocations will find app.com first. 上述策略的一个变体,有两个应用程序,一个叫做'app.com'(即只是用COM扩展名重命名控制台EXE),另一个名为'app.exe',这样命令行调用就能找到app.com第一。 Because of ancient DOS compatibility, .COM executables are found before .EXEs. 由于古老的DOS兼容性,.COM可执行文件在.EXE之前找到。 (This in configurable in Windows; see the PATHEXT environment variable.) (这在Windows中是可配置的;请参阅PATHEXT环境变量。)
  3. The rxvt/Cygwin technique, which is one I haven't really seen documented anywhere else. rxvt / Cygwin技术,这是我在其他任何地方都没有记录的技术。

Let me go into a little bit of detail about how rxvt on Cygwin works. 让我详细介绍一下有关Cygwin上rxvt的工作原理。 Rxvt is a terminal emulator that normally runs on the X Window system. Rxvt是一个终端仿真器,通常在X Window系统上运行。 Because of the limitations of the Win32 console, Cygwin packages it as a more fully-featured console, with support for things like lots of lines of history, dynamic resizing, per-instance configurable fonts and colour themes, non-application-freezing mouse select and copy, etc. In order to run natively on Windows, rxvt shipped with Cygwin includes a tiny X11 wrapper library for Win32. 由于Win32控制台的局限性,Cygwin将其打包为功能更全面的控制台,支持大量历史记录,动态调整大小,每个实例可配置字体和颜色主题,非应用程序冻结鼠标选择为了在Windows上本机运行,Cygwin附带的rxvt包含一个用于Win32的小型X11包装器库。 Rxvt on Windows is actually a console application for compatibility reasons with existing native Win32 executables, but most of the time you never see the console; Windows上的Rxvt实际上是一个控制台应用程序,出于与现有本机Win32可执行文件的兼容性原因,但大多数时候你从未看过控制台; you just see the rxvt terminal emulator window itself. 你只看到rxvt终端模拟器窗口本身。

The way it works is specifically implemented in rxvt/W11/wrap/wrap.c in the rxvt source tree, in the function called hideConsole() . 它的工作方式具体在rxvt/W11/wrap/wrap.c源代码树中的rxvt/W11/wrap/wrap.c中实现,名为hideConsole() Basically, it opens up its console (with a CreateFile("CONOUT$" ...) ), and checks to see if the cursor position is at (0,0) (using GetConsoleScreenBufferInfo() on the console handle). 基本上,它打开它的控制台(使用CreateFile("CONOUT$" ...) ),并检查光标位置是否为(0,0)(使用控制台句柄上的GetConsoleScreenBufferInfo() )。

If it is, then it infers that it has been started as a standalone application, rather than from a console parent application, and thus it knows the OS has created a dedicated Win32 console for the process. 如果是,那么它会推断它已作为独立应用程序启动,而不是从控制台父应用程序启动,因此它知道操作系统已为该进程创建了专用的Win32控制台。 It proceeds to hide this console window, but it has to find it first. 它继续隐藏这个控制台窗口,但它必须先找到它。 It uses SetConsoleTitle to set the console window's caption to a unique value based on the name of the application and the current thread ID. 它使用SetConsoleTitle根据应用程序名称和当前线程ID将控制台窗口的标题设置为唯一值。 It then uses FindWindow to find this window's handle (periodically Sleep ing for a few ms if necessary for the title to change, because the console windows are actually controlled by a different process entirely in Windows). 然后使用FindWindow查找此窗口的句柄(如果需要更改标题,则定期Sleep几毫秒,因为控制台窗口实际上完全由Windows中的不同进程控制)。 When it eventually finds the window handle, it hides it with ShowWindowAsync , passing in SW_HIDE . 当它最终找到窗口句柄时,它会使用ShowWindowAsync隐藏它,并传入SW_HIDE

Using this approach, you can write an application that: 使用此方法,您可以编写一个应用程序:

  • if started from a console parent, it can continue to use this console 如果从控制台父级启动,它可以继续使用此控制台
  • if started as an application, it can optionally choose whether or not to hide the console 如果作为应用程序启动,它可以选择是否隐藏控制台

The only downside is a very brief flash of a console window at application startup. 唯一的缺点是在应用程序启动时非常简短的控制台窗口闪存。

You can always the following P/Invoke method: 您始终可以使用以下P / Invoke方法:

[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);

const int ATTACH_PARENT_PROCESS = -1;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 生成进程时如何重定向标准输出 - How to redirect standard output when spawning a process 如何在后台启动进程并读取标准 output - How to start a process in the background and read standard output 如何在不重定向标准输出的情况下读取进程的控制台输出? - How to read console output of a process without redirecting standard output? 将父进程的控制台(stdout,标准错误等)输出重定向到子进程(反向) - Redirecting Console (stdout, standard error, etc.) output of a parent process to child process (reverse) C#-如何在流程退出时关闭标准输入和输出流? - C# - how to close standard input and output streams on process exit? 如何检索 SSIS 流程任务的标准输出和错误 - How to retrieve the standard output and error of an SSIS process task 如何在C#、. net中仅异步重定向标准错误流而不是进程的标准输出流 - How to asynchronously redirect ONLY standard error stream and not standard output stream of a process in C#, .net C#流程标准输出延迟 - C# process standard output delay Process.Start捕获标准输出字符 - Process.Start capturing standard output characters C#过程中的标准输入/输出 - Standard input/output in C# process
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM