mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
316
engine/cl_check_process.cpp
Normal file
316
engine/cl_check_process.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
//========= 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
|
||||
}
|
||||
Reference in New Issue
Block a user