轉自:https://www.cnblogs.com/qinfengxiaoyue/archive/2013/04/29/3051401.html
主要涉及兩個問題:
1.在程序的第二個實例啓動時,檢測該程序是否已有一個實例在運行;
2. 當第一個實例隱藏或最小化狀態時,把第一實例激活,第二個實例退出。
對於第一個問題,可以通過給應用程序設置互斥量/信號量,實例啓動時首先檢測該信號量,如已存在,則說明程序已運行一個實例。第二個問題的難點是獲取第一個實例的主窗對象指針或句柄,然後便可用SetForegroundWindow來激活。雖然FindWindow函數能尋找正運行着的窗口,但該函數要求指明所尋找窗口的標題或窗口類名,不是實現通用方法的途徑。我們可以用Win 32 SDK函數SetProp來給應用程序主窗設置一個特有的標記。用GetDesktopWindow可以獲取Windows系統主控窗口對象指針或句柄,所有應用程序主窗都可看成該窗口的子窗口,即可用GetWindow函數來獲得它們的對象指針或句柄。用Win 32 SDK函數GetProp查找每一應用程序主窗是否包含有我們設置的特定標記便可確定它是否我們要尋找的第一個實例主窗。使第二個實例退出很簡單,只要讓其應用程序對象的InitInstance函數返回FALSE即可。此外,當主窗口退出時,應用RemoveProp函數刪除我們爲其設置的標記。
下面通過在CWinApp的成員函數InitInstance/ExitInstance和CWnd的成員函數OnCreate/OnDestroy中添加若干代碼實現。
CWndApp中添加:
BOOL CMFCXXXApp::InitInstance()
{
this->m_hMutex = ::CreateMutexW(NULL,FALSE,this->m_pszAppName);//m_hMutex是新增的成員變量
if(::GetLastError()==ERROR_ALREADY_EXISTS)
{
::CloseHandle(m_hMutex);
HWND hPre = ::GetWindow(::GetDesktopWindow(),GW_CHILD);
while(::IsWindow(hPre))
{
if(::GetPropW(hPre,this->m_pszAppName))
{
if(::IsIconic(hPre))
{
::ShowWindow(hPre,SW_RESTORE);
}
::SetForegroundWindow(hPre);
::SetForegroundWindow(::GetLastActivePopup(hPre));
return false;
}
hPre = ::GetWindow(hPre,GW_HWNDNEXT);
}
}
//......
//以下省略
}
int CMFCXXXApp::ExitInstance()
{
::CloseHandle(this->m_hMutex);
return CWinApp::ExitInstance();
}
CWnd添加:
int CMFCXXXDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您專用的創建代碼
::SetPropW(this->m_hWnd,::AfxGetAppName(),(HANDLE)1);
return 0;
}
void CMFCXXXDlg::OnDestroy()
{
CDialogEx::OnDestroy();
::RemovePropW(this->m_hWnd,::AfxGetAppName());
}