亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#如何防止程序多次運行的技巧

2020-01-24 01:12:42
字體:
來源:轉載
供稿:網友

一、引言
最近發現很多人在論壇中問到如何防止程序被多次運行的問題的,如: 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文件預創建一個改程序進程時,我們去判斷這個變量是否存在,如果存在就說明這個進程已經運行,從而退出本次的程序,并且提示給用戶說該程序已經運行。
從上面的分析過程中可以看出,我們解決這個問題的思路就是從進程入手,第三點的思路就是直接從進程數量入手,而第四點思路也是從進程入手,只是做了一個變換罷了,讓一個變量來唯一標識一個進程,當變量存在時說明該程序進程也運行了。

二、使用互斥量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.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("/", "http://") == 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    }  }}

四、程序實現效果
四種實現方式的運行效果都是差不多的,這里就以實現方式一作為演示的,具體實現效果如下圖:

五、總結
寫這個專題主要是看到原因是看到有些朋友問了這樣的問題,所以就總結下具體的實現代碼來幫助遇到同樣問題的朋友做一個參考,同時也是對自己一個學習的積累和復習。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91久久在线播放| 日韩在线观看电影| 国产精品久久久久影院日本| 2019亚洲日韩新视频| 日本亚洲欧美成人| 久久免费福利视频| 欧美激情国内偷拍| 日本不卡高字幕在线2019| 成人免费淫片视频软件| 韩国一区二区电影| 亚洲精品欧美日韩专区| 亚洲wwwav| 久久影院资源站| 中文在线资源观看视频网站免费不卡| 日韩在线www| 亚洲视频电影图片偷拍一区| 欧美激情xxxx| 国产精品成人播放| 亚洲一区二区少妇| 日本精品一区二区三区在线播放视频| 欧美一级bbbbb性bbbb喷潮片| 久久精品国亚洲| 久久人人爽亚洲精品天堂| 青青草成人在线| 国产午夜精品一区理论片飘花| 欧美日韩一区二区在线播放| 97在线观看免费高清| 久久免费成人精品视频| 亚洲最大av网| 欧美电影免费观看高清完整| 中文欧美日本在线资源| 91精品啪在线观看麻豆免费| 欧美精品少妇videofree| 97免费中文视频在线观看| 日韩在线资源网| 欧美性猛交xxxxx水多| 日产精品久久久一区二区福利| 日韩av手机在线观看| 亚洲国产精品99久久| 日韩有码在线视频| 国产精品视频一区国模私拍| 最近2019中文字幕mv免费看| 国产日韩欧美在线观看| 国产99视频在线观看| 亚洲a中文字幕| 精品国产美女在线| 亚洲视频综合网| 亚洲精品之草原avav久久| 亚洲精选中文字幕| 国产精品国产三级国产aⅴ9色| 欧美日本在线视频中文字字幕| 日韩极品精品视频免费观看| 亚洲成年网站在线观看| 在线精品国产欧美| www.午夜精品| 8090理伦午夜在线电影| 欧美精品免费在线观看| 热re91久久精品国99热蜜臀| 日韩最新中文字幕电影免费看| 亚洲在线观看视频网站| 国产精品美女免费看| 亚洲欧美中文字幕在线一区| 伊人久久久久久久久久| 日韩中文字幕在线视频播放| 国产精品成人一区二区三区吃奶| 亚洲影院色在线观看免费| 日韩精品一二三四区| 欧美交受高潮1| 国产亚洲欧洲黄色| 91久久久久久久久久| 久久久噜噜噜久久久| 欧美日韩福利视频| 亚洲欧美一区二区三区在线| 日韩精品欧美国产精品忘忧草| 亚洲欧美日韩久久久久久| 欧美成人激情视频免费观看| 国产精品男人的天堂| 26uuu日韩精品一区二区| 日韩欧美极品在线观看| 91精品视频免费| 欧美色道久久88综合亚洲精品| 国模精品视频一区二区三区| 91精品久久久久久久久久久久久久| 欧美高清一级大片| 国产精品嫩草影院久久久| 国产久一一精品| 亚洲片在线观看| 国产午夜精品理论片a级探花| 亚洲成色999久久网站| 欧美在线视频a| 91大神福利视频在线| 黑人巨大精品欧美一区免费视频| 美女啪啪无遮挡免费久久网站| 成人欧美在线观看| 亚洲最新在线视频| 欧洲一区二区视频| 亚洲精品suv精品一区二区| 亚洲大胆美女视频| 国产精品扒开腿做| 欧美日韩xxx| 亚洲国产欧美日韩精品| 欧美在线激情网| 国产精品丝袜白浆摸在线| 中文字幕av一区中文字幕天堂| 久久6精品影院| 在线日韩第一页| 人体精品一二三区| 欧美激情精品久久久久久大尺度| 色在人av网站天堂精品| 88xx成人精品| 欧美在线观看一区二区三区| 亚洲性生活视频| 亚洲欧美日韩精品久久奇米色影视| 欧美日韩国产在线看| 亚洲国产欧美一区二区三区久久| 美女精品久久久| 欧美日韩亚洲一区二区三区| 国产91亚洲精品| 中文字幕在线看视频国产欧美| 日韩精品免费电影| 中文字幕v亚洲ⅴv天堂| 国产91精品青草社区| 69久久夜色精品国产7777| 欧美激情va永久在线播放| 一区二区三区 在线观看视| 亚洲欧美999| 久久在精品线影院精品国产| 久久精彩免费视频| 欧美性受xxxx黑人猛交| 亚洲加勒比久久88色综合| 亚洲国产成人精品久久久国产成人一区| 日韩在线欧美在线国产在线| 亚洲日本aⅴ片在线观看香蕉| 久99九色视频在线观看| 日本精品视频在线观看| 久久免费少妇高潮久久精品99| 亚洲国产精品va在线| 中文字幕日韩欧美在线| 精品偷拍各种wc美女嘘嘘| 欧美激情videoshd| 中文.日本.精品| 91久久精品日日躁夜夜躁国产| 欧洲精品在线视频| 日本欧美精品在线| 久久免费成人精品视频| 91亚洲永久免费精品| 国产福利精品视频| 欧美国产日韩在线| 中文字幕日韩精品在线观看| 高清日韩电视剧大全免费播放在线观看| 国产91成人在在线播放| 成人午夜激情网| 日韩av手机在线看| 日本久久中文字幕| 91麻豆国产语对白在线观看| 日韩av一区在线观看| 欧美激情精品久久久久久免费印度| 国产成人精品在线| 国产成人精品在线| 欧美激情综合色| 97av在线影院| 日韩av在线一区| 国产精品爱久久久久久久| 国产精品一区久久|