Microsoft MVP성태의 닷넷 이야기
Windows: 274. Windows 7부터 도입한 conhost.exe [링크 복사], [링크+제목 복사],
조회: 4921
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 2개 있습니다.)
Windows: 274. Windows 7부터 도입한 conhost.exe
; https://www.sysnet.pe.kr/2/0/13832

Windows: 275. C# - CUI 애플리케이션과 Console 윈도우 (Windows 10 미만의 Classic Console 모드인 경우)
; https://www.sysnet.pe.kr/2/0/13834




Windows 7부터 도입한 conhost.exe

근래의 윈도우 운영체제 환경에서 콘솔 프로그램을 실행할 때 이와 함께 연달아 뜨는 conhost.exe라는 프로세스를 본 적이 있을 것입니다. 그러게요, conhost.exe 프로세스가 도대체 뭘까요? 이에 대해 검색해 보면, 아래의 글에서 아주 상세하게 설명해 주고 있습니다.

What Is conhost.exe and Why Is It Running?
; https://www.howtogeek.com/4996/what-is-conhost.exe-and-why-is-it-running/

Windows XP까지만 해도, "Command Prompt" Console은 csrss.exe 프로세스(CSRSS: ClientServer Runtime System Service)가 담당했다고 합니다. 이로 인해 몇 가지 문제가 있었다고 하는데요, 1) csrss.exe 프로세스에 문제가 생기면 Console 조차도 띄울 수 없는 상황이 발생했고, 2) csrss.exe 프로세스가 높은 권한을 가지고 있어서 일부 문제는 보안 취약점으로 이어질 수도 있고, 3) 시스템 프로세스에 속하는 csrss 내에 User Interface와 관련된 테마(Theme)를 다루는 코드를 넣을 수 없어 이후 윈도우 버전이 올라가면서 바뀌는 UI 테마를 Console에는 반영할 수 없었다고 합니다.

csrss 개발팀이 UI 테마 코드를 시스템 프로세스 내에 넣는 것을 원치 않았다고는 하지만, 만약 오직 문제가 UI 테마 하나였다면 아마도 ^^ 구겨 넣지 않았을까 싶습니다. 하지만, 여러 가지 문제가 있었기 때문에 Console 기능을 별도의 프로세스로 분리하기로 결정한 것이 아닌가 생각됩니다.

실제로 XP 당시의 이미지를 보면 메모장과는 달리 cmd.exe 창은 XP 테마가 없습니다.

[출처: What Is conhost.exe and Why Is It Running?]
con_host_0.png

이후, Vista의 Desktop Window Manager(DWM)에서는 다행히 중간 처리 단계에서 "Command Prompt" 창에 부분적으로 테마를 적용할 수 있게 되었지만 그래도 여전히 csrss에서 담당하는 UI는 테마 적용이 안 됐습니다.

[출처: What Is conhost.exe and Why Is It Running?]
(창의 프레임 영역은 테마가 적용, 스크롤바 영역은 미적용)
con_host_1.png

그리고 마침내, Windows 7에서 "Console Window Host Process"를 도입해 csrss.exe로부터 "윈도우 호스트" 부분을 독립시킴으로써 테마 문제를 (보안/안정성 문제까지 한꺼번에) 해결했습니다. 바로 그 프로세스가 conhost.exe로 cmd.exe와 csrss.exe 사이의 중간 계층으로 동작한다고 합니다. 일례로, Windows XP/Server 2003에서 cmd.exe나 콘솔 앱을 실행하면,

cmd.exe
ConsoleApp1.exe

위와 같이 그 프로세스만 뜨고, 해당 프로세스 공간에서 함께 뜨는 콘솔 윈도우는 내부적으로 csrss.exe 측에서 관리를 하게 됩니다. 반면 Windows Server 2008 R2에서 콘솔 앱을 실행하면,

csrss.exe
   |- conhost.exe (cmd.exe와 연결)
   ㄴ conhost.exe (ConsoleApp1.exe와 연결)

cmd.exe
ConsoleApp1.exe

콘솔 응용 프로그램 하나에 대해 그와 상응하는 conhost.exe가 csrss.exe의 자식 프로세스로 뜨는데요, 이후 Windows Server 2012 R2에서는 그마저도 개별 프로세스의 하위에 뜨는 것으로 바뀌었습니다.

cmd.exe
   ㄴ conhost.exe

ConsoleApp1.exe (탐색기 등을 이용해 실행)
   ㄴ conhost.exe

cmd.exe (cmd.exe 환경에서 ConsoleApp1.exe 실행한 경우 conhost.exe를 공유)
   |- conhost.exe
   ㄴ ConsoleApp1.exe

conhost.exe에 대한 마이크로소프트의 공식 문서도 "What Is conhost.exe and Why Is It Running?" 글의 내용과 유사합니다.

Console Host
; https://learn.microsoft.com/en-us/windows/console/definitions#console-host

The Windows Console Host, or conhost.exe, is both the server application for all of the Windows Console APIs as well as the classic Windows user interface for working with command-line applications. The complete contents of this binary, both the API server and the UI, historically belonged to Windows csrss.exe, a critical system process, and was diverged for security and isolation purposes.


그리고 위의 글을 훨씬 자세하게 풀어쓴,

Windows Command-Line: Inside the Windows Console
; https://devblogs.microsoft.com/commandline/windows-command-line-inside-the-windows-console/

블로그에 담긴 아래의 그림이 모든 것을 설명해 줍니다.

[출처: Windows Command-Line: Inside the Windows Console]
con_host_2.png

먼저, 저 그림의 하단에 있는 ConDrv(condrv.sys)는 Console과 "Headless" 명령행 응용 프로그램이 연동하는 것을 나타냅니다. 즉, CUI 응용 프로그램의 I/O를 conhost.exe의 API Server로 연결해 주는 역할을 하는 것입니다.

사실 condrv.sys는 Windows 7 당시에는 없었고, Windows 8/Windows Server 2012 R2부터 도입됐는데요, 따라서 그전에는 아마도 속도가 느린 IPC 수단을 이용해 통신을 한 듯합니다. (그러고 보면, 마이크로소프트는 어떻게든 성능을 높이기 위해 커널 레벨로 내리는 것을 선호하는 경향이 종종 있습니다. ^^)

그림의 상단 영역에 있는 ConHost.exe 박스를 볼까요?

비록 해당 그림에서 ConHost.exe의 박스 안에 "Console UI App Services"라고 그려져 있어 자칫 프로세스 내부에서 Console 윈도우를 생성한다고 생각할 수 있는데, 실제로 테스트해 보면 ConsoleWindowClass에 해당하는 윈도우는 명령행 응용 프로그램의 프로세스 공간에서 생성됩니다. 그 윈도우와 conhost.exe가 어떻게 통신하는지는 모르겠지만, 어쩄든 그 윈도우의 관리 코드 자체는 ConHost.exe에 있다고 봐야 할 것이고 그 구성 요소 이름을 "Console UI App Services"라고 명명한 듯합니다.

이후, "Console"에 사용자가 입력한 텍스트, 가령 Console.ReadLine 코드의 수행으로 입력한 텍스트는 "Input Buffer"로 들어가 Console API를 거쳐 "Output Buffer"로 나온다고 합니다. 이때 Output Buffer는 (간략하게 보자면) CHAR_INFO 구조체 배열로 보면 되고, 그 "Output Buffer"로부터 GDI Renderer를 통해 화면으로 그려지는 명령이 다시 ConsoleWindowClass로 전달돼 최종적으로 Console 화면에 그려지는 것입니다. 이와 함께 "Console"에 사용자가 입력한 텍스트는 "API Server"를 거쳐 ConDrv의 IOCTL로 중계로 응용 프로그램에 전달됩니다. 다시 말해 Console.ReadLine의 결과가 반환되는 것입니다.

그리고 또 하나의 입력 방식이 있는데요, 바로 응용 프로그램이 ConDrv를 통해 전달하는 출력입니다. 가령 Console.WriteLine을 하면, 이것은 다시 ConDrv를 거쳐 IOCTL로 변환돼 "API Server"로 전달되고 "Console API"를 통해 "Output Buffer"로 표현됩니다. 만약 이 과정에서 Console.WriteLine에 VT Sequence가 포함돼 있다면, 이것은 VT Parser를 한 번 더 거쳐 "Output Buffer"로 전달됩니다.

그러니까, 바로 저 "VT Parser"가 추가된 덕분에 윈도우에서 VT Sequence를 제대로 처리할 수 있게 된 것입니다. 하지만 이것도 버전에 따라 다른데요, 아래의 그림에서처럼,

[출처: Windows Command-Line: Inside the Windows Console]
con_host_3.png

As discussed above, Windows Console provides a rich API. Using the Console API, Command-Line apps and tools write text, change text colors, move the cursor, etc. And, because of the Console API, Windows Console had little need to support ANSI/VT sequences that provide very similar functionality on other platforms. In fact, until Windows 10, Windows Console only implemented the bare minimum support for ANSI/VT sequences: ...[생략]... The Console team added comprehensive support for ANSI/VT sequences to Windows 10's Console, ...[생략]...


Windows 7에서는 기본적인 VT Sequence만 지원했고 이후 Windows 10이 돼서야 제대로 지원을 하게 됐다고 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 11/29/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [31]  32  33  34  35  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
13162정성태11/15/202215714.NET Framework: 2069. .NET 7 - AOT(ahead-of-time) 컴파일 [1]
13161정성태11/14/202214368.NET Framework: 2068. C# - PublishSingleFile로 배포한 이미지의 역어셈블 가능 여부 (난독화 필요성) [4]
13160정성태11/11/202214326.NET Framework: 2067. C# - PublishSingleFile 적용 시 native/managed 모듈 통합 옵션
13159정성태11/10/202217650.NET Framework: 2066. C# - PublishSingleFile과 관련된 옵션 [3]
13158정성태11/9/202213337오류 유형: 826. Workload definition 'wasm-tools' in manifest 'microsoft.net.workload.mono.toolchain' [...] conflicts with manifest 'microsoft.net.workload.mono.toolchain.net7'
13157정성태11/8/202214368.NET Framework: 2065. C# - Mutex의 비동기 버전파일 다운로드1
13156정성태11/7/202215966.NET Framework: 2064. C# - Mutex와 Semaphore/SemaphoreSlim 차이점파일 다운로드1
13155정성태11/4/202214214디버깅 기술: 183. TCP 동시 접속 (연결이 아닌) 시도를 1개로 제한한 서버
13154정성태11/3/202214691.NET Framework: 2063. .NET 5+부터 지원되는 GC.GetGCMemoryInfo파일 다운로드1
13153정성태11/2/202216013.NET Framework: 2062. C# - 코드로 재현하는 소켓 상태(SYN_SENT, SYN_RECV)
13152정성태11/1/202214910.NET Framework: 2061. ASP.NET Core - DI로 추가한 클래스의 초기화 방법 [1]
13151정성태10/31/202214360C/C++: 161. Windows 11 환경에서 raw socket 테스트하는 방법파일 다운로드1
13150정성태10/30/202213257C/C++: 160. Visual Studio 2022로 빌드한 C++ 프로그램을 위한 다른 PC에서 실행하는 방법
13149정성태10/27/202213833오류 유형: 825. C# - CLR ETW 이벤트 수신이 GCHeapStats_V1/V2에 대해 안 되는 문제파일 다운로드1
13148정성태10/26/202213755오류 유형: 824. msbuild 에러 - error NETSDK1005: Assets file '...\project.assets.json' doesn't have a target for 'net5.0'. Ensure that restore has run and that you have included 'net5.0' in the TargetFramew
13147정성태10/25/202213030오류 유형: 823. Visual Studio 2022 - Unable to attach to CoreCLR. The debugger's protocol is incompatible with the debuggee.
13146정성태10/24/202214339.NET Framework: 2060. C# - Java의 Xmx와 유사한 힙 메모리 최댓값 제어 옵션 HeapHardLimit
13145정성태10/21/202214977오류 유형: 822. db2 - Password validation for user db2inst1 failed with rc = -2146500508
13144정성태10/20/202214662.NET Framework: 2059. ClrMD를 이용해 윈도우 환경의 메모리 덤프로부터 닷넷 모듈을 추출하는 방법파일 다운로드1
13143정성태10/19/202215605오류 유형: 821. windbg/sos - Error code - 0x000021BE
13142정성태10/18/202220405도서: 시작하세요! C# 12 프로그래밍
13141정성태10/17/202216139.NET Framework: 2058. [in,out] 배열을 C#에서 C/C++로 넘기는 방법 - 세 번째 이야기파일 다운로드1
13140정성태10/11/202215531C/C++: 159. C/C++ - 리눅스 환경에서 u16string 문자열을 출력하는 방법 [2]
13139정성태10/9/202213630.NET Framework: 2057. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프로부터 모든 닷넷 모듈을 추출하는 방법파일 다운로드1
13138정성태10/8/202216221.NET Framework: 2056. C# - await 비동기 호출을 기대한 메서드가 동기로 호출되었을 때의 부작용 [1]
13137정성태10/8/202214142.NET Framework: 2055. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프로부터 닷넷 모듈을 추출하는 방법
... [31]  32  33  34  35  36  37  38  39  40  41  42  43  44  45  ...