July7th

导航

VC只运行一个程序实例

方法有很多,以下只是提供一种用的多的

一. 单文档程序

在程序App类的InitInstance中添加如下代码

BOOL CDDZApp::InitInstance()
{
	/*只运行一个实例*/
	//创建命名信标对象。  
	HANDLE hSem = CreateSemaphore(NULL, 1, 1, "DDZ");
	if (hSem) //信标对象创建成功。  
	{
		//信标对象已经存在,则程序已有一个实例在运行。  
		if (ERROR_ALREADY_EXISTS == GetLastError())
		{
			CloseHandle(hSem); //关闭信号量句柄。  
							   //获取桌面窗口的一个子窗口。  
			HWND hWndPrev = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
			while (::IsWindow(hWndPrev))
			{
				//判断窗口是否有我们预先设置的标记,如有,则是我们寻找的窗口,并将它激活。  
				if (::GetProp(hWndPrev, "DDZ"))
				{
					//如果主窗口已最小化,则恢复其大小。  
					if (::IsIconic(hWndPrev))
						::ShowWindow(hWndPrev, SW_RESTORE);
					//将应用程序的主窗口激活。  
					::SetForegroundWindow(hWndPrev);
					return FALSE; //退出实例。  
				}
				//继续寻找下一个窗口。  
				hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);
			}
			AfxMessageBox("已有一个实例在运行,但找不到它的主窗口!");
		}
	}
	else
	{
		AfxMessageBox("创建信标对象失败,程序退出!");
		return FALSE;
	}


	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControlsEx()。  否则,将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	// 初始化 OLE 库
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();

	EnableTaskbarInteraction(FALSE);

	// 使用 RichEdit 控件需要 AfxInitRichEdit2()	
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)


	// 注册应用程序的文档模板。  文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CDDZDoc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CDDZView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);


	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);



	// 调度在命令行中指定的命令。  如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();


	return TRUE;
}

2.在程序结束时删除标记

void CMainFrame::OnDestroy()
{
	CFrameWnd::OnDestroy();
	// TODO: 在此处添加消息处理程序代码
	::RemoveProp(m_hWnd, "DDZ");//删除所设置的标记。  
	
}

二. 对话框程序

在CXXXDlg.h中添加互斥变量

	HANDLE m_hMutex;			//一个实例的互斥变量;

在 CXXXDlg.cpp的OnCreate中添加如下代码 

int CXXXDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialogEx::OnCreate(lpCreateStruct) == -1)
		return -1;
	//程序只运行一个;
	this->m_hMutex = ::CreateMutexW(NULL,FALSE,AfxGetApp()->m_pszExeName);
	if(::GetLastError()==ERROR_ALREADY_EXISTS)
	{
		// 寻找先前实例的主窗口
		HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
		while (::IsWindow(hWndPrevious))
		{
			if (::GetProp(hWndPrevious, AfxGetApp()->m_pszExeName))
			{
				if (::IsIconic(hWndPrevious))
					::ShowWindow(hWndPrevious, SW_RESTORE);
				::SetForegroundWindow(hWndPrevious);
				::SetForegroundWindow(::GetLastActivePopup(hWndPrevious));
				return -1;
			}
			hWndPrevious = ::GetWindow(hWndPrevious, GW_HWNDNEXT);
		}
		return -1;
	}

	::SetProp(m_hWnd, AfxGetApp()->m_pszExeName , (HANDLE)1);

	return 0;
}

最后程序结束时清除申请的资源

void CXXXDlg::OnDestroy()
{
	CDialogEx::OnDestroy();
	::CloseHandle(this->m_hMutex);
	::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName);
}

 

posted on 2016-06-17 16:51  July7th  阅读(511)  评论(0编辑  收藏  举报