【问题标题】:What is the different between API functions AllocConsole and AttachConsole(-1)?API 函数 AllocConsole 和 AttachConsole(-1) 有什么不同?
【发布时间】:2010-09-30 18:37:31
【问题描述】:

您能否解释一下,API 函数 AllocConsoleAttachConsole(-1) 有什么区别?我的意思是如果AttachConsole 得到ATTACH_PARENT_PROCESS(DWORD)-1

【问题讨论】:

    标签: c# .net winapi console


    【解决方案1】:

    嗯,根本的区别是:

    • AllocConsole() 将创建一个新控制台(并附加到它)
    • AttachConsole( ATTACH_PARENT_PROCESS /* -1 */) 不会创建新的控制台,它会附加到父进程的现有控制台。

    在第一种情况下,您将获得一个全新的控制台窗口,在第二种情况下,您使用现有的控制台窗口。

    当然,如果您已经连接到控制台(即,您是从 cmd.exe 启动的控制台模式程序),则没有太大区别 - 使用任一 API 都会出错。

    另请注意,仅仅因为您从控制台分离并不意味着分离的控制台会有用 - 例如,如果您是从 cmd 窗口启动的控制台进程,则该窗口基本上会阻塞,直到您的进程结束。

    一些代码可以玩:

    int main( int argc, char* argv[])
    {
        int ch;
        BOOL bResult;
    
        printf( "default console\n");
        ch = getchar();
    
        bResult = FreeConsole();
        bResult = AllocConsole();    
        printf( "AllocConsole()\n");
        ch = getchar();
    
        bResult = FreeConsole();
        bResult = AttachConsole( ATTACH_PARENT_PROCESS);    
        printf( "AttachConsole( ATTACH_PARENT_PROCESS)\n");
        ch = getchar();
    
        return 0;
    }
    

    【讨论】:

    • 这可以在 C#.Net 中用于为编译为 Windows 程序(而不是控制台程序)的可执行文件创建控制台窗口吗?
    • 可以。但是获取控制台要容易得多,只需将项目的输出类型更改为控制台应用程序即可。
    • @configuratoir - 据我所知你可以做到这一点,但我认为你必须使用 p/invoke 来调用 Win32 API(这些 API 没什么大不了的) - 我是不确定是否有等效的框架。
    • @nobugz - 是的,你可以。更多信息请访问stackoverflow.com/questions/472282/…
    • @abatishchev:很好的链接到死链接......不是。
    【解决方案2】:

    我认为没有名为CreateConsole 的函数,但有AllocConsole

    假设这就是你的意思,我认为区别在于如果父进程没有控制台,AttachConsole(ATTACH_PARENT_PROCESS) 可以return ERROR_INVALID_HANDLE

    尝试从命令提示符和“开始”->“运行”运行此代码:

    #include <windows.h>
    #pragma comment ( lib, "user32.lib" )
    
    int main()
    {
        BOOL b;
        char msg[1024];
    
        b = FreeConsole();
        sprintf(msg, "%d", b);
        MessageBox(NULL, msg, "FreeConsole", 0);
    
        b = AttachConsole(ATTACH_PARENT_PROCESS);
        sprintf(msg, "%d", b);
        MessageBox(NULL, msg, "AttachConsole", 0);
    
        return 0;
    }
    

    从命令提示符运行时,会显示两个包含1 的消息框,这意味着两个调用都成功了。从 Start -> Run 运行时,第一个框包含1,第二个框包含0,这意味着只有第一个调用成功。第二个失败是因为 explorer.exe(它是从 Start -> Run 启动的进程的父进程)没有控制台。

    【讨论】:

      【解决方案3】:

      在 Windows 7 上,当您执行 cmd.exe 时,CreateProcess 将具有 CREATE_NEW_CONSOLE 标志,它将分配一个新控制台而不是附加到父控制台(这是 PE 标头包含 @ 时的默认行为987654324@ 即IMAGE_SUBSYSTEM_WINDOWS_CUI 表示它是一个控制台应用程序)。这意味着AllocConsole将在当前进程地址空间中的.exe图像入口点之前被调用。

      AllocConsole 创建一个新的conhost.exe 实例,它绘制GUI 窗口,处理鼠标和键盘事件,维护和写入输入缓冲区,维护和读取屏幕缓冲区,当有键盘时事件,它更新输入缓冲区。 AllocConsole 还将cmd.exe 进程PEB 中ParameterBlock 中的stdin 句柄设置为控制台输入缓冲区,并将stdoutstderr 设置为控制台伪句柄,并将ConsoleHandle 设置为ParameterBlockto the PID of theconhost.exe` 附加到的实例。

      cmd.exe 是用 C 编写的控制台应用程序,如 diskpart.exesetx.exe,它将命令提示符显示到屏幕缓冲区(cmd.exestdout)并从 stdin 读取命令cmd.exe 并解释要显示给 stdout 的按键事件,并确定调用什么命令以及显示给 stdout 的结果(可能是在 PEB 中处理,而不是发送到conhost)。 command 本身有一个 stdin 或者什么都没有、匿名管道的读取端、一个文件或 con 文件。

      cmd.exe 调用类似WriteFile 的函数,如果它正在写入标准句柄(否则它调用NtWriteFile),它将调用WriteConsole(这是WriteConsoleA 的别名)。这将在ParameterBlock-&gt;ConsoleHandle 中启动对conhost.exe PID 的ALPC 调用,传递控制台伪句柄和缓冲区以将结果写入(或从缓冲区读取)。

      当您从cmd.exe 内部执行cmd /c 时,它会创建一个子cmd.exe,但不提供CREATE_NEW_CONSOLE,这会导致子cmd.exe 附加到同一个可见控制台,即conhost.exe 实例并且在入口点之前调用AttachConsole。如果在非提升的cmd.exe 中完成使用admin /ccmd.exe 的管理员版本)创建的孩子则不是这种情况,因为它具有不同的权限,所以需要一个新的conhost.exe 实例。类似地,当启动一个程序时,start 提供CREATE_NEW_CONSOLE,这会为其子进程打开一个新的conhost.exe,但call 并将程序文件名+扩展名指定为原始命令不会打开另一个控制台窗口,而是附加到父级。 cmd /c diskpart 创建一个 cmd.exe 子级,该子级附加到父级附加到的控制台,然后该子级创建自己的子级diskpart.exe,它附加到父级附加到的控制台。

      当您执行 GUI 应用程序时,它不会分配或附加到控制台。如果您在应用程序中使用AllocConsole,它将创建一个新的conhost.exe 控制台窗口(它可以被应用程序隐藏,即搅拌机有window &gt; toggle system console,它通过获取conhost.exe 控制台的句柄来实现这一点窗口,然后使用ShowWindowSW_HIDE就可以了),但不会创建子进程,因为它是当前进程的控制台窗口,所以现在会有2个窗口。您也可以附加到属于pid 进程的控制台(使用AttachConsole)。 AttachConsole(-1) 附加到父 pid。这将使用该进程所附加到的conhost

      如果您已经连接到控制台而不使用FreeConsole,则不能AttachConsole,如果您使用DETACHED_PROCESS 创建进程,则不能AttachConsole 连接到父控制台。 CREATE_NO_WINDOWDETACHED_PROCESS 具有相同的效果,因为它不附加到控制台应用程序或为控制台应用程序分配控制台,但允许它附加到父控制台。

      【讨论】:

        【解决方案4】:

        使用winapi已经有一段时间了,但是我查了the MSDN documentation并没有找到CreateConsole API函数。所以我的猜测是 CreateConsole 是遗留的东西,已经被 AttachConsole 取代了。所以可能没有区别,但 CreateConsole 可能已被弃用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-06-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-21
          • 1970-01-01
          相关资源
          最近更新 更多