프로그래밍/C#, .NET

[.NET] 콘솔 애플리케이션(console application)에서 콘솔 모드 변경

당근천국 2022. 6. 23. 15:30

별생각 없이 콘솔로 프로그램을 만들었는데....

기본적으로 있는 콘솔 모드들 때문에 이상한 동작을 하는 경우가 있습니다.

 

대표적인 것이 "빠른 편집 모드(Quick Edit Mode)"라는 것인데

콘솔 창을 클릭하거나 드레그하면 응용프로그램이 멈추는 현상입니다.

이 모드를 바꾸는 방법을 알아봅시다.

 

연관글 영역

 

 

1. WinApi를 사용해야 한다.

몇 가지 방법들이 있지만 결국은 WinApi를 이용하는 것이 가장 편합니다.

 

WinApi로 콘솔 모드를 변경하려면

1) 디바이스(여기서는 콘솔)의 핸들을 받아서

2) 콘솔 모드 설정값을 받아온 뒤

3) 받은 설정값이 원하는 설정을 추가(혹은 제거)하고

4) 콘솔 모드 설정값을 다시 설정합니다.

 

설정값이 uint(UInt32)로 된 플래그(flag) 값이라 비트연산으로 추가나 제거를 할 수 잇습니다.

(참고 : [.NET] 열거형 맴버(enum)의 플래그(Flags)와 비트(bit) 연산)

 

 

2. 설정값 바꾸기

이제 코드를 한번 짜봅시다.

 

먼저 WinAPI를 임포트해야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/// <summary>
/// 디바이스의 핸들을 가지고 온다.
/// https://docs.microsoft.com/ko-kr/windows/console/getstdhandle
/// </summary>
/// <param name="nStdHandle"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
 
/// <summary>
/// 콘솔 모드를 가지고 온다.
/// https://docs.microsoft.com/ko-kr/windows/console/getconsolemode
/// </summary>
/// <param name="hConsoleHandle"></param>
/// <param name="lpMode"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
/// <summary>
/// 콘솔모드를 설정한다.
/// https://docs.microsoft.com/ko-kr/windows/console/setconsolemode
/// </summary>
/// <param name="hConsoleHandle"></param>
/// <param name="dwMode"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
cs

 

'GetStdHandle'를 이용하여 수정할 콘솔의 핸들을 받아옵니다.

1
IntPtr consoleHandle = GetStdHandle(-10);
cs

여기서 '-10'은 'STD_INPUT_HANDLE'을 의미합니다.

(참고 : MS Docs - GetStdHandle 함수 )

 

 

이렇게 받아온 핸들로 콘솔 모드를 가지고 옵니다.

1
2
3
4
//핸들에 설정된 콘솔 모드를 가지고 온다.
UInt32 consoleMode;
GetConsoleMode(consoleHandle, out consoleMode);
 
cs

 

콘솔 모드를 설정하려면 아래와 같이 합니다.

1
2
3
4
5
6
//값을 넣을때
consoleMode |= ((uint)[모드 값]);
 
 
//값을 뺄때
consoleMode &= ~((uint)[모드 값]);
cs

 

사용할 수 있는 모드값은 'MS Docs'를 참고하면 됩니다.

참고 - SetConsoleMode 함수

 

이제 값을 설정했으면 'SetConsoleMode'를 사용하여 수정한 설정값을 적용하면 됩니다.

1
2
//수정한 콘솔 모드를 설정한다.
SetConsoleMode(consoleHandle, consoleMode);
cs

 

 

3. 테스트해보기

 F11을 눌렀을 때 전체화면으로 전환되는 것을 막아 봅시다.

 

F11을 막기 위한 코드는 아래와 같습니다.

1
2
3
4
5
6
IntPtr consoleHandle = GetStdHandle((int)-10);
UInt32 consoleMode;
GetConsoleMode(consoleHandle, out consoleMode);
consoleMode &= ~((uint)0x0001);
 
SetConsoleMode(consoleHandle, consoleMode);
cs

 

이제 전체화면 전환이 되지 않는 것을 알 수 있습니다.

 

'빠른 편집 모드'를 끄려면 '0x0040'를 입력하면 됩니다.

 

 

4. 캡슐화

인터넷을 돌아다니다가 이걸 쓰기 좋게 캡슐화된 게 있습니다.

참고 : stackoverflow 'Patrick from NDepend team' 님 답변 - How to programmatic disable C# Console Application's Quick Edit mode?

 

제가 살짝 정리를 한 건 이겁니다.

github - dang-gun/DotNetSamples/ConsoleModeSettingTest/

 

 

마무리

윈폼(Winform)처럼 자체적인 함수를 지원해주면 좋겠다는 생각을 하는데 말이죠.....

콘솔 응용프로그램이라는 게 UI없는 만큼 퍼포먼스가 좋으라고 쓰는 거라 그런 걸까요?