获取句柄并写入启动我们进程的控制台

2024-03-19

我怎样才能写入一些已经打开的控制台的标准输出? 我通过这段代码找到了我需要的控制台:

    IntPtr ptr = GetForegroundWindow();           
    int u;
    GetWindowThreadProcessId(ptr, out u);
    Process process = Process.GetProcessById(u);

问题是如何获取这个进程的标准输出句柄指针(stdHandle)。

然后我想要类似的东西:

                SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
                FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
                Encoding encoding = Encoding.ASCII;
                StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
                standardOutput.AutoFlush = true;
                Console.SetOut(standardOutput);

使用 Windows API 的 C++ 代码没问题 - 我可以使用 pInvoke。

实际上,我想要的是将文本写入不是由我的进程生成的已经打开的控制台窗口(它是通过命令行启动我的进程时位于前台的窗口 - 但我的进程是 WinApp,因此控制台不会附加)标准)。

进程创建后可以重定向标准输出吗?

PS:我读到一些可用于执行此操作的 COM 文件,所以这意味着有一种编程方式......

Thanks!


我终于弄清楚了如何在启动 Windows 应用程序时透明地附加到控制台(如果它是前台窗口)。

不要问我为什么必须传递 STD_ERROR_HANDLE 而不是 STD_OUTPUT_HANDLE,但它只是有效,可能是因为标准错误可以共享。

注意:控制台可以在内部显示应用程序消息时接受用户输入,但是在 stderr 从应用程序输出时使用它有点令人困惑。

使用这段代码,如果您使用至少一个参数从控制台窗口启动应用程序,它将附加 Console.Write 到它,如果您使用参数 /debug 启动应用程序,那么它甚至会将 Debug.Write 附加到安慰。

在退出应用程序之前调用 Cleanup() 以释放控制台,并发送 Enter 按键以释放最后一行,以便控制台像启动应用程序之前一样可用。

附言。您不能通过此方法使用输出重定向,即:yourapp.exe > file.txt,因为 你会得到一个空文件。甚至不要尝试 myapp.exe > file.txt 2>&1,因为您将使应用程序崩溃(将错误重定向到输出意味着我们正在尝试附加到非共享缓冲区)。

这是代码:

[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

[DllImport("kernel32.dll",
    EntryPoint = "GetStdHandle",
    SetLastError = true,
    CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);

[DllImport("kernel32.dll",
    EntryPoint = "AllocConsole",
    SetLastError = true,
    CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();

private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private static bool _consoleAttached = false;
private static IntPtr consoleWindow;

[STAThread]
static void Main()
{
    args = new List<string>(Environment.GetCommandLineArgs());

    int prId;
    consoleWindow = GetForegroundWindow();            
    GetWindowThreadProcessId(consoleWindow, out prId);
    Process process = Process.GetProcessById(prId);

    if (args.Count > 1 && process.ProcessName == "cmd")
    {
        if (AttachConsole((uint)prId)) {
            _consoleAttached = true;
            IntPtr stdHandle = GetStdHandle(STD_ERROR_HANDLE); // must be error dunno why
            SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
            FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
            Encoding encoding = Encoding.ASCII;
            StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
            standardOutput.AutoFlush = true;
            Console.SetOut(standardOutput);
            if (args.Contains("/debug")) Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
            Console.WriteLine(Application.ProductName + " was launched from a console window and will redirect output to it.");
        }
    }
    // ... do whatever, use console.writeline or debug.writeline
    // if you started the app with /debug from a console
    Cleanup();
}

private static void Cleanup() {
    try
    {
        if (_consoleAttached)
        {
            SetForegroundWindow(consoleWindow);
            SendKeys.SendWait("{ENTER}");
            FreeConsole();
        }    
    }        
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

获取句柄并写入启动我们进程的控制台 的相关文章

随机推荐

  • 如何使用 System.HashCode.Combine 来处理超过 8 个值?

    NET 标准 2 1 NET 核心 3介绍 https github com dotnet corefx issues 14354 System HashCode https learn microsoft com en us dotnet
  • T-SQL计算列如何获取ISO周数[重复]

    这个问题在这里已经有答案了 我有一个基于日期和计算列的日历表 下面的代码 问题是 由于逻辑 52 7 364 它返回的是第 53 周 所以实际上我们每年总是有一些 空闲 天 例如 2014 年的这些天 2014 12 282014 12 2
  • 跳过从数据文件中读取字符 C++

    我有一个具有以下格式的数据文件 A dat Theta 0 0000 Phi 0 00000 Theta 1 0000 Phi 90 0000 Theta 2 0000 Phi 180 0000 Theta 3 0000 Phi 360 0
  • 如何使用 jQuery Validate 删除错误类?

    我有一个表单 它使用 jQuery Validate 插件将错误类添加到一组复选框的父 div 中 但是 当选中某个复选框时 错误类将被删除 但 CSS 样式仍然保留 有什么想法我做错了吗 例子 http jsfiddle net qK3S
  • 更改文本文件的默认“复制到输出目录”设置

    有谁知道是否有办法更改 Visual Studio 2008 中文件类型的默认 复制到输出目录 设置 我经常将文本文件添加到我的项目中 它们可以是自述文件中的任何内容 或一些使用信息 或应用程序在运行时实际使用的测试文件 但我从来没有添加过
  • Devise Oauth Twitter:OAuth::未经授权禁止 403

    我正在尝试使用 Devise 实现 Oauth Twitter 我在 Twitter 上创建了应用程序我已将回调 url 设置为 http 本地主机 3000 http localhost 3000我已将其添加到 config initia
  • 会话和基于令牌的身份验证之间的技术差异

    我正在写我的学士学位 其中我需要找出哪种身份验证 授权方法最适合我正在合作的公司 因此 我一直在比较基于会话和基于令牌的身份验证方法 但对于令牌如何工作以及它们如何比会话身份验证更好 我不清楚以下几点 我 100 清楚的唯一好处是 令牌可以
  • 将精确的 cv::Mat 图像存储在 sqlite3 数据库中

    有什么办法可以准确存储cv Mat使用 sqlite3 格式化数据Qt 因为我将来将使用相同的 cv Mat 格式 我尝试将图像转换为无符号字符 他们存储它 但这对我不起作用 还有其他技术吗 您可以将 cv Mat 序列化为 QByteAr
  • nodejs ffmpeg在特定时间播放视频并将其流式传输到客户端

    我正在尝试使用 nodeJS 和 ffmpeg 制作一个基本的在线视频编辑器 为此 我需要执行 2 个步骤 设置客户端视频的进出时间 要求客户端在特定的时间观看视频 并切换视频的位置 这意味着 如果使用单个视频作为输入 并将其分割成更小的部
  • java.io.InvalidClassException:本地类不兼容:

    我创建了客户端和服务器 然后在客户端添加了一个类用于序列化目的 然后只需转到硬盘驱动器中客户端的文件夹并将其复制粘贴到服务器对应的位置即可classname class and classname java分别 它在我自己的笔记本电脑上运行
  • 修改后的先序树遍历中的路径

    我已经实现了修改后的预序树遍历正如这里所解释的 http www sitepoint com hierarchical data database 2 我的树是这样的 ref name lft rgt NULL base 1 8 2 bas
  • 前向声明中的字段类型不完整[重复]

    这个问题在这里已经有答案了 我使用以下简单文件重现错误 它说 字段的类型 Foo 不完整 bar h class Foo class Bar private int x Foo foo error incomplete type publi
  • 受保护析构函数的基本原理

    我注意到许多 Poco 类都有一个受保护的析构函数 这使得它们的编码变得更加烦人 例如 这是我的一些代码 struct W2 Poco Util WinRegistryConfiguration typedef Poco Util WinR
  • Android 对话框,按下按钮时保持对话框打开

    我想在按下按钮时保持对话框打开 目前正在关闭 AlertDialog Builder builder new AlertDialog Builder this builder setMessage Are you sure you want
  • 在 javascript 资源中使用 Rails 辅助方法

    有没有办法使用 Rails 辅助方法 更具体地说 是 javascript 资源文件中的路径辅助方法 这个文件foo js coffee erb bar val 如果我能从 erubis 得到我会很高兴 bar val path to cr
  • 创建一段时间后删除会话文件

    我将会话保存在 temp 目录中的另一个目录中 说 session目录 使用session save path session 此外 还有一个代码可以在创建和注销 10 分钟后终止会话 但我提到 如果用户登录并关闭计算机 我的注销和会话销毁
  • 向 UITextField 添加不可编辑的文本后缀

    我有一个 UITextField 我想添加一个 所有输入文本的后缀 用户不应该能够删除这个 或在其右侧添加文本 解决这个问题的最佳方法是什么 Use the UITextFieldDelegate http developer apple
  • 转置前导维度为 N 的一维数组

    如何在没有额外空间的情况下转置前导维度为 N 的一维数组 任何语言都可以 我的一维就地矩阵转置解决方案 mn M N M rows and N columns q mn 1 i 0 Index of 1D array that repres
  • Chrome 多功能框特殊字符抛出错误

    我正在编写一个基本的 Chrome 扩展程序 以通过 JSON 源在多功能框中添加建议 几乎所有输入的查询都会在建议下拉列表中显示预期的结果 然而 每当描述中返回与号 时 Chrome 就会抛出错误 抛出的错误读取 xmlParseEnti
  • 获取句柄并写入启动我们进程的控制台

    我怎样才能写入一些已经打开的控制台的标准输出 我通过这段代码找到了我需要的控制台 IntPtr ptr GetForegroundWindow int u GetWindowThreadProcessId ptr out u Process