posted by 방랑군 2012. 1. 21. 21:27
C#을 다루다보면 간혹 응용 프로그램의 중복 실행을 방지해야하는 경우가 있습니다.

특히, 소켓 프로그램의 경우 중복 실행이 될 경우 포트 충돌 등으로 오류가 발생할 소지가 있어 프로그램 실행시 중복 실행을 방지하는 알고리즘은 필수라고 생각이 됩니다.

필자의 경우는 제작한 프로그램이 트래이 아이콘에 등록되다 보니 사용자들이 간혹 실수로 프로그램을 다시 실행하는 경우가 종종 있어서 Mutex를 사용하여 중복실행을 방지하고 있습니다.

프로세스를 찾아서 하는 방식도 있지만 여기서 Mutex를 이용하는 방법을 소개하고자 합니다.

Mutex 개념
    Mutex는 스레드 동기화의 한 방식으로 공유 리소스를 하나의 스레드가 단독으로 액세스할 수 있도록 합니다. 즉, 스레드가 뮤텍스를 가져오면 첫 번째 스레드가 뮤텍스를 해제할 때까지 해당 뮤텍스를 가져오려는 두 번째 스레드는 일시 중단(대기)됩니다.

중복 실행 방지 원리
    중복 실행 방지의 경우는 호출한 스레드가 초기 소유권를 가지도록 설정하여 Mutex 생성시 초기 소유권이 부여되었는지의 여부에 따라 실행과 중단을 결정합니다.

  • 소유권이 부여된 경우라면 사용중인 스레드가 없으므로 프로그램 가동
  • 소유권이 부여되지 않은 경우라면 이미 다른 스레드가 사용 중이므로 프로그램 종료

각 방식에 따라 장단점이 있지만 Mutex의 경우 간결하고 코드가 짧아 프로그램에 좋을 듯 합니다.
  • Mutex를 사용하기 위해서는 System.Threading 네임 스페이스를 추가합니다.
  • Main함수에 알고리즘을 구현합니다.

1. Mutex 함수 설명


    Name Space

    • System.Threading

      public Mutex(	bool initiallyOwned,	string name,	out bool createdNew  )
    Parameters
    • bool initiallyOwned : 호줄하는 쓰레드가 뮤텍스의 초기 소유권을 갖는지를 지정
    • string name : 뮤텍스 이름
    • out bool createdNew : 소유권 부여 여부

2. C# 프로그램 코드


?
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
28
29
30
31
//Program.CS
//namespace에 아래 추가
using System.Threading;
[STAThread]
static void Main()
{
// 기존 코드 주석 처리
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
bool bNew;
Mutex mutex = new Mutex(true, "MutexName", out bNew);
if(bNew)
{
// 소유권이 부여
// 즉 해당 프로그램이 실행되고 있지 않은 경우
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
// 뮤텍스 릴리즈
mutex.ReleaseMutex();
}
else
{
// 소유권이 부여되지 않음
MessageBox.Show("이미실행중입니다.");
Application.Exit();
}
}
C# 프로그램 중복 실행 방지 Mutex / Using a mutex to prevent multiple application from running
http://all4cs.tistory.com - 두그미의 사는 이야기

'강좌 > C#' 카테고리의 다른 글

VB.NET and C# 의 비교문서  (0) 2012.01.21
C# 으로 만든 DLL asp에서 사용  (0) 2012.01.21
.Net single-instance application without activation  (0) 2012.01.21
C# 사운드 재생  (1) 2012.01.21
SELECT 함수  (0) 2012.01.19
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에서는 지원하고 있었던 거였다. 이렇게 허무할 데가... 오늘 검색한 페이지만 해도 수백 개는 될텐데 ㅜㅜ
그렇지만 어쨌든 오늘 내로 해결해서 다행이라고 생각하는 양고였습니다.