|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Windows Only, does a check against all other processes to see how many other instances
// of this process is running concurrently
//
//=============================================================================//
//*********************************************************************************************
// Process Check
#include "cl_check_process.h"
#include "dbg.h"
#ifdef IS_WINDOWS_PC
#include <Windows.h>
#include <winternl.h>
#include <stdio.h>
#include <TlHelp32.h>
#include "strtools.h"
#include <Psapi.h>
#endif // IS_WINDOWS_PC
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef IS_WINDOWS_PC
#define HANDLE_QUERY_BUFFER_BLOCK_SIZE ( 1 * 1024 * 1024 )
#define SystemHandleInformation ( (SYSTEM_INFORMATION_CLASS)16 )
#define STATUS_INFO_LENGTH_MISMATCH ( (NTSTATUS)( 0xC0000004L ) )
typedef NTSTATUS (__stdcall *NtQuerySystemInformation1) ( IN ULONG SysInfoClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG RetLen );
typedef struct _HANDLE_INFORMATION { DWORD ProcessId; BYTE ObjectType; BYTE Flags; USHORT Handle; PVOID KernelObject; ACCESS_MASK GrantedAccess;
} HANDLE_INFORMATION, *PHANDLE_INFORMATION;
typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG HandleCount; HANDLE_INFORMATION HandleInfoArray[ 1 ];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
//
// Checks Process Count with CreateToolhelp32Snapshot
//
int CheckOtherInstancesRunningWithSnapShot( const char *thisProcessNameShort ) { DWORD nLength; char otherProcessNameShort[ MAX_PATH ];
nLength = MAX_PATH;
int iSnapShotCount = 0;
//
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hSnapshot ) { PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if ( Process32First( hSnapshot, &pe32 ) ) { do { V_FileBase( pe32.szExeFile, otherProcessNameShort, MAX_PATH ); if ( V_strcmp( thisProcessNameShort, otherProcessNameShort ) == 0 ) { // DevMsg( "CreateToolhelp32Snapshot - Process Name [ %s ] - OtherName [ %s ] \n", thisProcessNameShort, pe32.szExeFile );
// We found an instance of this executable.
iSnapShotCount++; } } while( Process32Next( hSnapshot, &pe32 ) ); } CloseHandle(hSnapshot); }
return iSnapShotCount; }
//
// Checks Process Count with QueryFullProcessImageName and OpenProcess
//
int CheckOtherInstancesWithEnumProcess( const char *thisProcessNameShort ) { NTSTATUS status; BOOL bStatus; DWORD nLength; DWORD nBufferSize; DWORD nLastProcess; DWORD i; HANDLE process; PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL; char otherProcessName[ MAX_PATH ]; char otherProcessNameShort[ MAX_PATH ]; HINSTANCE hInst = NULL;
// Start with a count of zero, since we will find ourselves too.
int iProcessCount = 0; // Get the path to the executable for this process.
nLength = MAX_PATH;
// Query all of the handles in the system. We have to do this in a loop, since we do
// not know how large of a buffer we need.
nBufferSize = 0; // Load ntdll.dll so we can Query the system
/* load the ntdll.dll */ NtQuerySystemInformation1 NtQuerySystemInformation;
//PVOID Info;
HMODULE hModule = LoadLibrary( "ntdll.dll" ); if (!hModule) { iProcessCount = CHECK_PROCESS_UNSUPPORTED; goto Cleanup; }
while ( TRUE ) { // Increase the buffer size and try the query.
if ( pHandleInfo != NULL ) { free( pHandleInfo ); } nBufferSize += HANDLE_QUERY_BUFFER_BLOCK_SIZE; pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc( nBufferSize ); if ( pHandleInfo == NULL ) { iProcessCount = CHECK_PROCESS_UNSUPPORTED; goto Cleanup; }
// Query the handles in the system.
NtQuerySystemInformation = (NtQuerySystemInformation1)GetProcAddress(hModule, "NtQuerySystemInformation"); if ( NtQuerySystemInformation == NULL ) { iProcessCount = CHECK_PROCESS_UNSUPPORTED; goto Cleanup; } status = NtQuerySystemInformation( SystemHandleInformation, pHandleInfo, nBufferSize, NULL ); // If our buffer was too small, try again.
if ( status == STATUS_INFO_LENGTH_MISMATCH ) { continue; } // If the query failed, return the error.
if ( !NT_SUCCESS( status ) ) { iProcessCount = CHECK_PROCESS_UNSUPPORTED; goto Cleanup; } break; } //
// Walk all of the entries looking for process IDs we have not processed yet.
// Note that this code assumes that handles will be grouped by process, which is
// what Windows does. If that assumption ever turns out to be false, this code
// will have to be altered to keep a list of process IDs already seen.
//
// Check for the presence of GetModuleFileNameEx
hInst = LoadLibrary( "Psapi.dll" ); if ( !hInst ) return CHECK_PROCESS_UNSUPPORTED;
typedef DWORD (WINAPI *GetProcessImageFileNameFn)(HANDLE, LPTSTR, DWORD); GetProcessImageFileNameFn fn = (GetProcessImageFileNameFn)GetProcAddress( hInst, #ifdef UNICODE
"GetProcessImageFileNameW"); #else
"GetProcessImageFileNameA"); #endif
if ( !fn ) return CHECK_PROCESS_UNSUPPORTED;
nLastProcess = 0; for ( i = 0; i < pHandleInfo->HandleCount; i++ ) { if ( pHandleInfo->HandleInfoArray[ i ].ProcessId != nLastProcess ) { //nLastProcess = pHandleInfo->HandleInfoArray[ i ].ProcessId;
nLastProcess = pHandleInfo->HandleInfoArray[ i ].ProcessId; //
// Try to open a handle to this process. Note that we may not have
// access to all processes, so we ignore errors.
//
process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, nLastProcess ); if ( process != NULL ) { // Query the name of the executable for the process we opened. If the query
// fails, we ignore this process.
nLength = MAX_PATH; bStatus = fn( process, otherProcessName, nLength ); if ( bStatus ) { //
// We have the process name. See if it is the same name as our process.
//
V_FileBase( otherProcessName, otherProcessNameShort, MAX_PATH ); if ( V_strcmp( thisProcessNameShort, otherProcessNameShort ) == 0 ) { // We found an instance of this executable.
// DevMsg( "EnumProcess - Process Name [ %s ] - OtherName [ %s ] \n", thisProcessNameShort, otherProcessName );
iProcessCount++; } } CloseHandle( process ); } } } Cleanup:
// Free allocated resources.
if ( pHandleInfo != NULL ) { free( pHandleInfo ); }
if ( hInst != NULL ) { FreeLibrary( hInst ); }
if ( hModule != NULL ) { FreeLibrary( hModule ); }
return iProcessCount; } #endif // IS_WINDOWS_PC
int CheckOtherInstancesRunning( void ) { #ifdef IS_WINDOWS_PC
BOOL bStatus = 0; DWORD nLength = MAX_PATH; char thisProcessName[ MAX_PATH ]; char thisProcessNameShort[ MAX_PATH ];
// Load the pspapi to get our current process' name
HINSTANCE hInst = LoadLibrary( "Psapi.dll" ); if ( hInst ) { typedef DWORD (WINAPI *GetProcessImageFileNameFn)(HANDLE, LPTSTR, DWORD); GetProcessImageFileNameFn fn = (GetProcessImageFileNameFn)GetProcAddress( hInst, #ifdef UNICODE
"GetProcessImageFileNameW"); #else
"GetProcessImageFileNameA"); #endif
if ( fn ) { bStatus = fn( GetCurrentProcess(), thisProcessName, nLength ); }
FreeLibrary( hInst ); }
if ( !bStatus ) { return CHECK_PROCESS_UNSUPPORTED; }
V_FileBase( thisProcessName, thisProcessNameShort, MAX_PATH );
// Msg( "Checking Other Instances Running : ProcessShortName [ %s - %s ] \n", thisProcessName, thisProcessNameShort );
int iSnapShotCount = CheckOtherInstancesRunningWithSnapShot( thisProcessNameShort ); if ( iSnapShotCount > 1 ) { return iSnapShotCount; }
int iEnumCount = CheckOtherInstancesWithEnumProcess( thisProcessNameShort ); return iEnumCount > iSnapShotCount ? iEnumCount : iSnapShotCount; #endif // IS_WINDOWS_PC
return CHECK_PROCESS_UNSUPPORTED; // -1 UNSUPPORTED
}
|