English 中文(简体)
如何获取父进程标准输出?
原标题:
  • 时间:2008-12-18 13:56:34
  •  标签:

我正在编写一个实用程序(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. But in second - I need to show it, Translation: 并且 (bìng qiě) it s created with

if (ptrNew == IntPtr.Zero)
{
    ptrNew = GetStdHTranslation: 并且 (bìng qiě)le(-11);
}
if (!AllocConsole())
{
    throw new ExternalCallException("AllocConsole");
}
ptrNew = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (!SetStdHTranslation: 并且 (bìng qiě)le(-11, ptrNew))
{
    throw new ExternalCallException("SetStdHTranslation: 并且 (bìng qiě)le");
}
StreamWriter newOut = new StreamWriter(Console.OpenStTranslation: 并且 (bìng qiě)ardOutput());
newOut.AutoFlush = true;
Console.SetOut(newOut);
Console.SetError(newOut);

我想要的是获取父进程的标准输出并使用它(在通过cmd.exe或Far Manager执行的情况下)。我该怎么办?

我試過了

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;
}

Translation: 并且 (bìng qiě)

StreamWriter newOut = GetParentProc().StTranslation: 并且 (bìng qiě)ardInput;

but got InvalidOperationException: StTranslation: 并且 (bìng qiě)ardIn has not been redirected. Because of

GetParentProc().StartInfo.RedirectStTranslation: 并且 (bìng qiě)ardOutput = false
最佳回答

在Windows上,有几种方法可以应用于需要根据上下文选择是否作为控制台或图形用户界面应用程序的情况。

  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 (i.e. just rename a console EXE with COM extension) and the other called app.exe , so that command-line invocations will find app.com first. Because of ancient DOS compatibility, .COM executables are found before .EXEs. (This in configurable in Windows; see the PATHEXT environment variable.)
  3. The rxvt/Cygwin technique, which is one I haven t really seen documented anywhere else.

让我稍微详细介绍一下在Cygwin上运行rxvt的方式。Rxvt是一个终端仿真器,通常在X Window系统上运行。由于Win32控制台的限制,Cygwin将其打包成一个更完整功能的控制台,支持许多行历史记录、动态调整大小、每个实例可配置字体和颜色主题、不会使应用程序冻结的鼠标选择和复制等功能。为了在Windows上本地运行,Cygwin附带的rxvt包括一个为Win32编写的微型X11包装库。在Windows上,rxvt实际上是一个控制台应用程序,以兼容现有的本地Win32可执行文件,但大部分时间你看不到控制台,你只看到rxvt终端仿真器窗口本身。

它的工作方式专门在rxvt源代码树中的rxvt/W11/wrap/wrap.c中实现,在名为hideConsole()的函数中。基本上,它打开其控制台(使用CreateFile("CONOUT$" ...)),并检查光标位置是否在(0,0)(使用GetConsoleScreenBufferInfo()在控制台句柄上)。

如果是的话,就意味着它已经作为一个独立应用程序启动,而不是从控制台父应用程序启动,因此它知道操作系统已经为该进程创建了一个专用的Win32控制台。它继续隐藏这个控制台窗口,但必须首先找到它。它使用SetConsoleTitle根据应用程序的名称和当前线程ID设置控制台窗口的标题为唯一值。然后使用FindWindow查找该窗口的句柄(如果必要,周期性地睡眠几毫秒以使标题更改,因为控制台窗口实际上完全由不同的进程控制)。当它最终找到窗口句柄时,它使用ShowWindowAsync隐藏它,传递SW_HIDE

使用这个方法,你可以编写一个应用程序,它:

  • 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

唯一的缺点是应用程序启动时非常短暂的控制台窗口闪现。

问题回答

您可以始终使用以下的 P/Invoke 方法:

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

const int ATTACH_PARENT_PROCESS = -1;




相关问题
热门标签