You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
7.8 KiB
316 lines
7.8 KiB
//========= 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 |
|
}
|
|
|