Environment: Windows NT, Windows 2000
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/////////////////////////////////////////////////////////////////
// OtherInstanceOtherInstance::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
// [email protected]
// 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 processstrcpy(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 MEhInstLib = 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