Stopping the Second Instance of Your Application

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:

  1. #include "OtherInstance.h" in your main module
  2. In your InitInstance() of your application, include:
  3.   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;
    
    }
    
  4. Compile—Run—Hopefully your application still runs....
  5. Run a second instance of your application. That should pop up a message; when you click on the OK button, it should terminate.

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

Downloads

Download source - 4 Kb


Comments

  • Re: The same job in 6 lines

    Posted by bigbang on 09/10/2006 08:52am

    pwned!

    Reply
  • Request for MFC code to enumerate Processes

    Posted by Legacy on 03/10/2003 12:00am

    Originally posted by: deepthi

    Respected Sir,
    As 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.

    Reply
  • The same job in 6 lines

    Posted by Legacy on 12/15/2002 12:00am

    Originally 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.

    Reply
  • What about XP and Multi User a the same time

    Posted by Legacy on 08/30/2002 12:00am

    Originally posted by: Roland Hasen�hrl

    HANDLE g_hAppRunningEvent = INVALID_HANDLE_VALUE;
    
    TCHAR szEventName;

    if(IsWindowNT40())
    lstrcpy(szEventName,TEXT("GlobalSingleInstApp_"));
    else
    lstrcpy(szEventName,TEXT("Global\\SingleInstApp_"));

    _tcscat(szEventName,TEXT(s_AppID));

    g_hAppRunningEvent = CreateEvent(NULL,FALSE,FALSE,
    szEventName);

    if(g_hAppRunningEvent != NULL)
    {
    if(GetLastError() == ERROR_ALREADY_EXISTS)
    {
    CloseHandle(g_hAppRunningEvent);
    g_hAppRunningEvent = NULL;
    //Application is not running
    }
    }

    Reply
  • can work

    Posted by Legacy on 08/29/2002 12:00am

    Originally posted by: Mitwa

    This also works well. This is not a bullet proof solution but does work. Add these lines to the InitInstance of yur application. 
    
    

    ::CreateSemaphore(NULL, 1, 1, app.m_pszAppName);
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
    AfxMessageBox("You cannot run more than one Instance!");
    return FALSE;
    }

    Reply
  • KHAK TOO SARET

    Posted by Legacy on 08/28/2002 12:00am

    Originally posted by: upset

    AHMAG E BISHOOR...IN CHIE????
    KHAK TOO SARET

    Reply
  • Yet another method...

    Posted by Legacy on 08/27/2002 12:00am

    Originally 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.

    Reply
  • Yeah, what's wrong with CreateMutex() really ?

    Posted by Legacy on 08/27/2002 12:00am

    Originally posted by: Just curious

    It cant get any simplier than that

    Reply
  • CreateMutex()

    Posted by Legacy on 08/26/2002 12:00am

    Originally posted by: Vinoj Kumar

    The CreateMutex() API does a better job than this.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • Best-in-Class organizations execute on a strategy that supports the multi-channel nature of customer requests. These leading organizations do not just open up their service infrastructures to accommodate new channels, but also empower their teams to deliver an effective and consistent experience regardless of the channel selected by the customer. This document will highlight the key business capabilities that support a Best-in-Class customer engagement strategy.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds