一般软件,都是可以启动多个实例窗口的,但是有一些软件不需要启动多个实例窗口,那我们该如何防止启动多个实例窗口。防止启动多个创建我们常用的方法就是使用互斥对象。保证只运行一个实例窗口对象。使用CreateMutex()函数创建互斥对象,这个函数是Windows内核中的一个重要的对象。
当有一个实例对象已经运行的话,就需要把已经运行的实例对象放到桌面最上面。在此使用的函数有SetForeGroundWindow()。
使用的函数:
1.CreateMutex()
CreateMutex是一个计算机函数,作用是找出当前系统是否已经存在指定进程的实例。如果没有则创建一个互斥体。
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes, // 指向安全属性的指针
BOOLbInitialOwner, // 初始化互斥对象的所有者
LPCTSTRlpName // 指向互斥对象名的指针
);
- 返回值 Long,如执行成功,就返回互斥体对象的句柄;零表示出错。会设置GetLastError。如果返回的是一个有效句柄,但指定的名字已经存在,GetLastError也会设为ERROR_ALREADY_EXISTS,bInitialOwner的值将会被忽略。如果调用者限制了权限,GetLastError将会返回ERROR_ACCESS_DENIED,这个时候应该使用OpenMutex函数。
- lpMutexAttributes SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递零值(将参数声明为ByVal As Long,并传递零值),表示使用不允许继承的默认描述符
- bInitialOwner BOOL,如创建进程希望立即拥有互斥体,则设为TRUE。一个互斥体同时只能由一个线程拥有
- lpName String,指定互斥体对象的名字。用vbNullString创建一个未命名的互斥体对象。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体。这个名字可能不与现有的事件、信号机、可等待计时器或文件映射相符SetForeGroundWindow()
2.SetForegroundWindow
函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
函数原型:BOOL SetForegroundWindow(HWND hWnd)。
hWnd , 将要设置前台的窗口句柄..
返回值:如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。
例子:
第一步,在软件的XXXAPP.h中创建一个句柄
protected:
HANDLE m_hMutex;//创建一个句柄对象
第二步,在软件的XXXAPP.cpp中的InitInstance()函数中创建互斥对象
m_hMutex = ::CreateMutex(NULL,FALSE,_T("DEM"));//创建一个互斥对象,每一次程序打开的时候都会用
//CreateMutex函数创建
//创建互斥对象,并以第三个参数命名(次命名为唯一标识),
//如果存在则返回 ERROR_ALREADY_EXISTS
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AfxMessageBox(_T("已经有一个实例在运行了"));
return FALSE;
}
else
{
AfxMessageBox(_T("第一个运行的实例"));
}
这时,软件就已经拥有防止创建多个实例的功能了。
但是我们不仅需要防止产生多个实例,还要当实例运行的时候将已经运行的实例窗口显示到桌面窗口的最上面。这就需要以下步骤。
第三步、在显示的主窗口中的OnCreate()函数中设置窗口标志
int C只运行一个实例Dlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
//添加窗口属性标记
::SetProp(m_hWnd,AfxGetApp()->m_pszExeName,(HANDLE)1);
return 0;
}
第四步、在主窗口的销毁函数中释放窗口标志。
void C只运行一个实例Dlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 在此处添加消息处理程序代码
::RemoveProp(m_hWnd,AfxGetApp()->m_pszExeName);//当窗口关闭之后释放标志
}
第五步、在在软件的XXXAPP.cpp中的InitInstance()函数将已存在的窗口显示到桌面最上面。\
m_hMutex = ::CreateMutex(NULL,FALSE,_T("DEM"));//创建一个互斥对象,每一次程序打开的时候都会用CreateMutex函数创建
//创建互斥对象,并以第三个参数命名(次命名为唯一标识),
//如果存在则返回ERROR_ALREADY_EXISTS
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
//AfxMessageBox(_T("已经有一个实例在运行了"));
CWnd* pDesktopWnd = CWnd::GetDesktopWindow();//获取桌面句柄
CWnd* pWnd = pDesktopWnd->GetWindow(GW_CHILD);//获取桌面中所有的子窗口
while (pWnd != NULL)//判断是否还有子窗口
{
if (::GetProp(pWnd->m_hWnd,m_pszExeName))//获取窗口标记,如果获取到窗口标记
{
pWnd->SetForegroundWindow();//使用SetForegroundWindow函数将窗口移到窗口最前面。
return FALSE;
}
pWnd = pWnd->GetWindow(GW_HWNDNEXT);//获取下一个窗口
}
return FALSE;
}