青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

yehao's Blog

防止C++程序重復(fù)運(yùn)行的幾種方法

轉(zhuǎn)自http://hi.baidu.com/dreamyguy/blog/item/aacc6f44086afe45500ffef9.html

有時候,為了某些要求,我們希望程序?qū)嵗贿\(yùn)行一次。而在VB6中,我們可以很輕易的根據(jù)App.hPreInstance來判斷程序是否已經(jīng)運(yùn)行。但是在C++中,這一切就變得不是那么容易。

雖然WinMain函數(shù)有hPreInstance參數(shù)來指示,但是那是在Win16位的前提下,到了32Bit時代,那個參數(shù)已經(jīng)完全成為擺設(shè)。

而本文正好探討了如何防止C++程序重復(fù)運(yùn)行的方法。

PS:因?yàn)楸救耸褂肕FC,所以為了方便,所有代碼均為以MFC為基礎(chǔ)。大家可以根據(jù)自己需要更改

  1.查找窗體

對于存在GUI窗體(CUI暫不討論)的程序來說,最容易想到的就是利用FindWindow,以標(biāo)題作為參數(shù)進(jìn)行查找主窗體,然后使其關(guān)閉即可。

通常,我們能寫出如下代碼:

// Find Window by Caption
// Add this code in InitInstance function of class 
// you have derived from the CWinApp class

HWND hWnd 
= ::FindWindow(NULL, "MFCDialog");

if (hWnd)
{
AfxMessageBox(
"Has been running");
return FALSE;
}

 

以上的代碼可以簡單的起到防止重復(fù)啟動的效果,但是局限性很大。

首先,由于在FindWindow中要指定窗體的標(biāo)題,如果窗體的標(biāo)題在程序運(yùn)行中是不斷變化的,那么就給搜索帶來了一定難度。

而且,如果其他程序也恰好是用相同的標(biāo)題的話……- -#。當(dāng)然,你可以通過在FindWindow中指定類名來減少錯誤。但是如果你看過我前面寫的文章的話,你就會發(fā)現(xiàn),MFC注冊窗口類并不是那么隨意,而是經(jīng)過N次陰謀籌劃之后……

看來這方法的局限性的確很大- -#

  2.額外窗體存儲

此方法來源于對上面一種方法的補(bǔ)充,因?yàn)橥ㄟ^搜索MFC的窗體類比較困難,而且準(zhǔn)確度不一定高。所以,我想到了使用額外窗體存儲(Extra Widnow Memory)的方法

PS:關(guān)于什么是額外窗體存儲,請自行g(shù)oogle或MSDN或查看我曾經(jīng)寫的The Analyses Of Windows Runnning Principle

如果你使用SDK進(jìn)行開發(fā),可以在創(chuàng)建窗體時填充這一屬性,然后用GetWindowLong獲取。

而由于我使用MFC,所以我更關(guān)注如何在MFC中使用這一屬性。

一般來說,我們可以使用SetWindowLong對額外窗體存儲進(jìn)行填充,然后用GetWindowLong獲取,最后配合FindWindow來檢驗(yàn)程序是否重復(fù)運(yùn)行。

// Add this code in InitDialog function
// and you can specify any number you want
BOOL bRet = ::SetWindowLong(GetSafeHwnd(), GWL_USERDATA, 256);

// Add this code in InitInstance function
// Find Window by using extra memory

HWND hWnd 
= FindWindow(NULL, "MFCDialog");

if (hWnd)
{
BOOL bRet 
= ::GetWindowLong(hWnd, GWL_USERDATA);

if (256 == bRet)  // compare
    {
AfxMessageBox(
"Has been running");
return FALSE;
}
}

 

 3.全局原子

你可以使用GlobalAddAtom將某個特定的字符串添加到全局原子列表(Global Atom Table),然后在程序運(yùn)行時檢查該字符串即可。

但是這個方法有一個致命的弱點(diǎn),程序退出時,Windows不會自動為你刪除添加到列表中的Atom,而是需要你自己使用GlobalDeleteAtom進(jìn)行刪除。

這就意味著,如果你的程序意外的退出了,沒有刪除添加的Atom,那么,你的程序?qū)o法運(yùn)行。

所以,這并不是一個好方法。


  4.枚舉進(jìn)程

這或許是一個畢竟正常,或者說相對穩(wěn)定的方法。

我們可以使用CreateToolhelp32Snapshot或者EnumProcess來枚舉當(dāng)前的進(jìn)程,然后檢查是否已經(jīng)運(yùn)行。如果擔(dān)心存在同名的進(jìn)程,還可以檢查路徑。

//   關(guān)閉一個進(jìn)程  
static   bool   CloseApplication(CString   sAppToClose,   CString   sAppToUpdate,    
CString   sFilename,   bool   bAskUser   /*   =   true   */)  
{  
//   Declare   variables  
HANDLE   hProcessSnap   =   NULL;  
PROCESSENTRY32   pe32   =   {NULL};  
CString   sCompare,   sTemp;  

       //sProcessFileName是你的進(jìn)程名  
CString   sProcesFilename   =   m_pPath->ExtractFilename(sFilename);  
CLanguage   *   pLanguage   =   CLanguage::Instance();  

//調(diào)整統(tǒng)一大小寫格式,方便比較、  
#if   (_MFC_VER   <   0x0700)  
sProcesFilename.MakeLower();  
#else  
CString   sLowerTemp;  
sLowerTemp   =   sProcesFilename;  
sProcesFilename   =   sLowerTemp.MakeLower();  
#endif  

hProcessSnap   =   CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,   0);  

pe32.dwSize   =   sizeof(PROCESSENTRY32);  
//   系統(tǒng)進(jìn)程快照  
if (Process32First(hProcessSnap,   &pe32))  
{  
do  
{  
sCompare.Format("%s",   pe32.szExeFile);  

#if   (_MFC_VER   <   0x0700)  
sCompare.MakeLower();  
#else  
CString   sLowerTemp;  
sLowerTemp   =   sCompare;  
sCompare   =   sLowerTemp.MakeLower();  
#endif  


//   Check   if   we   found   the   right   process  
if(sCompare   ==   sProcesFilename)  
{  
//   If   we   are   not   in   hidden   mode  
if(bAskUser)  
{  
//Set   up   confirmation   text  
sTemp.Format(pLanguage->GetString(IDS_CONFIRMATION_CLOSEAPPLICATION_EXPLANATION),  
sAppToClose,   sAppToUpdate,   sAppToClose);  

//Ask   confirmation  
CConfirmationDlg   dlgConfirm(pLanguage->GetString(IDS_CONFIRMATION_CLOSEAPPLICATION_TITLE),  
pLanguage->GetString(IDS_CONFIRMATION_TITLE),   sTemp,  
pLanguage->GetString(IDS_GENERAL_YES),   pLanguage->GetString(IDS_GENERAL_NO));  
if(dlgConfirm.DoModal()   ==   IDNO)  
{  
return   false;  
}  
}  

//   Get   handle   to   process  
HANDLE   hProcess   =   OpenProcess(PROCESS_ALL_ACCESS,   FALSE,   pe32.th32ProcessID);  

//   Exit   process  
DWORD   exCode;  
GetExitCodeProcess(hProcess,   &exCode);  
TerminateProcess(hProcess,   exCode);  

//   Wait   until   process   is   finished  
if   (WaitForSingleObject(hProcess,   30000)   ==   WAIT_TIMEOUT)  
return   false;  
}  
}   while   (Process32Next(hProcessSnap,   &pe32));  
}  
else  
{  
return   false;  
}  

return   true;  
}

PS:在Vista下使用EnumProcess時,要注意權(quán)限問題,OpenProcess增加了一個新的權(quán)限常數(shù),僅限Vista。如果不增加這個參數(shù),很多進(jìn)程是無法被枚舉出來的(不過MS不印象我們自己的進(jìn)程- -#)。


  5.互斥對象

使用互斥對象來防止程序重復(fù)運(yùn)行是一個很常用的做法,而且M$也推薦使用這種方法。和上面的幾種方法相比,需要寫的代碼少,而且效率比較高。所謂方便易用~

一般我們會使用CreateMutex來創(chuàng)建互斥體,當(dāng)?shù)诙蝿?chuàng)建相同的互斥體時,這個API會返回前一個互斥體的Handle,而GetLastError則會返回ERROR_ALREADY_EXITS

// Mutex Object 
// Add this code in InistInstance function
  
HANDLE hMutex 
= NULL;
TCHAR 
*lpszName = "TestMutex";

hMutex 
= ::CreateMutex(NULL, FALSE, lpszName);
DWORD dwRet 
= ::GetLastError();

if (hMutex)
{
if (ERROR_ALREADY_EXISTS == dwRet)
{
AfxMessageBox(
"Has been running");
CloseHandle(hMutex);  
// should be closed
      return FALSE;
}
}
else
{
AfxMessageBox(
"Create Mutex Error");
}

// Add this code in Destruction function
  
::CloseHandle(hMutex);

使用互斥體時要注意幾個問題:
在CreateMutex之后馬上GetLastError,GetLastError是一個很復(fù)雜的API,任何牽涉到GetLastError的操作在執(zhí)行之后,都會覆蓋先前的值。

把正常的CloseHandle寫到窗體的析構(gòu)函數(shù)或者程序?qū)ο蟮奈鰳?gòu)函數(shù)里。不要在CreateMutex之后立刻CloseHandle,否則互斥對象會被清空。

這也是我當(dāng)初所犯的錯誤,(不知道網(wǎng)上那么多錯誤的代碼是不是經(jīng)過Debug的囧),當(dāng)互斥對象的最后一個Handle被Close之后,互斥對象將被刪除。如果程序在退出時沒有清空互斥對象,Windows將會執(zhí)行這一操作。當(dāng)然,把次操作交給OS不是一個好習(xí)慣。

詳情請看MSDN的引用:
引用:
Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.
轉(zhuǎn)自:http://bbs.cfan.com.cn/viewthread.php?tid=793295
http://topic.csdn.net/t/20060424/09/4708145.html
http://student.csdn.net/space.php?uid=110004&do=thread&id=3278

posted on 2011-05-03 18:28 厚積薄發(fā) 閱讀(746) 評論(0)  編輯 收藏 引用 所屬分類: Windows編程

導(dǎo)航

<2025年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

統(tǒng)計

常用鏈接

留言簿

隨筆分類

文章分類

文章檔案

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            日韩一区二区久久| 国产精一区二区三区| 美玉足脚交一区二区三区图片| 久久www成人_看片免费不卡| 久久婷婷成人综合色| 玖玖玖国产精品| 欧美视频日韩| 黄色一区二区在线| 99精品国产一区二区青青牛奶| 一区二区三区精密机械公司 | 欧美日本三区| 国产视频在线观看一区| 在线看片一区| 国产精品99久久久久久宅男| 久久久91精品| 亚洲精品极品| 一区二区三区日韩精品视频| 亚洲精品在线视频观看| 久久久噜噜噜久久中文字幕色伊伊| 欧美久久久久久蜜桃| 99riav国产精品| 亚洲一区制服诱惑| 欧美绝品在线观看成人午夜影视| 亚洲午夜精品17c| 欧美成人免费大片| 99re8这里有精品热视频免费| 国产精品久久91| 亚洲一区3d动漫同人无遮挡| 亚洲欧美日韩区| 国产精品嫩草久久久久| 一区二区三区国产精品| 香蕉成人伊视频在线观看| 欧美性一区二区| 99精品久久| 久久精品国语| 国产一区自拍视频| 久久久久久久一区| 欧美日韩亚洲三区| 亚洲香蕉成视频在线观看| 欧美制服丝袜| 亚洲欧美中文在线视频| 一本在线高清不卡dvd | 宅男噜噜噜66一区二区66| 欧美激情一区二区三区蜜桃视频 | 国内精品久久久久国产盗摄免费观看完整版 | 亚洲大胆av| 亚洲影院色无极综合| 日韩一级精品| 欧美成人一区二区三区片免费| 国产一区二区精品| 久久久精品国产99久久精品芒果| 欧美精品久久久久久久免费观看| 久久精品国产清高在天天线| 亚久久调教视频| 好男人免费精品视频| 久久综合五月天婷婷伊人| 久久精品国产一区二区三区免费看| 一区二区成人精品 | 午夜亚洲福利| 午夜精品在线| 欧美性大战久久久久久久蜜臀| 亚洲国产乱码最新视频| 欧美激情亚洲一区| 欧美69wwwcom| 欧美视频精品在线| 日韩视频精品在线观看| 亚洲精品一区二区三区蜜桃久| 亚洲美女啪啪| 一区二区三区视频观看| 欧美日韩一区免费| 日韩亚洲欧美中文三级| 亚洲视频一区在线观看| 欧美日韩在线观看一区二区| 日韩视频一区| 亚洲一区二区三区中文字幕| 欧美视频二区| 亚洲欧美中文日韩v在线观看| 亚洲欧美在线视频观看| 国产日韩在线一区| 久久久精品动漫| 欧美顶级大胆免费视频| 99精品欧美一区二区三区综合在线| 欧美电影免费网站| 99精品黄色片免费大全| 黄色国产精品| 美日韩免费视频| 日韩视频一区| 欧美在线视屏| 欧美精品在线观看| 在线性视频日韩欧美| 欧美在线精品免播放器视频| 激情久久婷婷| 欧美日本高清| 亚洲欧美日本日韩| 老色批av在线精品| 中文成人激情娱乐网| 国产乱码精品一区二区三区五月婷| 久久激情综合网| 亚洲欧美日韩在线观看a三区| 久久亚洲精品视频| 日韩视频在线永久播放| 欧美专区在线观看| 最新成人av网站| 久久漫画官网| 一本色道久久| 蜜臀av性久久久久蜜臀aⅴ四虎 | 久久国产视频网| 亚洲激情第一区| 亚洲激情在线播放| 久久影院亚洲| 亚洲午夜精品| 午夜精品一区二区三区四区 | 国产精品二区二区三区| 久久精品综合网| 中文一区在线| 亚洲国产欧美国产综合一区| 午夜精品免费视频| 亚洲日本在线观看| 国产香蕉97碰碰久久人人| 欧美精品亚洲精品| 久久久综合视频| 亚洲一区二区影院| 亚洲人成欧美中文字幕| 美日韩在线观看| 久久gogo国模裸体人体| 亚洲图片欧美日产| 99热在这里有精品免费| 久久视频一区| 性色av一区二区三区| 日韩午夜免费视频| 亚洲第一天堂无码专区| 日韩午夜激情| 亚洲第一页在线| 狠狠色狠狠色综合日日小说| 国产精品色婷婷| 久久成人国产| 香蕉免费一区二区三区在线观看 | 欧美在线一二三四区| 亚洲午夜女主播在线直播| 亚洲精品一线二线三线无人区| 欧美激情综合五月色丁香| 久久婷婷国产综合精品青草| 久久精品国产欧美亚洲人人爽| 亚洲男人第一av网站| 蜜桃av久久久亚洲精品| 久久久久久网| 亚洲免费观看| 亚洲最黄网站| 一区二区三区四区蜜桃| 亚洲午夜av在线| 亚洲一区二区三区免费视频| 亚洲一区二区在线视频| 在线免费观看欧美| 亚洲黄色有码视频| 亚洲精品视频免费观看| 99精品视频免费| 亚洲一区日韩在线| 性视频1819p久久| 黄色一区二区三区| 激情文学综合丁香| 91久久精品日日躁夜夜躁欧美 | 禁断一区二区三区在线| 黑人一区二区| 亚洲欧洲一区二区在线播放| 亚洲免费激情| 欧美亚洲在线| 美女爽到呻吟久久久久| 亚洲国产成人午夜在线一区| 99国内精品久久久久久久软件| 一本久道久久综合中文字幕| 亚洲综合成人婷婷小说| 久久久亚洲综合| 欧美日韩免费一区二区三区| 国产精品第13页| 激情综合色综合久久综合| 亚洲精品免费电影| 亚洲一区二区三区涩| 久久露脸国产精品| 亚洲国产精品久久人人爱蜜臀 | 午夜精品一区二区三区在线视| 久久久999精品免费| 欧美女同在线视频| 国模套图日韩精品一区二区| 日韩视频不卡中文| 久久久999精品免费| 亚洲日韩成人| 久久国产精品色婷婷| 欧美日韩国产一区二区| 麻豆成人综合网| 国产精品视频不卡| 亚洲理伦在线| 久久在线91| 欧美成人免费大片| 亚洲欧美日本视频在线观看| 免费成人高清视频| 国产日韩欧美亚洲一区| 在线视频亚洲| 欧美国产精品日韩| 欧美资源在线| 国产精品你懂的在线|