zoukankan      html  css  js  c++  java
  • 如何控制一个程序只能有一个进程

    EnumWindows的使用

    BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );该函数枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数,其中lParam是传递给lpEnumFunc的参数。回调函数返回FALSE将停止枚举,否则EnumWindows函数继续到所有顶层窗口枚举完为止。例如获取所有的桌面窗口句柄,并将其值放到CListBox中:

    进程统指应用程序的一个实例

    两个问题:

    1.在程序的第二个实例启动时,如何发现该程序已有 一个实例在运行

    2.如何将第一个实例激活,而第二个实例退出

    由于windows并没有给内核对象定义唯一的名字标准,而且不同的内核对象共用一个名字空间,可以借鉴定义一个有名字的内核对象来标识唯一(具体不做说明)

     第二个问题的难点是获取第一个实例的主窗对象指针或句柄,然后便可用SetForegroundWindow来激活。虽然FindWindow函数能寻找正运行着的窗口,但该函数要求指明所寻找窗口的标题或窗口类名,不是实现通用方法的途径。我们可以用Win32   SDK函数SetProp来给应用程序主窗设置一个特有的标记。用GetDesktopWindow可以获取Windows系统主控窗口对象指针或句柄,所有应用程序   主窗都可看成该窗口的子窗口,即可用GetWindow函数来获得它们的对象指针或句 柄。用Win32   SDK函数GetProp查找每一应用程序主窗是否包含有我们设置的特定 标记便可确定它是否我们要寻找的第一个实例主窗。使第二个实例退出很简单,只要让其应用程序对InitInstance函数返回FALSE即可。此外,当主窗口退出时 ,应用RemoveProp函数删除我们为其设置的标记。

    方法1:

    1、在App的InitInstance()中枚举所有窗口,查找本程序实例

    HWND oldHWnd = NULL;
    EnumWindows(EnumWndProc,(LPARAM)&oldHWnd);    //枚举所有运行的窗口
    if(oldHWnd != NULL)
    {
    	AfxMessageBox("本程序已经在运行了");
    	::ShowWindow(oldHWnd,SW_SHOWNORMAL);          //激活找到的前一个程序
    	::SetForegroundWindow(oldHWnd);                //把它设为前景窗口
    	return false;                                  //退出本次运行
    }
    

    2、添加EnumWndProc窗口过程函数:

    //添加的标识只运行一次的属性名
    CString  g_szPropName = "Your Prop Name";   //自己定义一个属性名
    HANDLE   g_hValue = (HANDLE)1;               //自己定义一个属性值
    
    BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lParam)
    {
    HANDLE h = GetProp(hwnd,g_szPropName);
    if( h == g_hValue)
    {
    *(HWND*)lParam = hwnd;
    return false;
    }
    return true;
    }
    
    

    3、在主窗口的 OnInitDialog()中添加属性

    //设置窗口属性
    SetProp(m_hWnd,g_szPropName,g_hValue);
    
    


     

     方法二:

     

    BOOL CTestApp::InitInstance() 
    { 
    	/********************************/ 
    	//   用应用程序名创建信号量  
    	HANDLE   hSem   =   CreateSemaphore(NULL, 1, 1, m_pszExeName);   
    	//   信号量已存在?  
    	//   信号量存在,则程序已有一个实例运行  
    	if (GetLastError() == ERROR_ALREADY_EXISTS)   
    	{   
    		//关闭信号量句柄  
    		CloseHandle(hSem);   
    		//寻找先前实例的主窗口  
    		HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD);   
    		while (::IsWindow(hWndPrevious))   
    		{   
    			// 检查窗口是否有预设的标记?   
    			//有,则是我们寻找的主窗  
    			if (::GetProp(hWndPrevious,   m_pszExeName))   
    			{   
    				//   主窗口已最小化,则恢复其大小  
    				if (::IsIconic(hWndPrevious))   
    					::ShowWindow(hWndPrevious, SW_RESTORE);   
    				//   将主窗激活  
    				::SetForegroundWindow(hWndPrevious);   
    				//   将主窗的对话框激活  
    				::SetForegroundWindow(::GetLastActivePopup(hWndPrevious));   
    				//   退出本实例  
    				return   FALSE;   
    			}   
    			//   继续寻找下一个窗口 
    			hWndPrevious  = ::GetWindow(hWndPrevious, GW_HWNDNEXT);   
    
    		}   
    		//   前一实例已存在,但找不到其主窗  
    
    		//   可能出错了  
    
    		//   退出本实例  
    		return   FALSE;   
    	} 
    	AfxEnableControlContainer(); 
    	//... ... 
    
    } 
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    { 
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 
    		return -1;
    
    	//设置寻找标记 ljs   
    
    	::SetProp(m_hWnd,   AfxGetApp()->m_pszExeName,(HANDLE)1);   
    
    	m_GameLobbyDlg.Create(this); 
    	m_bInit = TRUE; 
    	return 0; 
    }
    
    CMainFrame::~CMainFrame() 
    { 
    	//删除寻找标记  
    	::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName);  
    
    } 
    
    


     

    方法三:

    ::CreateMutex(NULL,TRUE,m_pszExeName);   
    
    if(GetLastError()==ERROR_ALREADY_EXISTS)   
    {   
    	//   寻找先前实例的主窗口  
    	HWND   hWndPrevious   =   ::GetWindow(::GetDesktopWindow(),   GW_CHILD);   
    	while(::IsWindow(hWndPrevious))   
    	{   
    
    		if (::GetProp(hWndPrevious,m_pszExeName))   
    		{   
    			// 主窗口已最小化,则恢复其大小  
    			if (::IsIconic(hWndPrevious))   
    				::ShowWindow(hWndPrevious,   SW_RESTORE);   
    			//   将主窗激活  
    			::SetForegroundWindow(hWndPrevious);   
    			//   将主窗的对话框激活  
    			::SetForegroundWindow(::GetLastActivePopup(hWndPrevious));   
    			//   退出本实例  
    			return   FALSE;   
    		}   
    		hWndPrevious   =   ::GetWindow(hWndPrevious,   GW_HWNDNEXT);   
    
    	}   
    	return   FALSE;    
    
    } 
    


    方法四: 

    另建线程创建一个窗口,记录APP的m_hWnd,直接发线程消息,激活这个窗口.

  • 相关阅读:
    ASP.NET使用SWFUpload上传大文件教学
    Gridview自定义分页(转载)
    扩展GridView之个性分页(转载)
    畅通工程
    一个人的旅行
    Stockbroker Grapevine
    Arbitrage
    More is better
    HDU Today
    Minimum Transport Cost
  • 原文地址:https://www.cnblogs.com/hgy413/p/3693637.html
Copyright © 2011-2022 走看看