윈도우 7. 배치 파일이 "Downloading..." 에서 멈췄다가 Enter 를 누르면 풀릴 때: 콘솔 빠른 편집 모드
노트북 한 대로 원격 수리 과정을 처음부터 끝까지 돌려 보던 날이었습니다. 고객이 내려받아 실행하는 배치 파일이 이 줄에서 한참 동안 꼼짝을 안 했습니다.
Downloading PCM Support launcher...
그런데 Enter 를 누르자 바로 다음으로 넘어갔습니다.
이건 프로그램이 멈춘 게 아니라 콘솔이 멈춘 겁니다. 윈도우 콘솔은 기본으로 “빠른 편집 모드” 가 켜져 있어서, 창 안을 마우스로 클릭하면 텍스트 선택 상태가 됩니다. 이 상태에서는 그 콘솔에 출력을 쓰려는 프로그램이 전부 그 자리에서 기다립니다. 다운로드 진행률을 찍으려던 순간 멈춘 거고, Enter 가 선택을 풀어 주니 다시 움직인 거죠. 고객은 창을 클릭했다는 것도 모를 테니, 그냥 “멈췄다” 고 느낄 겁니다.
사실 빠른 편집 모드를 끄는 코드는 이미 있었습니다. 문제는 위치였습니다. 런처를 내려받은 뒤에 실행되는 PowerShell 스크립트에서 끄고 있었으니, 그 앞 단계는 무방비였던 겁니다.
그래서 배치 파일이 처음 콘솔을 정리하는 단계(창을 최대화하는 PowerShell 한 줄)에서 같이 끄도록 옮겼습니다. 콘솔 입력 모드는 콘솔 전체에 걸리는 설정이라, 거기서 한 번 끄면 뒤에 같은 콘솔을 쓰는 단계도 모두 적용됩니다.
끄는 방법은 GetConsoleMode 로 입력 모드를 읽어 ENABLE_QUICK_EDIT_MODE(0x40) 비트를 빼고 ENABLE_EXTENDED_FLAGS(0x80) 는 켠 채로 SetConsoleMode 를 부르는 겁니다. PowerShell 에서는 대략 이렇게 합니다.
Add-Type -Namespace W -Name C -MemberDefinition @'
[DllImport("kernel32.dll")] public static extern IntPtr GetStdHandle(int h);
[DllImport("kernel32.dll")] public static extern bool GetConsoleMode(IntPtr h, out uint m);
[DllImport("kernel32.dll")] public static extern bool SetConsoleMode(IntPtr h, uint m);
'@
$h = [W.C]::GetStdHandle(-10)
$m = 0; [void][W.C]::GetConsoleMode($h, [ref]$m)
[void][W.C]::SetConsoleMode($h, ($m -band -bnot 0x40) -bor 0x80)
창을 숨긴 콘솔로 시험해 보니 입력 모드가 0x1F7 에서 0x1B7 로 바뀌었습니다. 0x40 하나만 빠진 값입니다.
고객이 실행하는 콘솔 프로그램이라면 첫 줄 가까이에서 꺼 두는 게 좋겠습니다. 오래 걸리는 단계가 있으면 그사이에 누군가는 꼭 창을 클릭하거든요.