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;
}