"Console","cmd.exe","shell"之间的区别?

smw*_*dia 9 c# windows

我不太确定控制台(在"Windows控制台应用程序"),cmd.exe,shell之间的区别.

  • 我知道cmd.exe在运行时是一个独立的进程,是cmd.exe == shell吗?那么shell只是一个过程?
  • 是console == cmd.exe?
  • MSDN说ProcessStartInfo.UseShellExecute == True表示在启动进程时使用shell,是否意味着进程启动与运行cmd.exe一样,并从该命令提示符运行程序?这样做有什么意义?以这种方式启动的流程是否有自己的控制台?

提前致谢.

Mat*_*lia 11

- MSDN说ProcessStartInfo.UseShellExecute == True表示在启动进程时使用shell,这是否意味着进程启动与运行cmd.exe一样,并从该命令提示符运行程序?这样做有什么意义?以这种方式启动的流程是否有自己的控制台?

实际上它的工作原理如下:

  • 如果UseShellExecute为false,则将使用CreateProcess API 启动应用程序; 此API允许您指定许多启动选项,其中有可能重定向stdin/stdout/stderr,但只会启动可执行文件.如果您尝试使用CreateProcess启动文件(例如word文档),它将失败,因为word文档不是可执行文件.
  • 如果UseShellExecute为true,则使用ShellExecuteEx API 启动该进程; 此功能是Windows资源管理器("相同功能壳",至少在微软的术语)使用,当你双击某个文件夹中的文件; 它的主要优点是它"知道"如何启动文档(用相关程序打开它们),它知道shell文件夹,...因为它使用了很多shell工具.然而它有一些主要的缺点:与裸CreateProcess相比,它相当重量级(因为它必须执行大量的额外工作),如果文件关联/ shell扩展/ ...出现问题,它甚至无法打开可执行文件无法重定向stdin/stdout/stderr.从理论上说这不可能:毕竟ShellExecuteEx内部调用CreateProcess; 问题是它没有公开这个功能.

因此,创建流程的两种方法实际上是完全不同的; 对于扁平化它们,Process类做得很好,但是使用ShellExecuteEx函数绝对无法再现的功能是IO流重定向,因为ShellExecuteEx函数无法使用它,并且只能在进程启动时通过CreateProcess启用它.

启动程序使用控制台是另一个问题.控制台在CreateProcess中分配/重用(实际上是IIRC,它与windows PE加载器有关,它检查PE头中所需的子系统); 控制台创建/重用的规则在此处指定.

如果启动的应用程序是GUI应用程序,则根本不会创建任何控制台; 另一方面,如果启动控制台应用程序,它将重用其父进程的控制台,除非它在CreateProcess中指定调用CREATE_NEW_CONSOLE标志.默认情况下不指定此标志,但我不确定ShellExecuteEx对控制台应用程序的作用,我手头没有Windows框来检查.我会将此作为练习留给读者.:P


其他答案

嗨,Matteo,另一个问题.如果我创建一个新进程作为一个没有附加控制台的分离进程.现在流程的标准在哪里?流程的输出在哪里?进程的标准输出是否与控制台的输出不同?

我不清楚你的意思.当您使用CreateProcess/ShellExecuteEx启动新进程时,控制台将根据需要进行分配,即如果exe是控制台可执行文件(如PE标头中所指定),则Windows会为其提供一个控制台(即新控制台或父级控制台)根据我上面指定的规则); 如果exe是GUI应用程序,则不会为其分配控制台.

IIRC,对于GUI应用程序,stdout/stdin/stderr只是位桶,即它们没有任何用处,所有IO都被丢弃了; 顺便说一下,没有什么能阻止 GUI应用程序分配控制台并将其自己的std*流重定向到它.

请记住,控制台,Windows标准流和CRT标准流是三个独立的事情.控制台只是一个界面,对于控制台应用程序,它默认方便地绑定到Windows标准流.

Windows std流是在CreateProcess中指定stdin/stdout/stderr重定向时重定向的流; 你可以把手,将其与GetStdHandle功能,并与他们重定向SetStdHandle.

最后,CRT stdin/stdout/stderr是另一个抽象,由C运行时库构建; 它们默认绑定到Windows标准流.

所有这些通常无缝地工作,你甚至不必担心Windows标准流和CRT流之间的差异; 但是,当您开始考虑流重定向时,这种差异变得很重要.

如果进程的stdout流与控制台的输出不同,那么Shell会为我们绑定这两个流.是否将进程的输出从process.stdout复制到console.output?这样有效吗?

shell不参与此过程,是执行管道的内核,遵循CreateProcess中使用的指令(或随后使用其他API从新进程内部进行修改).对于您的性能问题,使用这样的分层结构,这是唯一的方法; 而且,复制部分(如果它真的是副本,我怀疑整个事情只是传递指针的问题)是过程中最快的部分,真正的瓶颈是控制台窗口绘制/滚动/等等.事实上,如果您想运行一个控制台应用程序让它以全速生成数据,您通常会将其标准输出重定向到文件或通过管道.

非常感谢.Matteo Italia.你是一个很好的问题.:d

谢谢.:)