Stopping the Second Instance of Your Application
Posted
by Saeed Saeed
on August 26th, 2002
If you ever need to have only one instance of an application active, you might be interested in using this class. This class enables you to stop running a second instance of an application.
The main credit goes to Mr. Kochhars. I modified his code to cater to this functionality and used it as the main method in a class fulfilling my need. The main method needs more work to be cleaned up; however, as it is now, it is quite capable of getting the job done without introducing any major flaws.
The class has three major methods:
| Method | Description |
| CString get_processname() | Tells you what your application name is |
| FindProcess(get_processname() ) | Tells you if your application is already running |
| IsThereAnyOtherInstance | Returns you with a boolean depending on what FindProcess detects |
The way you should use it is simple. Just follow these steps:
- #include "OtherInstance.h" in your main module
- In your InitInstance() of your application, include:
- Compile—Run—Hopefully your application still runs....
- Run a second instance of your application. That should pop up a message; when you click on the OK button, it should terminate.
OtherInstance *c=new OtherInstance();
if(c)
{
if(c->IsThereAnyOtherInstance())
{
CString x;
x= c->get_processname()+ " will NOT run because there is
another instance running ";
AfxMessageBox(x);
delete c;
PostQuitMessage(0);
}
delete c;
}
The Class Header File
#if !defined(AFX_OTHERINSTANCE_H__66456775_42AC_45CE_BCB6_
7D75E94A1A7D__INCLUDED_)
#define AFX_OTHERINSTANCE_H__66456775_42AC_45CE_BCB6_
7D75E94A1A7D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// OtherInstance.h : header file
//
/////////////////////////////////////////////////////////////////
// OtherInstance window
class OtherInstance : public CWnd
{
// Construction
public:
OtherInstance();
int FindProcess(const char *szToTerminate);
CString get_processname();
bool IsThereAnyOtherInstance();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(OtherInstance)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~OtherInstance();
// Generated message map functions
protected:
//{{AFX_MSG(OtherInstance)
// NOTE - the ClassWizard will add and remove member
// functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations
// immediately before the previous line.
#endif // !defined(AFX_OTHERINSTANCE_H__66456775_42AC_45CE_BCB6_
7D75E94A1A7D__INCLUDED_)
The Class Source File
// OtherInstance.cpp : implementation file // #include "stdafx.h" #include "OtherInstance.h" #include <windows.h> #include <tlhelp32.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////// // OtherInstance OtherInstance::OtherInstance() { } OtherInstance::~OtherInstance() { } //--------------------------------------------------------------- int OtherInstance::FindProcess(const char *szToTerminate) // Created: 6/23/2000 (RK) // Last modified: 03/30/2001 (RK) // Last modified: 20/08/2002 (Saeed) // Please report any problems or bugs to // kochhar@physiology.wisc.edu // The latest version of this routine can be found at: // http://www.neurophys.wisc.edu/ravi/software/killproc/ // Terminate the process "szToTerminate" if it is currently // running. // This works for Win/95/98/ME and also Win/NT/2000 // The process name is case-insensitive; in other words, // "notepad.exe" and "NOTEPAD.EXE" will both work // (for szToTerminate) // Return codes are as follows: // 1 = Process is running // 603 = Process is not currently running // 604 = No permission to terminate process // 605 = Unable to search for process // 602 = Unable to terminate process for some other reason // 606 = Unable to identify system type // 607 = Unsupported OS // 632 = Invalid process name { BOOL bResult,bResultm; DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0; DWORD iCbneeded,i,iFound=0; char szName[MAX_PATH],szToTermUpper[MAX_PATH]; HANDLE hProc,hSnapShot,hSnapShotm; OSVERSIONINFO osvi; HINSTANCE hInstLib; int iLen,iLenP,indx; HMODULE hMod; PROCESSENTRY32 procentry; MODULEENTRY32 modentry; int Cntr=0; // Transfer Process name into "szToTermUpper" and // convert it to upper case iLenP=strlen(szToTerminate); if(iLenP<1 || iLenP>MAX_PATH) return 632; for(indx=0;indx<iLenP;indx++) szToTermUpper[indx]=toupper(szToTerminate[indx]); szToTermUpper[iLenP]=0; // PSAPI Function Pointers. BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ); BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ); DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE, LPTSTR, DWORD ); // ToolHelp Function Pointers. HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ; BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ; BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ; // First, check what version of Windows we're in osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); bResult=GetVersionEx(&osvi); if(!bResult) // Unable to identify system version return 606; // At present, we only support Win/NT/2000 or Win/9x if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) && (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) return 607; if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT) { // Win/NT or 2000 // Load library and get the procedures explicitly. We do // this so that we don't have to worry about modules using // this code failing to load under Windows 9x, because // it can't resolve references to the PSAPI.DLL. hInstLib = LoadLibraryA("PSAPI.DLL"); if(hInstLib == NULL) return 605; // Get procedure addresses. lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*)) GetProcAddress( hInstLib, "EnumProcesses" ) ; lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( hInstLib, "EnumProcessModules" ) ; lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE, LPTSTR, DWORD )) GetProcAddress( hInstLib, "GetModuleBaseNameA" ) ; if( lpfEnumProcesses == NULL || lpfEnumProcessModules == NULL || lpfGetModuleBaseName == NULL) { FreeLibrary(hInstLib); return 605; } bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded); if(!bResult) { // Unable to get process list, EnumProcesses failed FreeLibrary(hInstLib); return 605; } // How many processes are there? iNumProc=iCbneeded/sizeof(DWORD); // Get and match the name of each process Cntr=0; for(i=0;i<iNumProc;i++) { // Get the (module) name for this process strcpy(szName,"Unknown"); // First, get a handle to the process hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS _VM_READ,FALSE, aiPID[i]); // Now, get the process name if(hProc) { if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod), &iCbneeded) ) { iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH); } } CloseHandle(hProc); // We will match regardless of lower- or uppercase if(strcmp(_strupr(szName),szToTermUpper)==0) { // Process found; now terminate it iFound=1; // First, open for termination hProc=OpenProcess(PROCESS_TERMINATE,FALSE,aiPID[i]); if(hProc) Cntr++; if(Cntr==2) { FreeLibrary(hInstLib); return 1; } } } return 0; } if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) { // Win/95 or 98 or ME hInstLib = LoadLibraryA("Kernel32.DLL"); if( hInstLib == NULL ) return FALSE ; // Get procedure addresses. // We are linking to these functions of Kernel32 // explicitly, because otherwise a module using // this code would fail to load under Windows NT, // which does not have the Toolhelp32 // functions in the Kernel 32. lpfCreateToolhelp32Snapshot= (HANDLE(WINAPI *)(DWORD,DWORD)) GetProcAddress( hInstLib, "CreateToolhelp32Snapshot" ) ; lpfProcess32First= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32First" ) ; lpfProcess32Next= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32Next" ) ; lpfModule32First= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32First" ) ; lpfModule32Next= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32Next" ) ; if( lpfProcess32Next == NULL || lpfProcess32First == NULL || lpfModule32Next == NULL || lpfModule32First == NULL || lpfCreateToolhelp32Snapshot == NULL ) { FreeLibrary(hInstLib); return 605; } // The Process32.. and Module32.. routines return names // in all uppercase // Get a handle to a Toolhelp snapshot of all the // systems processes. hSnapShot = lpfCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ; if( hSnapShot == INVALID_HANDLE_VALUE ) { FreeLibrary(hInstLib); return 605; } // Get the first process' information. procentry.dwSize = sizeof(PROCESSENTRY32); bResult=lpfProcess32First(hSnapShot,&procentry); // While there are processes, keep looping and checking. while(bResult) { // Get a handle to a Toolhelp snapshot of this process. hSnapShotm = lpfCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, procentry.th32ProcessID) ; if( hSnapShotm == INVALID_HANDLE_VALUE ) { FreeLibrary(hInstLib); return 605; } // Get the module list for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32First(hSnapShotm,&modentry); // While there are modules, keep looping and checking while(bResultm) { if(strcmp(modentry.szModule,szToTermUpper)==0) { // Process found; now terminate it Cntr++; if(Cntr==2) { FreeLibrary(hInstLib); iFound=1; return 1; } } else { // Look for next modules for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32Next(hSnapShotm,&modentry); } } //Keep looking procentry.dwSize = sizeof(PROCESSENTRY32); bResult = lpfProcess32Next(hSnapShot,&procentry); } } if(iFound==0) { FreeLibrary(hInstLib); return 603; } FreeLibrary(hInstLib); return 0; } //--------------------------------------------------------------- CString OtherInstance::get_processname() { char szPath[200]; char c; char s[255]; strcpy(szPath,""); GetModuleFileName (NULL,szPath,sizeof(szPath)); CString dum=(LPCTSTR)szPath; dum.MakeLower(); strcpy(s,dum); for(int i=strlen(s)-1;i>=0;i--) { c=s[i]; if(c=='\\') { dum=dum.Mid(i+1); break; } } return dum; } //--------------------------------------------------------------- bool OtherInstance::IsThereAnyOtherInstance() { CString x; int ret; ret=FindProcess(get_processname()); if(ret==1) return true; else return false; } //--------------------------------------------------------------- BEGIN_MESSAGE_MAP(OtherInstance, CWnd) //{{AFX_MSG_MAP(OtherInstance) // NOTE - the ClassWizard will add and remove mapping macros // here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////// // OtherInstance message handlers

Comments
Re: The same job in 6 lines
Posted by bigbang on 09/10/2006 08:52ampwned!
ReplyRequest for MFC code to enumerate Processes
Posted by Legacy on 03/10/2003 12:00amOriginally posted by: deepthi
Respected Sir,
ReplyAs a part of my project I have to enumerate the processes present in a system.I have done it using SDK(EnumProcesses()).Now I have to modify my program using MFC.Pls help.I need the steps or source code for that.
The same job in 6 lines
Posted by Legacy on 12/15/2002 12:00amOriginally posted by: Francis Leca
Just add this code in your app InitInstance()
HANDLE hEvent;
hEvent = CreateEvent(NULL, FALSE, TRUE, AfxGetAppName());
if ( GetLastError()==ERROR_ALREADY_EXISTS
{
AfxMessageBox("Already running");
return FALSE;
}
You can use CreateMutex() if you prefer.
ReplyWhat about XP and Multi User a the same time
Posted by Legacy on 08/30/2002 12:00amOriginally posted by: Roland Hasen�hrl
Replycan work
Posted by Legacy on 08/29/2002 12:00amOriginally posted by: Mitwa
ReplyKHAK TOO SARET
Posted by Legacy on 08/28/2002 12:00amOriginally posted by: upset
AHMAG E BISHOOR...IN CHIE????
KHAK TOO SARET
Reply
Yet another method...
Posted by Legacy on 08/27/2002 12:00amOriginally posted by: Mark
This also works where the application name doesn't get tainted with a filename. This is by no means bullet proof but does work. Add these lines to the InitInstance of yur application.
::CreateSemaphore(NULL, 1, 1, theApp.m_pszAppName);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Present a message or whatever.
AfxMessageBox("I already exist!");
// Halt this instance.
return FALSE;
}
A 'full' solution that takes a multi-user environment and other issues into consideration has been proposed by Joseph Newcomer - this is on another, nameless website.
ReplyYeah, what's wrong with CreateMutex() really ?
Posted by Legacy on 08/27/2002 12:00amOriginally posted by: Just curious
It cant get any simplier than that
Reply
CreateMutex()
Posted by Legacy on 08/26/2002 12:00amOriginally posted by: Vinoj Kumar
The CreateMutex() API does a better job than this.
Reply