void CInstanceChecker::QuitPreviousInstance(int nExitCode) { //Try to open the previous instances MMF HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename()); if (hPrevInstance) { // Open up the MMF int nMMFSize = sizeof(CWindowInstance); CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize)); if (pInstanceData != NULL) //Opening the MMF should work { // Lock the data prior to reading from it CSingleLock dataLock(&m_instanceDataMutex, TRUE); //activate the old window ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF? HWND hWnd = pInstanceData->hMainWnd; //Ask it to exit HWND hChildWnd = GetLastActivePopup(hWnd); PostMessage(hChildWnd, WM_QUIT, nExitCode, 0); } //Close the file handle now that we CloseHandle(hPrevInstance); } }
// Returns TRUE if a previous instance of the App is running. BOOL CInstanceChecker::PreviousInstanceRunning() { //Try to open the MMF first to see if we are the second instance HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename()); BOOL bPreviousInstance = (hPrevInstance != NULL); if (hPrevInstance) CloseHandle(hPrevInstance); return bPreviousInstance; }
// Activate the Previous Instance of our Application. HWND CInstanceChecker::ActivatePreviousInstance() { //Try to open the previous instances MMF HANDLE hPrevInstance = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename()); if (hPrevInstance) { // Open up the MMF int nMMFSize = sizeof(CWindowInstance); CWindowInstance* pInstanceData = (CWindowInstance*) ::MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize); if (pInstanceData != NULL) //Opening the MMF should work { // Lock the data prior to reading from it CSingleLock dataLock(&m_instanceDataMutex, TRUE); //activate the old window ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF HWND hWindow = pInstanceData->hMainWnd; if (hWindow) { CWnd wndPrev; wndPrev.Attach(hWindow); CWnd* pWndChild = wndPrev.GetLastActivePopup(); // Restore the focus to the previous instance and bring it to the foreground if (wndPrev.IsIconic()) wndPrev.ShowWindow(SW_RESTORE); pWndChild->SetForegroundWindow(); //Detach the CWnd we were using wndPrev.Detach(); } //Unmap the MMF we were using ::UnmapViewOfFile(pInstanceData); //Close the file handle now that we ::CloseHandle(hPrevInstance); //return the Window handle of the previous instance return hWindow; } //Close the file handle now that we ::CloseHandle(hPrevInstance); //When we have activate the previous instance, we can release the lock ReleaseLock(); } return NULL; }
//Activate the Previous Instance of our Application. HWND CInstanceChecker::ActivatePreviousInstance(LPCTSTR lpCmdLine, ULONG_PTR dwCopyDataItemData, DWORD dwTimeout) { //What will be the return value from this function (assume the worst) HWND hWindow = NULL; //Try to open the previous instances MMF HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename()); if (hPrevInstance) { //Open up the MMF int nMMFSize = sizeof(CWindowInstance); CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize)); if (pInstanceData) //Opening the MMF should work { //Lock the data prior to reading from it CSingleLock dataLock(&m_instanceDataMutex, TRUE); //activate the old window ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF hWindow = pInstanceData->hMainWnd; if (::IsWindow(hWindow)) { CWnd wndPrev; wndPrev.Attach(hWindow); CWnd* pWndChild = wndPrev.GetLastActivePopup(); //Restore the focus to the previous instance and bring it to the foreground if (wndPrev.IsIconic()) wndPrev.ShowWindow(SW_RESTORE); if (pWndChild) pWndChild->SetForegroundWindow(); if (lpCmdLine) { //Send the current apps command line to the previous instance using WM_COPYDATA COPYDATASTRUCT cds; cds.dwData = dwCopyDataItemData; DWORD dwCmdLength = static_cast<DWORD>(_tcslen(lpCmdLine) + 1); cds.cbData = dwCmdLength * sizeof(TCHAR); TCHAR* pszLocalCmdLine = new TCHAR[dwCmdLength]; //We use a local buffer so that we can specify a constant parameter //to this function #if (_MSC_VER >= 1400) _tcscpy_s(pszLocalCmdLine, dwCmdLength, lpCmdLine); #else _tcscpy(pszLocalCmdLine, lpCmdLine); #endif cds.lpData = pszLocalCmdLine; CWnd* pMainWindow = AfxGetMainWnd(); HWND hSender = NULL; if (pMainWindow) hSender = pMainWindow->GetSafeHwnd(); //Send the message to the previous instance. Use SendMessageTimeout instead of SendMessage to ensure we //do not hang if the previous instance itself is hung DWORD_PTR dwResult = 0; if (SendMessageTimeout(hWindow, WM_COPYDATA, reinterpret_cast<WPARAM>(hSender), reinterpret_cast<LPARAM>(&cds), SMTO_ABORTIFHUNG, dwTimeout, &dwResult) == 0) { //Previous instance is not responding to messages hWindow = NULL; } //Tidy up the heap memory we have used delete [] pszLocalCmdLine; } //Detach the CWnd we were using wndPrev.Detach(); } //Unmap the MMF we were using UnmapViewOfFile(pInstanceData); } //Close the file handle now that we CloseHandle(hPrevInstance); //When we have activate the previous instance, we can release the lock ReleaseLock(); } return hWindow; }
//Track the first instance of our App. //return TRUE on success, else FALSE BOOL CInstanceChecker::TrackFirstInstanceRunning() { //If a previous instance is running, just return prematurely if (PreviousInstanceRunning()) return FALSE; //If this is the first instance then copy in our info into the shared memory //First create the MMF int nMMFSize = sizeof(CWindowInstance); g_sinstanceData.hInstanceData = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, nMMFSize, GetMMFFilename()); if (g_sinstanceData.hInstanceData == NULL) { TRACE(_T("Failed to create the MMF even though this is the first instance, you might want to consider overriding GetMMFFilename()\n")); return FALSE; } //Open the MMF CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(g_sinstanceData.hInstanceData, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize)); ASSERT(pInstanceData != NULL); //Opening the MMF should work //Lock the data prior to updating it CSingleLock dataLock(&m_instanceDataMutex, TRUE); pInstanceData->hMainWnd = GetWindowToTrack(); UnmapViewOfFile(pInstanceData); //Since this will be the last function that will be called //when this is the first instance we can release the lock ReleaseLock(); return TRUE; }