應用程式只有一個執行個體

來源:互聯網
上載者:User

在項目開發中,經常要求系統在同一時刻在同一台機器上只能運行一個執行個體,可以通過這種方式實現
   在InitInstance()函數中添加如下代碼(可以函數最前邊添加,也可以放後邊點,不過最好放最前邊):
  

Sample Code
HANDLE m_hMutex = ::CreateMutex(NULL,TRUE,m_pszName);// m_pszName為互斥體 名 如"132"或者"my"
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
    AfxMessageBox("您已經運行了本軟體!");//彈出對話方塊確認不能運行第二個執行個體。
     return FALSE;
}

 

 

 

1: 建立一基於對話方塊的工程ex1,採用預設設定
  

 2: 用GUIDGEN.EXE產生一個全域標誌,#define one "產生的全域標誌"
   本例中產生的語句如下:#define one "0xbe8e2ce1, 0xdab6, 0x11d6, 0xad, 0xd0, 0x0,
   0xe0, 0x4c, 0x53, 0xf6, 0xe6"
  

3: 在應用程式類CEx1App::InitInstance()中,用CreateMutex函數建立一個互斥量,後調用函數GetLastError()
   如果結果等於ERROR_ALREADY_EXISTS說明已經有一個執行個體在運行了這時返回FALSE.
  BOOL CEx1App::InitInstance()
  {
  handle=::CreateMutex(NULL,FALSE,one);//handle為聲明的HANDLE類型的全域變數  ,前邊是個局部變數 故不用第4步
  if(GetLastError()==ERROR_ALREADY_EXISTS)
  {
  AfxMessageBox("應用程式已經在運行");
  return FALSE;
  }
  }

4:在CEx1App::ExitInstance()中,刪除這個互斥量
  int CEx1App::ExitInstance()
  {
  CloseHandle(handle);
  return CWinApp::ExitInstance();
  }

 

------------------------------一----------------------------------------------------------------

 

方法一:
我用得做多的方法是建立互斥體Mutex,使用Mutex代碼比較簡潔,但是此時不能取得已經啟動的執行個體視窗局柄,因此無法啟用已經啟動的執行個體視窗,代碼如下:
// -------------------------------------------------------------------------
// 函數  : CreateSendingWNDList
// 功能  : 建立互斥量,用於保證只啟動一個進程
// 傳回值 : int
//            成功   0
//     失敗   -1
//     存在進程執行個體 1
// 附註  :
// -------------------------------------------------------------------------
int CreateSendingWNDList(const TCHAR *pstrKSCoreAppName)
{
 //-------防止多次起動---------- 
 HANDLE hMutex = ::CreateMutex(0, true, pstrKSCoreAppName);
 int nRet = 0;
 if (hMutex)
 {
  if(GetLastError() == ERROR_ALREADY_EXISTS)
  {
   nRet = 1;
  }
  else
  {
   nRet = 0;
  }
 }
 else
 {
  nRet = -1;
 }

 return nRet;
}

// 在建立視窗前調用下面代碼
switch(CreateSendingWNDList(g_strKSCoreAppName))
{
case 0:
 // 正常啟動
 // TODO……

 break; 
case 1: 
 // 已存在進程,退出
 {
  ::MessageBox(NULL, TEXT("已經有一個執行個體在運行了。"), TEXT("注意"), MB_OK);
 }

case -1:// 無法建立,退出
default:
 return FALSE;
}

 

方法二:
一般來說,使程式只運行一個執行個體的最簡單的方法當然是使用FindWindow()尋找主視窗,如果主視窗已經存在了,當然說明已經有一個執行個體運行了。代碼如下:
// 這種方法有缺陷,視窗名字改變之後就再也找不到了,FindWindow()的參數ClassName和Caption比較難取得。
HWND hWnd = FindWindow(NULL, TEXT("SingleInstanceFW"));
if(IsWindow(hWnd))
{
 ::MessageBox(NULL, TEXT("已經有一個執行個體在運行了。"), TEXT("注意"), MB_OK);
 ::ShowWindow(hWnd, SW_NORMAL);     // 顯示
 ::SetForegroundWindow(hWnd);       // 啟用
 return FALSE;
}

 

方法三:

這種方法相比上面兩種方法,避免上面兩種方法的缺點,通過SetProp()為程式主視窗設定一個特殊的Property,然後在啟動時遍曆所有的視窗,找出包含著個Property的視窗局柄

。【這個附加的視窗屬性在視窗銷毀時也應該銷毀】這個方法的缺點就是代碼比較多一點,如下:

// 聲明全域的 屬性 名和 屬性值
TCHAR g_strKSCoreAppName[] = _T("AFX_KSInstall_CPP__12036F8B_8301_46e2_ADC5_A14A44A85877__");
HANDLE g_hValue = (HANDLE)1022;

// 定義枚舉視窗回呼函數
BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
 //TCHAR str[200] = {0};
 //::GetWindowText(hwnd, str, 200);
 HANDLE h = GetProp(hwnd, g_strKSCoreAppName);
 if(h == g_hValue)
 {
  *(HWND*)lParam = hwnd;
  return FALSE;
 }
 return TRUE;
}

// 主視窗建立前判斷
HWND oldHWnd = NULL;
::EnumWindows(EnumWndProc,(LPARAM)&oldHWnd);    //枚舉所有啟動並執行視窗
if (oldHWnd != NULL)
{
 ::MessageBox(NULL, TEXT("已經有一個執行個體在運行了。"), TEXT("注意"), MB_OK);

 ::ShowWindow(oldHWnd, SW_NORMAL);     // 顯示
 ::SetForegroundWindow(oldHWnd);       // 啟用
 return FALSE;
}

// 主視窗建立後設定,為視窗附加一個屬性
::SetProp(m_hWnd, g_strKSCoreAppName, g_hValue);

// 主視窗退出時移除該附加屬性
::RemoveProp(m_hWnd, g_strKSCoreAppName);

 

方法四:

上面的方法二和方法三都有一個弊病,不知道大家發現沒,那就是依賴於視窗的存在,沒有視窗的程式怎麼辦了,用方法一是可以的,不過方法一不太適合即時修改狀態,譬如我想提供選項給使用者,可以即時修改是否允許多執行個體,像KMP就提供了即時修改是否允許多執行個體,使用全域變數是一個比較好的解決方案,使用全域共用變數的方法則主要是在VC架構程式中通過編譯器來實現的。通過#pragma data_seg先行編譯指令建立一個新節,在此節中可用volatile關鍵字定義一個變數,而且必須對其進行初始化。Volatile關鍵字指定了變數可以為外部進程訪問。最後,為了使該變數能夠在進程互斥過程中發揮作用,還要將其設定為共用變數,同時允許具有讀、寫存取權限。這可以通過#pragma comment先行編譯指令來通知編譯器。下面給出使用了全域變數的進程互斥代碼清單:

#pragma data_seg("Shared")
int volatile g_lAppInstance = 0;
#pragma data_seg()
#pragma comment(linker,"/section:Shared,RWS")

if (0 == g_lAppInstance)
{
 g_lAppInstance = 1;
}
else if (1 == g_lAppInstance)
{
 ::MessageBox(NULL, TEXT("已經有一個執行個體在運行了。"), TEXT("注意"), MB_OK);
 return FALSE;
}
else
{
 // 直接啟動
}

【注意,代碼應該放在程式的入口處】

其實上面的方法可以兩種進行組合來實現一些比較特殊的需求,具體怎樣就自己去想了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.