posted by 방랑군 2012. 1. 21. 21:22

기본적으로 .net과 C# 기반이면서,

  1. 하나의 인스턴스만을 허용하고
  2. (추가)실행시 포커스를 가져가지 않는 어플리케이션 개발! 
    창이 위로 뜨거나 작업표시줄이 번쩍거려서는 곤란하다.

메신저나 팝업 알림창 뭐 이런 용도로 필요할 듯하다. 내 경우 선거방송과 관련해서 백그라운드로 데이터를 업데이트해주는 유틸을 개발하기 위해 필요했다. 백그라운드로 뜬다지만 UI를 없앨 수는 없고, 번쩍대지 않고 뒤에 조용히 떠있으면 되는 그런 유틸이다.

이것은 쉬워 보이지만 막상 해보면 어렵다.
1의 single-instance app이란 것은 여러 가지 솔루션들이 나와 있고 그 중에 명령줄인수를 받을 수 있는 것으로는 visual basic으로부터 WindowsFormsApplicationBase를 가져다 쓰는 방법이 가장 쉽다.
코드프로젝트에 설명이 잘 돼있으면서 데모프로젝트까지 제공하고 있는 포스트가 있다.
http://www.codeproject.com/KB/cs/CSSIApp.aspx

2의포커스를 훔쳐가지 않기, 즉 "without activation" 이것도 쉽다.
Form의 ShowWithoutActivation 속성을 true로 설정하면 된다. read-only이기 때문에 다음과 같이 재정의하면 된다.

  protected override bool ShowWithoutActivation
  {
   get { return true; }
  }

그러나, 실제로 해보면 작동하지 않는다.
ShowWithoutActivation은 분명히 true로 설정되어 있음을 form 생성 후에도 확인할 수 있지만, 매번 실행시마다 창은 작업중이던 다른 창 위로 뜨고 포커스도 빼앗겼다.
어쩌다 창이 위로 뜨지 않는 경우도 생겼지만, 어쨌든 태스크바는 대화를 원하는 메신저 창처럼 마구 번쩍인다.

두 개의 서로 다른 문제에 대해서 각각 솔루션들은 넘쳐나지만 둘 다를 해결해주는 방법은 없었다. 시계는 어느새 11시 30분을 넘기고... 이제는 포기하고 싶은 마음 생길 때 쯤에 울리는 전화벨 소리~ 는 아니고 뭔가를 보았다.

그것은 visual basic 응용 프로그램 모델 개요라는 MSDN 아티클을 보고 있을 때였다. 내용은 이런 것이었다.
Visual Basic 응용 프로그램 모델을 사용하면 단일 인스턴스 응용 프로그램을 쉽게 만들 수 있습니다. 단일 인스턴스 응용 프로그램은 응용 프로그램 인스턴스를 한 번에 하나씩만 실행할 수 있다는 점에서 일반 응용 프로그램과 다릅니다. 단일 인스턴스 응용 프로그램에서 다른 인스턴스를 추가로 시작하려고 하면 원래 실행 중이던 인스턴스는 StartupNextInstance 이벤트를 통해 다른 시작이 시도되었다는 알림을 받게 됩니다. 이 알림에는 후속 인스턴스의 명령줄 인수가 포함됩니다. 그러면 응용 프로그램의 후속 인스턴스는 초기화가 실행되기 전에 닫힙니다.

단일 인스턴스 응용 프로그램은 시작될 때 자신이 응용 프로그램의 첫 번째 인스턴스인지 후속 인스턴스인지 확인합니다.

  • 첫 번째 인스턴스이면 정상적으로 시작됩니다.

  • 첫 번째 인스턴스가 실행되고 있는 동안 응용 프로그램을 시작하려는 시도가 이루어지면 그때마다 결과 동작은 매우 달라집니다. 후속 시도는 첫 번째 인스턴스에 명령줄 인수에 대해 알린 다음 즉시 종료됩니다. 첫 번째 인스턴스는 StartupNextInstance 이벤트를 처리하여 후속 인스턴스의 명령줄 인수가 무엇인지 확인한 다음 계속 실행됩니다.

    이 다이어그램은 후속 인스턴스에서 첫 번째 인스턴스에 신호하는 방법을 보여 줍니다.

StartupNextInstance 이벤트를 처리하여 단일 인스턴스 응용 프로그램이 동작하는 방식을 제어할 수 있습니다. 예를 들어, Microsoft Outlook은 일반적으로 단일 인스턴스 응용 프로그램으로 실행됩니다. Outlook이 실행되고 있을 때 Outlook을 다시 시작하려고 하면 포커스가 원래 인스턴스로 변경되고 다른 인스턴스는 열리지 않습니다.

음... 그런 것인가.
첫번째 인스턴스는 Startup, 그 다음부터는 StartupNextInstance 이벤트가 발생한다.
음 그래 StartupNextInstance... (이미 의식이 혼미한 상태)
전에는 기본 형식의 메서드를 더블클릭하면 자동으로 오버라이드가 됐던 것 같은데 왜 안 되는거야...
visual studio의 개체 브라우저를 하염없이 클릭만 하고 있다가...

헉!

"응용프로그램 인스턴스를 포그라운드로 가져와야 하는지"

저 구절이 눈에 번쩍 하고 띄었다.
그렇다... 이거 한 줄만 StartupNextInstance 이벤트 핸들러에 추가하면 된다.
eventArgs.BringToForeground = false;

원래부터 WindowsFormsApplicationBase에서는 지원하고 있었던 거였다. 이렇게 허무할 데가... 오늘 검색한 페이지만 해도 수백 개는 될텐데 ㅜㅜ
그렇지만 어쨌든 오늘 내로 해결해서 다행이라고 생각하는 양고였습니다.