C\#프로그램 이 여러 번 실행 되 는 것 을 방지 하 는 방법

13139 단어 C#프로그램 실행
머리말
최근 많은 사람들 이 포럼 에서 프로그램 이 여러 번 실행 되 는 것 을 방지 하 는 방법 에 대해 묻 는 것 을 발견 했다.예 를 들 어http://social.msdn.microsoft.com/Forums/zh-CN/6398fb10-ecc2-4c03-ab25-d03544f5fcc9그래서 여기 서 기록 하고 똑 같은 문 제 를 만난 친구 에 게 참고 하 는 동시에 자신 에 대한 축적 이기 도 한다.구체 적 인 실현 코드 를 소개 하기 전에 우 리 는 이 문 제 를 해결 하 는 사고방식 이 무엇 인지 명확 해 야 한다.다음은 내 가 생각 하 는 이 문 제 를 공유 하 는 방식 이다.
1.우리 가 exe 파일 을 클릭 하면 이 exe 프로그램 이 실 행 됩 니 다.우 리 는 이 프로그램의 인터페이스 를 볼 수 있 습 니 다.컴퓨터 에 있어 서 시스템 에서 이 프로그램의 진행 을 열 것 입 니 다.이것 은 우리 가 작업 관리 자 를 통 해 볼 수 있 습 니 다.(우리 가 exe 를 클릭 한 후에 프로그램 이 실 행 됩 니 다.시스템 은 프로그램 과 같은 이름 의 프로 세 스 를 만 들 것 입 니 다)
2.우리 가 프로그램 이 여러 번 실행 되 는 것 을 방지 해 야 한다.즉,프로그램 이 한 번 만 실 행 될 수 있다 는 것 이다.운영 체제 의 측면 에서 볼 때 이 프로그램의 프로 세 스 는 유일한 것 일 수 밖 에 없다 는 것 이다.여기 서 우 리 는 자 연 스 럽 게 생각 했다.이 프로그램의 프로 세 스 가 하나 밖 에 없다 는 것 을 확보 하려 면 우 리 는 이 프로그램의 프로 세 스 가 자신의 운영 체제 에서 실행 되 었 는 지 판단 해 야 한다.프로 세 스 가 실행 되 었 다 면 다음 에 exe 를 실행 할 때 이 프로그램 프로 세 스 를 다시 시작 하 는 것 이 아니 라 종료 합 니 다.알림 상 자 를 꺼 내 서 프로그램 이 실행 되 었 음 을 알려 줍 니 다.운영 체제 가 이 프로그램 프로 세 스 를 실행 하지 않 았 다 면 이 프로그램 을 실행 합 니 다.
3.이 문 제 는 이 프로그램의 프로 세 스 의 수량 문 제 를 판단 하 는 것 으로 바 뀌 었 습 니 다.이때 우 리 는.NET 이 이 프로 세 스 이름 을 얻 을 수 있 는 수량 을 제공 하 는 지 생각 합 니 다.만약 수량 이 1 보다 많 으 면 이 프로그램 이 이미 실행 되 었 고 작 으 면 프로그램 이 실행 되 지 않 았 음 을 나타 냅 니 다..NET 라 이브 러 리 에 익숙 한 사람 은.NET 라 이브 러 리 에 process 클래스 가 있다 는 것 을 알 고 있 을 것 이다.이 클래스 는 프로 세 스 의 추상 적 인 뜻 이다.(어떤 사람들 은 내 가 처음에는 이런 종류 가 있 는 지 몰 랐 는데 어 떡 하지?라 고 말한다.그것 은 바로 당신 의 영 어 를 시험 하 는 것 입 니 다.왜냐하면 프로 세 스 의 영 어 는 Process 이기 때 문 입 니 다.그러나 모든 프로 그래 밍 언어의 이름 은 매우 통속 적 이 고 알 기 쉽 습 니 다.이때 Process 로 MSDN 에서 검색 할 수 있 습 니 다.그러면 당신 도 이런 종 류 를 발견 할 수 있 습 니 다)
4.세 번 째 점 에서 프로 세 스 수량 을 찾 는 방향 을 제시 하 는 것 을 제외 하고 또 다른 실현 방향 은 바로-우리 가 프로 세 스 를 실행 할 때 이 프로 세 스 에 변 수 를 가 질 수 있 는 지 없 는 지 하 는 것 이다.이 변 수 는 이 프로 세 스 를 유일 하 게 표시 하 는 것 이다.exe 파일 을 클릭 하여 프로그램 변경 프로 세 스 를 미리 만 들 때 우 리 는 이 변수 가 존재 하 는 지 판단 한다.존재 한다 면 이 프로 세 스 가 실행 되 었 음 을 설명 하고 이번 프로그램 을 종료 하 며 프로그램 이 실행 되 었 음 을 알려 줍 니 다.
위의 분석 과정 에서 알 수 있 듯 이 우리 가 이 문 제 를 해결 하 는 방향 은 바로 프로 세 스 에 착안 하 는 것 이다.세 번 째 사 고 는 바로 프로 세 스 수량 에 착안 하 는 것 이다.네 번 째 사 고 는 프로 세 스 에 착안 하여 하나의 변 화 를 했 을 뿐 하나의 변 수 를 하나의 프로 세 스 를 유일 하 게 표시 하 게 하 는 것 이다.변수 가 존재 할 때 이 프로그램의 프로 세 스 도 실 행 된 것 을 설명 한다.
2.상호 배척 량 Mutex 사용
주요 한 실현 방향 을 알 게 된 후에 코드 의 실현 은 전혀 문제 가 되 지 않 습 니 다.상호 배척 의 실현 을 사용 하 는 것 은 바로 네 번 째 사고의 표현 입 니 다.우 리 는 이 프로그램 프로 세 스 를 위해 상호 배척 의 Mutex 대상 변 수 를 만 듭 니 다.이 프로그램 을 실행 할 때 이 프로그램 프로 세 스 는 서로 배척 하 는 Mutex 변 수 를 가지 게 됩 니 다.만약 에 이 프로그램 을 다시 실행 하면이 상호 배척 변수 가 존재 하 는 지 확인 합 니 다.(이 프로 세 스 가 존재 하 는 지 교체 합 니 다)존재 하면 프로그램 이 실행 되 었 음 을 설명 합 니 다.그렇지 않 으 면 실행 되 지 않 습 니 다.여기 서 주의해 야 할 것 은 제 다 중 스 레 드 동기 화 글 을 통 해 알 수 있 듯 이 Mutex 류 도 스 레 드 를 동기 화 할 수 있 습 니 다.그러면 다른 스 레 드 동기 화 클래스 도 본 주제 의 문 제 를 해결 할 수 있 습 니까?정 답 은 부정 입 니 다.Mutex 류 가 이 문 제 를 해결 할 수 있 는 이 유 는 Mutex 류 가 스 레 드 를 동기 화 할 수 있 을 뿐만 아니 라 프로 세 스 도 동기 화 할 수 있 기 때 문 입 니 다.실현 코드 를 구체 적 으로 살 펴 보 자.

using System;
using System.Threading;
using System.Windows.Forms;

namespace OnlyInstanceRunning
{
  static class Program
  {
    /// <summary>
    ///          。
    /// </summary>
    [STAThread]
    static void Main()
    {
      #region    :     
      bool createNew;

      // createdNew:
      //        ,          ( ,   name   null      )           ,       true;
      //                ,  false
      using (Mutex mutex = new Mutex(true, Application.ProductName, out createNew))
      {
        if (createNew)
        {
          Application.EnableVisualStyles();
          Application.SetCompatibleTextRenderingDefault(false);
          Application.Run(new Form1());
        }
        //          ,              
        else
        {
          MessageBox.Show("          ...");
          System.Threading.Thread.Sleep(1000);

          //                       。
          System.Environment.Exit(1);
        }
      }

      #endregion
    }
  }
}

3.프로 세 스 가 존재 하 는 지 직접 판단 하 는 방식 으로 이 문 제 를 해결한다.
3.1 이 프로그램의 프로 세 스 수 를 판단 하 는 방식
위의 사고 분석 을 한 후에 여러분 들 이 아래 코드 를 보면 한눈 에 알 수 있 을 것 이 라 고 믿 습 니 다.여 기 는 설명 이 많 지 않 고 코드 를 직접 보 겠 습 니 다.

  #region    :     
      Process[] processcollection = Process.GetProcessesByName(Application.CompanyName);
      //            ,          ,              ,        
      if (processcollection.Length >= 1)
      {
        MessageBox.Show("          。。");
        Thread.Sleep(1000);
        System.Environment.Exit(1);
      }
      else
      {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        //        
        Application.Run(new Form1());
      }
      #endregion 
3.2 프로그램 프로 세 스 가 존재 하 는 지 직접 판단 하 는 방식

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Way3
{
  static class Program
  {
    #region    :   Win32     
    /// <summary>
    ///          
    /// Win32      :http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
    /// </summary>
    /// <param name="hWnd">    </param>
    /// <param name="cmdShow">         </param>
    /// <returns>         ,      ;         ,     </returns>
    [DllImport("User32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);

    /// <summary>
    ///               ,       。         ,             。
    ///                         。 
    /// </summary>
    /// <param name="hWnd">               </param>
    /// <returns>         ,      ;          ,     </returns>
    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    //          
    private const int WS_SHOWNORMAL = 1;
    #endregion

    /// <summary>
    ///          。
    /// </summary>
    [STAThread]
    static void Main()
    {
      #region    :  Win32 API,                
      //      VS         ,   VS  F5      OnlyInstanceRunning.vshost,             ,    OnlyInstanceRunning       
      //                :http://msdn.microsoft.com/zh-cn/library/ms185331(v=vs.100).aspx
      //     OnlyInstanceRunning.exe        OnlyInstanceRunning,
      //             , currentProcess.ProcessName.Replace(".vshose","")         OnlyInstanceRunning

      //          ,         ,      
      Process process = RunningInstance();
      if (process == null)
      {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
      }
      else
      {
        //        ,             
        MessageBox.Show("          ......");
        HandleRunningInstance(process);
      }
      #endregion 
    }

    #region         
    /// <summary>
    ///          ,          null
    /// </summary>
    /// <returns></returns>
    private static Process RunningInstance()
    {
      //          
      Process currentProcess = Process.GetCurrentProcess();

      //                 
      //        ,       1
      Process[] processcollection = Process.GetProcessesByName(currentProcess.ProcessName.Replace(".vshost", ""));
      foreach (Process process in processcollection)
      {
        //     ID          ID                      
        //               ,            
        if (process.Id != currentProcess.Id)
        {
          if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == process.MainModule.FileName)
          {
            return process;
          }
        }
      }

      return null;
    }

    /// <summary>
    ///         
    /// </summary>
    /// <param name="instance"></param>
    private static void HandleRunningInstance(Process instance)
    {
      //     
      ShowWindow(instance.MainWindowHandle, WS_SHOWNORMAL);

      //        
      SetForegroundWindow(instance.MainWindowHandle);
    }

    #endregion
  }
}

3.3 3.2 실현 방식 에 존재 하 는 문제점 해결-최소 화 된 창 만 표시 할 수 있 고 트 레이 에 숨 기 면 실행 중인 프로그램 을 표시 할 수 없습니다.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Way4
{
  static class Program
  {

    #region    :   Win32     

    /// <summary>
    ///                      
    ///       :http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx
    /// </summary>
    /// <param name="lpClassName">   </param>
    /// <param name="lpWindowName">   </param>
    /// <returns>          ,    null</returns>
    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    /// <summary>
    ///              ,   SetForegroundWindow     
    /// </summary>
    /// <param name="hWnd">    </param>
    /// <param name="fAltTab">True        Alt/Ctrl +Tab   </param>
    [DllImport("user32.dll ", SetLastError = true)]
    static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

    ///// <summary>
    /////          
    ///// Win32      :http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
    ///// </summary>
    ///// <param name="hWnd">    </param>
    ///// <param name="cmdShow">         </param>
    ///// <returns>         ,      ;         ,     </returns>
    [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
    public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
    public const int SW_RESTORE = 9;
    public static IntPtr formhwnd;
    #endregion

    /// <summary>
    ///          。
    /// </summary>
    [STAThread]
    static void Main()
    {
      #region    :                
      //                      ,
      //                   ,                     
      //            :http://social.msdn.microsoft.com/Forums/zh-CN/6398fb10-ecc2-4c03-ab25-d03544f5fcc9
      Process currentproc = Process.GetCurrentProcess();
      Process[] processcollection = Process.GetProcessesByName(currentproc.ProcessName.Replace(".vshost", string.Empty));
      //        ,
      if (processcollection.Length >= 1)
      {
        foreach (Process process in processcollection)
        {
          if (process.Id != currentproc.Id)
          {
            //         0,          ,          
            if (process.MainWindowHandle.ToInt32() == 0)
            {
              //       
              formhwnd = FindWindow(null, "Form1");
              //                 
              ShowWindow(formhwnd, SW_RESTORE);
              SwitchToThisWindow(formhwnd, true);
            }
            else
            {
              //         ,               
              //            ,      
              SwitchToThisWindow(process.MainWindowHandle, true);
            }
          }
        }
      }
      else
      {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
      }
      #endregion
    }
  }
}
4.절차 실현 효과
네 가지 실현 방식 의 운행 효 과 는 모두 차이 가 많 지 않다.여기 서 실현 방식 을 보 여 주 는 것 으로 구체 적 인 실현 효 과 는 다음 과 같다.

총화
이 주 제 를 쓰 는 이 유 는 어떤 친구 들 이 이런 질문 을 하 는 것 을 보 았 기 때문에 구체 적 인 실현 코드 를 정리 하여 같은 문제 에 부 딪 힌 친 구 를 참고 하 는 동시에 자신의 학습 에 대한 축적 과 복습 이기 도 한다.

좋은 웹페이지 즐겨찾기