请您解释一下,API函数AllocConsole
和AttachConsole(-1)
之间的区别是什么?我的意思是AttachConsole
获得ATTACH_PARENT_PROCESS(DWORD)-1
。
答案 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 = 3
即 IMAGE_SUBSYSTEM_WINDOWS_CUI
表示它是一个控制台应用程序)。这意味着 AllocConsole
将在当前进程地址空间中的 .exe
图像入口点之前被调用。
AllocConsole
创建一个新的 conhost.exe
实例,它绘制 GUI 窗口,处理鼠标和键盘事件,维护和写入输入缓冲区,维护和读取屏幕缓冲区,以及何时有一个键盘事件,它更新输入缓冲区。 AllocConsole
还将 stdin
进程 PEB 中的 ParameterBlock
中的 cmd.exe
句柄设置为控制台输入缓冲区,并将 stdout
和 stderr
设置为控制台伪句柄,并在它附加到的 ParameterBlockConsoleHandle
conhost.exe` 实例中设置 to the PID of the
。
cmd.exe
是用 C 编写的控制台应用程序,如 diskpart.exe
或 setx.exe
,它将命令提示符显示到屏幕缓冲区(stdout
的 cmd.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.exe
(AttachConsole
的管理员版本)创建的子项不是这种情况,需要有一个新的 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
连接到父控制台}}。 AttachConsole
与 FreeConsole
的作用相同,因为它不附加到控制台应用程序或为控制台应用程序分配控制台,但允许它附加到父控制台。
答案 3 :(得分:0)
自从我使用winapi以来已经有一段时间了,但是我查了the MSDN documentation而我无法找到CreateConsole API函数。所以我的猜测是CreateConsole是遗留的东西,已被AttachConsole取代。所以可能没什么区别,但CreateConsole可能已被弃用。