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,直接发线程消息,激活这个窗口.

  • 相关阅读:
    FEniCS 1.1.0 发布,计算算术模型
    Piwik 1.10 发布,增加社交网站统计
    淘宝褚霸谈做技术的心态
    CyanogenMod 10.1 M1 发布
    Druid 发布 0.2.11 版本,数据库连接池
    GNU Gatekeeper 3.2 发布
    Phalcon 0.9.0 BETA版本发布,新增大量功能
    EUGene 2.6.1 发布,UML 模型操作工具
    CVSps 3.10 发布,CVS 资料库更改收集
    Opera 移动版将采用 WebKit 引擎
  • 原文地址:https://www.cnblogs.com/hgy413/p/3693637.html
Copyright © 2011-2022 走看看