오랜만에 포스팅을 하네요.
이번 포스팅은 업무 중 겼었던 WPF Application의 MainWindow가 닫혔는데도 종료되지 않고 프로세스 형태로 남아있었던 증상을 해결했던 경험을 포스팅하려 합니다.
현직장 업무 특성상 AutoCAD의 3rdParty Plugin 형태의 개발을 진행하다보니 Standalone 형태의 프로그램을 개발할 때 발생할 수 있는 문제를 지나치던 경우가 많았는데, 이번에 Plugin 형태에서 Standalone 형태로 변경하는 작업을 진행하게 되어 작은 문제들이 발생했었습니다.
그 중 하나가 바로 Application.MainWindow가 닫힌 이후에도 프로그램이 종료되지 않고 프로세스 형태로 남아있던 현상이었습니다.
현재 개발 중인 프로그램 특성상 Thread, Task와 같은 비동기 요소를 사용하기 때문에, 잉여 쓰레드의 존재가 의심되어 Visual Studio의 스레드 창을 이용해 확인해봤습니다.
스레드를 확인해봤으나, 딱히 의심갈만한 스레드가 존재하지 않았고, 실행 중인 모든 스레드가 Background 특성을 갖고있는 것으로 보다 문제될 것이 없었습니다.
스레드를 확인했는데 아무 이상이 없어 이때부터 "도대체 뭐가 문제지?" 하면서 멘탈이 흔들리더군요 ㅎㅎ 그래서 의심되는 코드를 하나하나 주석처리해가며 디버깅을 해봤습니다.
그러던 중 Application.Windows 내에 MainWindow가 닫힌 후에도 남아있는 Window를 발견했고, 해당 Window를 발생시키는 코드를 주석처리하니, 프로그램이 정상적으로 종료되더군요.
이를 단서롤 구글링을 조금 해보니 Application 내에는 ShutdownMode와 관련되었다는 걸 알 수 있었습니다.
Applications stop running only when the Shutdown method of the Application is called. Shut down can occur implicitly or explicitly, as specified by the value of the ShutdownMode property.
If you set ShutdownMode to OnLastWindowClose, Windows Presentation Foundation (WPF) implicitly calls Shutdown when the last window in an application closes, even if any currently instantiated windows are set as the main window (see MainWindow).
A ShutdownMode of OnMainWindowClose causes WPF to implicitly call Shutdown when the MainWindow closes, even if other windows are currently open.
The lifetime of some applications may not be dependent on when the main window or last window is closed, or may not be dependent on windows at all. For these scenarios you need to set the ShutdownMode property to OnExplicitShutdown, which requires an explicit Shutdown method call to stop the application. Otherwise, the application continues running in the background.
MSDN 참고 (https://learn.microsoft.com/en-us/dotnet/api/system.windows.application.shutdownmode?view=windowsdesktop-7.0)
MSDN의 글 내용처럼 Application은 ShutdownMode를 통해 암묵적, 묵시적으로 종료된다고 나와있습니다.
그래서 Application 진입지점에서 ShutdownMode를 OnMainWindowClose로 변경하니 정상적으로 종료가 되더군요 ㅎ
더 찾아보다 Application.Windows에 언제 Window가 추가되고, 관리되는지도 알게되었습니다.
Window 생성자에서 실행되는 Initalize 함수
.NET 코드를 보니 Window 인스턴스를 생성하는 순간부터 Application.Windows에 추가가 되는 것을 알 수 있습니다.
new Window(); // Application.Windows에 추가됨.
위 코드와 같이 Window 인스턴스를 생성하게되면 바로 추가가 되는 것입니다.
따라서 개발 중 잉여 Window를 생성하는 것만으로도 추후에 문제가 발생될 수 있겠네요 ㅎ
하지만, ShutdownMode를 OnMainWindowClose로 변경하기에는 앞으로 발생할 수 있는 오류들을 무시하게되고 유지보수할 때 힘들어질 수 있다는 생각에 내부에 존재하는 잔여 윈도우를 정리하는 방향으로 코드를 수정하여 해결했습니다.
정말 별거 아닌거 같은 오류였는데, 생각치도 못한 부분에서 해결을 해봄으로써 아직 내가 많이 부족하구나 하고 느끼게 되네요 ㅎ
이번 문제를 해결하면서 알게된 걸 정리하면 다음과 같습니다.
- Application 내에는 ShutdownMode 속성이 존재하고, 이를 제어함으로써 Application이 어느 조건일 때 종료될 수 있도록 조절할 수 있다.
- ShutdownMode가 OnLastWindowClose로 되어 있다면 잔여 Window가 남아있을 경우 MainWindow 창이 종료되더라도 Application은 종료되지 않는다.
- Window 인스턴스를 만들 때 해당 인스턴스를 잘 관리하여 마지막에 모두 Close 되도록 해야한다.
감사합니다.