API函数AllocConsole和AttachConsole(-1)之间有什么不同?

时间:2009-01-11 12:29:49

标签: c# .net winapi console

请您解释一下,API函数AllocConsoleAttachConsole(-1)之间的区别是什么?我的意思是AttachConsole获得ATTACH_PARENT_PROCESS(DWORD)-1

4 个答案:

答案 0 :(得分:13)

嗯,根本区别在于:

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

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

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

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

可以使用的一些代码:

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

答案 1 :(得分:5)

我不认为有一个名为CreateConsole的函数,但有AllocConsole

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

尝试从命令提示符和Start - >运行此代码。运行:

#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的消息框,这意味着两个调用都成功。从开始运行时 - &gt;运行时,第一个框包含1,第二个框包含0,表示只有第一个调用成功。第二个失败是因为explorer.exe(从Start - &gt; Run启动的进程的父进程)没有控制台。

答案 2 :(得分:2)

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

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

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

cmd.exe 调用类似 WriteFile 的函数,如果它正在写入标准句柄(否则它调用 {{ 1}})。这将启动对 WriteConsole 中的 WriteConsoleA PID 的 ALPC 调用,传递控制台伪句柄和缓冲区以将结果写入(或读取的缓冲区)。

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

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

如果您已经连接到控制台而不使用 AttachConsole(-1),则不能 pid,如果您使用 {{1} 创建进程,则不能 conhost 连接到父控制台}}。 AttachConsoleFreeConsole 的作用相同,因为它不附加到控制台应用程序或为控制台应用程序分配控制台,但允许它附加到父控制台。

答案 3 :(得分:0)

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