Click here to Skip to main content
13,299,298 members (63,642 online)
Click here to Skip to main content
Add your own
alternative version


24 bookmarked
Posted 28 Feb 2010

Running multiple instances of Task Manager

, 28 Feb 2010
Rate this:
Please Sign up or sign in to vote.
A simple application that allows the user to run more then one instance of the Task Manager.


As we all know, Task Manager, whatever the reasons are, does not allow the user to run multiple instances. This article explains a simple application that allows the user to start as many instances of the Task Manager as he/she wishes to. The technique described here is only valid for Windows 7 (and maybe Vista); XP's Task Manager uses a different technique.


To do so, it employs simple tactics. When it begins execution, it tries to create a named kernel object (in this case, a mutex), and if there is already an object with the name Task Manager, it assumes that another instance of it is already active and it closes the current process.

The nme of the offending mutex is TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0.

Here's an example of how it can be done:

if( ::CreateMutex( NULL, FALSE, 
  TEXT( "TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0" ) ) == NULL )
  if( ::GetLastError() == ERROR_ALREADY_EXISTS )
    // task manager is already running - close current process

// active task manage wasn't detected - continue


But first, we must find out the full name of the mutex, which is in a format like this: \Sessions\<SESSION_ID>\BaseNamedObjects\TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0, and we can obtain the session ID using the ProcessIdToSessionId API call.

DWORD sid;
if( !::ProcessIdToSessionId( ::GetCurrentProcessId(), &sid ) )
  wprintf( L"Unable to get session ID. Error code: %d\n", ::GetLastError() );
  return 2;

WCHAR mutexName[ MAX_PATH ];
mutexName[ 0 ] = 0;

// full name of the mutex (we want to mess only with session of the current user)
wcscat( mutexName, L"\\Sessions\\" );
_itow( sid, mutexName + wcslen( mutexName ), 10 );
wcscat( mutexName, L"\\BaseNamedObjects\\" );
wcscat( mutexName, MUTEX_NAME );

The basic idea is to destroy the mutex object before we start another instance of the Task Manager. To destroy it, we need to find all the handles to the object and close them. In the process, we need to use these undocumented API calls: NtQuerySystemInformation, NtQueryObject, and DuplicateHandle.

We use NtQuerySystemInformation to get the list of all open handles in the system, and then we iterate through the list, duplicating handles, to gain access to the object, and call NtQueryObject to get the name of the object. When we find the handle, we make a duplicate using the DuplicateHandle API call, but this time, we pass the DUPLICATE_CLOSE_SOURCE flag that instructs the system to close the original handle after the copy is made (effectively taking the ownership of the object), and immediately after that, we also close the new handle, and the end result is destroying the object.

// Searches for handle to an object with specified name 
// Returns -1 if it cannot obtain list of handles, 
// 0 if there's no handles to the object or 
// 1 if the object if found and handle is closed
INT SeekAndDestory(WCHAR* handleName)
  INT found = 0;

  // get list of opened handles
  DWORD size = 0;
  if( !NT_SUCCESS( ::pNtQuerySystemInformation(
    (SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handles,
    sizeof( SYSTEM_HANDLE_INFORMATION ), &size ) ) )
    free( handles );

    if( size == 0 )
      return -1;

    DWORD newSize = size + sizeof(HANDLE) * 512;
    handles = (PSYSTEM_HANDLE_INFORMATION)malloc( newSize );
    if( !NT_SUCCESS( ::pNtQuerySystemInformation( 
      (SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handles,
      newSize, &size ) ) )
      free( handles );
      return -1;

  for( DWORD i = 0; i < handles->dwCount; i++ )
    HANDLE process = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, 
      handles->Handles[ i ].dwProcessId );
    if( process )
      HANDLE myHandle;

      if( ::DuplicateHandle( process, 
        (HANDLE)handles->Handles[ i ].wValue, ::GetCurrentProcess(),
        &myHandle, DUPLICATE_SAME_ACCESS, FALSE, 0 ) )
        // get object name
        if( !NT_SUCCESS( pNtQueryObject( myHandle, ObjectNameInformation,
          nameInfo, sizeof( PUBLIC_OBJECT_TYPE_INFORMATION ), &size ) ) )
          free( nameInfo );

          if( (int)size <= 0 )
            ::CloseHandle( myHandle );

          DWORD newSize = size;
          nameInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)malloc( newSize );
          if( !NT_SUCCESS( pNtQueryObject( myHandle, ObjectNameInformation,
            nameInfo, newSize, &size ) ) )
            ::CloseHandle( myHandle );

        ::CloseHandle( myHandle );

        if( lstrcmp( handleName, nameInfo->TypeName.Buffer ) == 0 )
          // take ownership of the handle
          // (copy handle and close original and then close the copy)
          if( ::DuplicateHandle( process, 
            (HANDLE)handles->Handles[ i ].wValue, ::GetCurrentProcess(),
            &myHandle, 0, FALSE,
            ::CloseHandle( myHandle );
            found = 1;

        free( nameInfo );

      ::CloseHandle( process );

  free( handles );
  return found;

Note: To get access to NtQuerySystemInformation and NtQueryObject, we need to use GetProcAddress because they are not available to the linker during the building process. The NtLib.h file contains the definitions required for using the undocumented API.

pfnNtQuerySystemInformation pNtQuerySystemInformation = NULL;
pfnNtQueryObject pNtQueryObject = NULL;

BOOL LoadNtLib()
  pNtQuerySystemInformation = (pfnNtQuerySystemInformation)::GetProcAddress(
    GetModuleHandle( TEXT( "ntdll" ) ), "NtQuerySystemInformation" );
  pNtQueryObject = (pfnNtQueryObject)::GetProcAddress(
    GetModuleHandle( TEXT( "ntdll" ) ), "NtQueryObject" );

  return pNtQuerySystemInformation && pNtQueryObject;

Some more information about NtQuerySystemInformation can be found in Naveen's article: Listing Used Files.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Mladen Janković
Software Developer
Serbia Serbia
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionKind Request from C++ to VBNET Pin
Miklo B22-Sep-15 10:04
memberMiklo B22-Sep-15 10:04 
QuestionWindows 8 Pin
Member 1013314630-Jun-13 0:36
memberMember 1013314630-Jun-13 0:36 
AnswerRe: Windows 8 Pin
Mladen Janković1-Jul-13 8:44
memberMladen Janković1-Jul-13 8:44 
GeneralRe: Windows 8 Pin
boobssMan13-Mar-14 8:06
memberboobssMan13-Mar-14 8:06 
AnswerRe: Windows 8.1 Pro 32. Pin
Member 476859324-Jan-14 20:54
memberMember 476859324-Jan-14 20:54 
QuestionIt doesn't actually work, at least not in Win7x64 Pin
Member 100981997-Jun-13 6:40
memberMember 100981997-Jun-13 6:40 
AnswerRe: It doesn't actually work, at least not in Win7x64 Pin
Mladen Janković7-Jun-13 10:04
memberMladen Janković7-Jun-13 10:04 
GeneralExcellent! Pin
SouzaRM4-Nov-12 17:54
memberSouzaRM4-Nov-12 17:54 
GeneralCool stuff. Pin
Fredrik Bornander9-Mar-10 6:23
memberFredrik Bornander9-Mar-10 6:23 
GeneralSysinternals process explorer Pin
owillebo2-Mar-10 2:48
memberowillebo2-Mar-10 2:48 
GeneralRe: Sysinternals process explorer Pin
Mladen Jankovic2-Mar-10 3:51
memberMladen Jankovic2-Mar-10 3:51 
GeneralGJ Pin
Predrag Tomasevic1-Mar-10 5:55
memberPredrag Tomasevic1-Mar-10 5:55 
GeneralRe: GJ Pin
Mladen Jankovic1-Mar-10 7:26
memberMladen Jankovic1-Mar-10 7:26 
General5 bre! Pin
Nemanja Trifunovic1-Mar-10 5:46
memberNemanja Trifunovic1-Mar-10 5:46 
GeneralRe: 5 bre! Pin
Mladen Jankovic1-Mar-10 7:25
memberMladen Jankovic1-Mar-10 7:25 
QuestionInteresting though this is, I don't quite see what the point is - can someone tell me what I'm missing? Pin
Mike Diack1-Mar-10 1:14
memberMike Diack1-Mar-10 1:14 
AnswerRe: Interesting though this is, I don't quite see what the point is - can someone tell me what I'm missing? Pin
Mladen Jankovic1-Mar-10 3:42
memberMladen Jankovic1-Mar-10 3:42 
GeneralWell Done! Pin
Richard Andrew x6428-Feb-10 10:50
memberRichard Andrew x6428-Feb-10 10:50 
GeneralRe: Well Done! Pin
Mladen Jankovic1-Mar-10 3:43
memberMladen Jankovic1-Mar-10 3:43 
GeneralMy vote of 5 Pin
Nishant Sivakumar28-Feb-10 8:35
mvpNishant Sivakumar28-Feb-10 8:35 
GeneralRe: My vote of 5 Pin
Mladen Jankovic28-Feb-10 9:24
memberMladen Jankovic28-Feb-10 9:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171207.1 | Last Updated 28 Feb 2010
Article Copyright 2010 by Mladen Janković
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid