An implementation that lets an application run only one instance

  • 2020-04-01 23:30:54
  • OfStack

In our program, if we want to achieve the function similar to 360 software manager, we have to solve two problems. The first is to determine that the program has an instance running, and the second is to activate the running application instance and exit the second application instance.

For the first problem, we can detect the mutex or beacon object when the program starts by setting the named mutex object or the named beacon object. If the mutex or beacon object already exists, we can judge that an instance of the program is already running.

The second problem is how to find an instance of the application that is already running. If we can find a pointer to the main window of the instance that is running, we can call setgroundwindow to activate the instance. We can find the main window of a running instance in two forms, one more commonly found by calling FindWindowEx to find the handle to a running window, and the other in this article. By calling SetProp to set a mark for the main window of the application, GetDesktopWindow can be used to get the handle of the desktop window under the Windows environment. All the main Windows of the application can be regarded as the child Windows of the window. Then we can use the GetWindow function to get the handle of these Windows. Then use the Win32 SDK function GetProp to find out whether the main window of each application contains the mark we set, so that we can find the first instance main window we are looking for.

The following example shows a single document application with the project name of Mutex.


1 , in the application class InitInstance() Function to determine if an application instance is already running. 
BOOL CMutexApp::InitInstance()
{
       //Create a named beacon object.
       HANDLE hSem=CreateSemaphore(NULL,1,1," reform ");
       if(hSem)  //The beacon object was created successfully.
       {
              //If the beacon object already exists, an instance of the program is already running.
              if(ERROR_ALREADY_EXISTS==GetLastError())
              {                  
                     CloseHandle(hSem);      //Close the semaphore handle.
 
//Gets a child window of the desktop window.
                     HWND hWndPrev=::GetWindow(::GetDesktopWindow(),GW_CHILD);   
 
                     while(::IsWindow(hWndPrev))
                     {
                     //Determine whether the window has a flag that we set up beforehand, and if so, the window we are looking for, and activate it.
                            if(::GetProp(hWndPrev," reform "))   
                            {
                            //If the main window is minimized, its size is restored.
                                   if (::IsIconic(hWndPrev))     
                                          ::ShowWindow(hWndPrev,SW_RESTORE);
 
                                   //Activates the main window of the application.
                                   ::SetForegroundWindow(hWndPrev);
                                   return FALSE;                      //Exit the instance.
                            }
                            //Keep looking for the next window.
                            hWndPrev = ::GetWindow(hWndPrev,GW_HWNDNEXT);
                     }
                    
                     AfxMessageBox(" An instance is running, but its main window cannot be found! ");
              }
       }
       else
       {
              AfxMessageBox(" Failed to create beacon object, program exit! ");
              return FALSE;
       }
 
       AfxEnableControlContainer();
 
       // Standard initialization
       // If you are not using these features and wish to reduce the size
       //  of your final executable, you should remove from the following
       //  the specific initialization routines you do not need.
      
#ifdef _AFXDLL
       Enable3dControls();                     // Call this when using MFC in a shared DLL
#else
       Enable3dControlsStatic();      // Call this when linking to MFC statically
#endif
 
       // Change the registry key under which our settings are stored.
       // TODO: You should modify this string to be something appropriate
       // such as the name of your company or organization.
       SetRegistryKey(_T("Local AppWizard-Generated Applications"));
 
       LoadStdProfileSettings();  // Load standard INI file options (including MRU)
 
       // Register the application's document templates.  Document templates
       //  serve as the connection between documents, frame windows and views.
 
       CSingleDocTemplate* pDocTemplate;
       pDocTemplate = new CSingleDocTemplate(
              IDR_MAINFRAME,
              RUNTIME_CLASS(CMutexDoc),
              RUNTIME_CLASS(CMainFrame),       // main SDI frame window
              RUNTIME_CLASS(CMutexView));
       AddDocTemplate(pDocTemplate);
 
       // Parse command line for standard shell commands, DDE, file open
       CCommandLineInfo cmdInfo;
       ParseCommandLine(cmdInfo);
 
       // Dispatch commands specified on the command line
       if (!ProcessShellCommand(cmdInfo))
              return FALSE;
 
       // The one and only window has been initialized, so show and update it.
       m_pMainWnd->ShowWindow(SW_SHOW);
       m_pMainWnd->UpdateWindow();
 
       return TRUE;
}
2 , in the framework class OnCreate() In the function Set the find tag.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
       if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
              return -1;
      
       if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
       {
              TRACE0("Failed to create toolbar/n");
              return -1;      // fail to create
       }
 
       if (!m_wndStatusBar.Create(this) ||
              !m_wndStatusBar.SetIndicators(indicators,
                sizeof(indicators)/sizeof(UINT)))
       {
              TRACE0("Failed to create status bar/n");
              return -1;      // fail to create
       }
 
       // TODO: Delete these three lines if you don't want the toolbar to
       //  be dockable
 
       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
       EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_wndToolBar);
 
      
       //Set the find tag.
       ::SetProp(m_hWnd," reform ",(HANDLE)1);
 
       return 0;
}
3 , is to delete the mark set at the program exit, in response to the framework class WM_DESTROY Message for processing. 
void CMainFrame::OnDestroy()
{
       CFrameWnd::OnDestroy();
      
       // TODO: Add your message handler code here
       //Deletes the mark set.
       ::RemoveProp(m_hWnd," reform ");
}
 At this point, the ability to run only one instance of the application is complete. 

 


Related articles: