mfc之使两次点开可执行文件为同一个应用程序

15 篇文章 1 订阅

1.准备工作添加一个CFAWinAppEx.h和CFAWinAppEx.cpp文件

CFAWinAppEx.h文件 继承CWinAppEX

#ifndef __WINAPP_H__
#define __WINAPP_H__
#pragma once

#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif

// Auxiliary AFX functions
/*
#if (_MFC_VER < 0x0700) // 0x0421, 0x0600, 0x0700
	#include <..\src\afximpl.h>
#else
	#include <..\src\mfc\afximpl.h>	
#endif
*/

// CFAWinAppEx

class CFAWinAppEx : public CWinAppEx
{
	DECLARE_DYNCREATE( CFAWinAppEx )

protected:
	CFAWinAppEx( LPCTSTR lpszAppName = NULL );
	virtual ~CFAWinAppEx( void );
	
public:	
	BOOL PostInstanceMessage( WPARAM wParam, LPARAM lParam );		
	BOOL EnableTokenPrivilege( LPCTSTR lpszSystemName, BOOL bEnable = TRUE );
	
public:
	AFX_INLINE void RegisterShellFileTypes( BOOL bCompat = FALSE );
	AFX_INLINE void UnregisterShellFileTypes( void );

public:
	virtual BOOL PreTranslateMessage( LPMSG pMsg );
	virtual BOOL OnAnotherInstanceMessage( LPMSG pMsg) ;

protected:
	BOOL FindAnotherInstance( LPCTSTR lpszUID );
	void RegisterShellFileTypesEx( BOOL bCompat = FALSE, BOOL bRegister = TRUE );
	virtual void DealCmdLine(){}
protected:
	DECLARE_MESSAGE_MAP()

protected:	
	UINT	m_uMsgCheckInst;
	
};

AFX_INLINE CFAWinAppEx* GetApp( void )
	{ return STATIC_DOWNCAST( CFAWinAppEx, AfxGetApp() ); }

AFX_INLINE void CFAWinAppEx::RegisterShellFileTypes( BOOL bCompat /*FALSE*/ )
	{ RegisterShellFileTypesEx( bCompat, TRUE ); }

AFX_INLINE void CFAWinAppEx::UnregisterShellFileTypes( void) 
	{ RegisterShellFileTypesEx( FALSE, FALSE ); }

#endif // __WINAPP_H__

CFAWinAppEx.cpp文件


#include "stdafx.h"
#include "FAWinAppEx.h"
#include <atlbase.h>	// Required for the CRegKey

// CFAWinAppEx
 
IMPLEMENT_DYNCREATE( CFAWinAppEx, CWinAppEx)
CFAWinAppEx::CFAWinAppEx( LPCTSTR lpszAppName /*NULL*/ )
{	
	m_uMsgCheckInst = NULL;
}

CFAWinAppEx::~CFAWinAppEx( void )
{	
	m_uMsgCheckInst = NULL;	
}

BEGIN_MESSAGE_MAP(CFAWinAppEx, CWinApp)	
END_MESSAGE_MAP()

// CFAWinAppEx message handlers

BOOL CFAWinAppEx::PreTranslateMessage( LPMSG pMsg )
{
	if( pMsg->message == m_uMsgCheckInst )
		return OnAnotherInstanceMessage( pMsg );	
	
	return CWinApp::PreTranslateMessage( pMsg );	
}

// CFAWinAppEx functions

BOOL CFAWinAppEx::FindAnotherInstance( LPCTSTR lpszUID )
{
	ASSERT( lpszUID != NULL );
		
	// Create a new mutex. If fails means that process already exists:

	HANDLE hMutex  = ::CreateMutex( NULL, FALSE, lpszUID );
	DWORD  dwError = ::GetLastError();	
	if( hMutex != NULL )
	{
		// Close mutex handle
		::ReleaseMutex( hMutex );
		hMutex = NULL;

		// Another instance of application is running:

		if( dwError == ERROR_ALREADY_EXISTS || dwError == ERROR_ACCESS_DENIED )			
			return TRUE;
	}

	return FALSE;
}

BOOL CFAWinAppEx::PostInstanceMessage( WPARAM wParam, LPARAM lParam )
{
	ASSERT( m_uMsgCheckInst != NULL );

	// One process can terminate the other process by broadcasting the private message 
	// using the BroadcastSystemMessage function as follows:
		
	DWORD dwReceipents = BSM_APPLICATIONS;

	if( this->EnableTokenPrivilege( SE_TCB_NAME ) )
		dwReceipents |= BSM_ALLDESKTOPS;
		
	// Send the message to all other instances.
	// If the function succeeds, the return value is a positive value.
	// If the function is unable to broadcast the message, the return value is ?.

	LONG lRet = ::BroadcastSystemMessage( BSF_IGNORECURRENTTASK | BSF_FORCEIFHUNG | 
					BSF_POSTMESSAGE, &dwReceipents, m_uMsgCheckInst, wParam, lParam );

	return (BOOL)( lRet != -1 );
}

BOOL CFAWinAppEx::OnAnotherInstanceMessage( LPMSG pMsg )
{
	// Get command line arguments (if any) from new instance.
	
	BOOL bShellOpen = FALSE;
	
	if( pMsg->wParam != NULL ) 
	{
		::GlobalGetAtomName( (ATOM)pMsg->wParam, m_lpCmdLine, _MAX_FNAME );			
		::GlobalDeleteAtom(  (ATOM)pMsg->wParam );		
		bShellOpen = TRUE;		
	}
	
	// If got valid command line then try to open the document -
	// CDocManager will popup main window itself. Otherwise, we
	// have to popup the window 'manually' :

   if( ::IsWindow( m_pMainWnd->GetSafeHwnd() ) )
	{
		// Does the main window have any popups ? If has, 
		// bring the main window or its popup to the top
		// before showing:

		CWnd* pPopupWnd = m_pMainWnd->GetLastActivePopup();
		pPopupWnd->BringWindowToTop();

		// If window is not visible then show it, else if
		// it is iconic, restore it:

		if( !m_pMainWnd->IsWindowVisible() )
			m_pMainWnd->ShowWindow( SW_SHOWNORMAL ); 
		else if( m_pMainWnd->IsIconic() )
			m_pMainWnd->ShowWindow( SW_RESTORE );
		
		// And finally, bring to top after showing again:

		pPopupWnd->BringWindowToTop();
		pPopupWnd->SetForegroundWindow(); 
		//
		DealCmdLine();
	}
	
	return TRUE;
}

BOOL CFAWinAppEx::EnableTokenPrivilege( LPCTSTR lpszSystemName, 
									  BOOL    bEnable /*TRUE*/ )
{
	ASSERT( lpszSystemName != NULL );
	BOOL bRetVal = FALSE;
	
	if( ::GetVersion() < 0x80000000 ) // NT40/2K/XP // afxData ???
	{
		HANDLE hToken = NULL;		
		if( ::OpenProcessToken( ::GetCurrentProcess(), 
			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
		{
			TOKEN_PRIVILEGES tp = { 0 };
			
			if( ::LookupPrivilegeValue( NULL, lpszSystemName, &tp.Privileges[0].Luid ) )
			{
				tp.PrivilegeCount = 1;
				tp.Privileges[0].Attributes = ( bEnable ? SE_PRIVILEGE_ENABLED : 0 );
								
				// To determine whether the function adjusted all of the 
				// specified privileges, call GetLastError:
				
				if( ::AdjustTokenPrivileges( hToken, FALSE, &tp, 
					 sizeof( TOKEN_PRIVILEGES ), (PTOKEN_PRIVILEGES)NULL, NULL ) )
				{				
					bRetVal = ( ::GetLastError() == ERROR_SUCCESS );
				}
			}
			::CloseHandle( hToken );
		}
	}

	return bRetVal;
}

void CFAWinAppEx::RegisterShellFileTypesEx( BOOL bCompat   /*FALSE*/, 
										  BOOL bRegister /*TRUE*/ )
{
	// Register all application document types:

	if( bRegister == TRUE )
		CWinApp::RegisterShellFileTypes( bCompat );
		
	// Now register SDI document dde open.
	// Loop through the document templates:

	POSITION pos = GetFirstDocTemplatePosition();
	while( pos != NULL )
	{		
		CString strFileTypeId( _T("") );
		CDocTemplate* pTemplate = GetNextDocTemplate( pos );

		if( pTemplate->GetDocString( strFileTypeId,
		    CDocTemplate::regFileTypeId ) && !strFileTypeId.IsEmpty() )
		{
			// CDocTemplate::windowTitle is present only in the document template 
			// for SDI applications. So, we detected SDI application and should 
			// overregister shell file types :
			
			CString strTemp( _T("") );
			if ( pTemplate->GetDocString( strTemp, CDocTemplate::windowTitle ) &&
				 !strTemp.IsEmpty() )
			{
				// path\shell\open\ddeexec = [open("%1")]
				strTemp.Format( _T( "%s\\shell\\open\\%s" ), (LPCTSTR)strFileTypeId, _T( "ddeexec" ) );
				
				#if ( _MFC_VER >= 0x0700 )
					CRegKey reg( HKEY_CLASSES_ROOT );
				#else
					CRegKey reg;
					reg.Attach( HKEY_CLASSES_ROOT );
				#endif

				if( bRegister )
				{				
					if( reg.SetKeyValue( strTemp, _T( "[open(\"%1\")]" ) ) == ERROR_SUCCESS )
					{
						strTemp += _T( "\\Application" );

						OSVERSIONINFO osvi = { 0 };
						osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
						::GetVersionEx( & osvi );

						if( !( osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
							   osvi.dwMajorVersion == 5 && 
							   osvi.dwMinorVersion >= 1 ) )
						{
							reg.SetKeyValue( strTemp, AfxGetAppName() );
						}
						else
							reg.DeleteSubKey( strTemp );
					}
				}
				else // Unregister 'ddeexec' registry entry:
					reg.RecurseDeleteKey( strTemp );
				
				#if ( _MFC_VER >= 0x0700 )
					reg.Flush();
				#else
					::RegFlushKey( reg );
				#endif
				reg.Close(); 
			}
		}
	}

	// Unregister all application document types:

	if( bRegister == FALSE )
		CWinApp::UnregisterShellFileTypes();
}

//


2.在工程名的.h里边加头文件并把基类设置为CFAWinAppEx

并添加virtual BOOL InitInstance( LPCTSTR lpszUID );重写InitInstance函数

3.在工程名的.cpp文件底部添加如下代码

BOOL 工程名App::InitInstance( LPCTSTR lpszUID )
	{		
		if( lpszUID != NULL )
		{
			ASSERT( m_uMsgCheckInst == NULL ); // Only once
			m_uMsgCheckInst = ::RegisterWindowMessage( lpszUID );
			ASSERT( m_uMsgCheckInst >= 0xC000 && m_uMsgCheckInst <= 0xFFFF );
			if( this->FindAnotherInstance( lpszUID ) )
			{
				WPARAM wpCmdLine = NULL;
				wpCmdLine = (ATOM)::GlobalAddAtom( GetCommandLine() );
				this->PostInstanceMessage( wpCmdLine, NULL );
				return FALSE;
			}
		}
		return CWinApp::InitInstance();
	}

4.修改InitInstance()里边的内容

CWinApp::InitInstance();改为

if( !InitInstance( L"{唯一标识的字符串}") )//例如InitInstance( L"{8CD4-4f87-8834-F83C72939E16}")
	{
		return FALSE;
	}


并去掉

	CShellManager *pShellManager = new CShellManager;
	if (pShellManager != NULL)
	{
		delete pShellManager;
	}



















  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值