Created
May 30, 2017 13:25
-
-
Save matcap/dbcce28b4c321eb89a273473dca36cce to your computer and use it in GitHub Desktop.
A simple process killer for Windows.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <string> | |
#include <iostream> | |
#include <set> | |
#include <chrono> | |
#include <iomanip> | |
#include <map> | |
#include <Windows.h> | |
#include <TlHelp32.h> | |
using namespace std; | |
void abort(const string& msg); | |
typedef map<wstring, vector<unsigned int>> ProcessScan; // Match process name with the PIDs of its multple instances | |
class KillerDaemon { | |
set<wstring> procs_to_kill; // Names of the processes to kill | |
unsigned int scan_interval; // Seconds of sleep between each process scan | |
public: | |
KillerDaemon(int argc, char** argv); | |
void kill_targets(const ProcessScan &scan); | |
void wait(); | |
static ProcessScan scan_processes(); | |
static void print_help(); | |
}; | |
int main(int argc, char** argv) { | |
KillerDaemon kd(argc, argv); | |
do { | |
kd.wait(); | |
auto proc_list = KillerDaemon::scan_processes(); | |
kd.kill_targets(proc_list); | |
} while (true); | |
return 0; | |
} | |
void abort(const std::string& msg) { | |
std::cerr << "ERROR: " << msg << std::endl; | |
std::exit(1); | |
} | |
KillerDaemon::KillerDaemon(int argc, char** argv) : scan_interval(10) { | |
if (argc <= 1) { | |
abort("Not enough arguments"); | |
} | |
for (int i = 0; i < argc; i++) { | |
string arg(argv[i]); | |
// Help | |
if (arg == "-h") { | |
KillerDaemon::print_help(); | |
exit(0); | |
} | |
// Interval set | |
else if (arg == "-i") { | |
if (++i < argc) { | |
string seconds = argv[i]; | |
scan_interval = strtoul(&seconds[0], nullptr, 10); | |
if (!scan_interval) { | |
abort("Invalid interval argument."); | |
} | |
} | |
else { | |
abort("Interval argument missing."); | |
} | |
} | |
// Process name | |
else if (arg[0] != '-') { | |
procs_to_kill.insert(wstring(arg.cbegin(), arg.cend())); | |
} | |
// Invalid arg | |
else { | |
abort("Invalid process name '" + arg + "'."); | |
} | |
} | |
} | |
void KillerDaemon::wait() { | |
Sleep(scan_interval * 1000); | |
} | |
void KillerDaemon::kill_targets(const ProcessScan &scan) { | |
for (auto proc_name : procs_to_kill) { | |
// Proceed only if the process is currently running | |
if (!scan.count(proc_name)) { | |
continue; | |
} | |
time_t t = chrono::system_clock::to_time_t(chrono::system_clock::now()); | |
tm* time = localtime(&t); | |
// Try to kill every running instance of that program | |
for (auto pid : scan.at(proc_name)) { | |
cout << put_time(time, "%F %T") << " - "; | |
HANDLE p = OpenProcess(PROCESS_TERMINATE, false, pid); | |
if (p == INVALID_HANDLE_VALUE) { | |
cout << "Cannot open process handle for [" << pid << "] "; | |
wcout << proc_name; | |
cout << endl; | |
break; | |
} | |
if (!TerminateProcess(p, 0)) { | |
cout << "Killing failed for [" << pid << "] "; | |
wcout << proc_name; | |
cout << endl; | |
} | |
else { | |
cout << "Successfully killed [" << pid << "] "; | |
wcout << proc_name; | |
cout << endl; | |
} | |
CloseHandle(p); | |
} | |
} | |
} | |
ProcessScan KillerDaemon::scan_processes() { | |
HANDLE procs_snap; | |
ProcessScan procs; | |
PROCESSENTRY32 proc_entry; | |
proc_entry.dwSize = sizeof(PROCESSENTRY32); | |
procs_snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); | |
if (procs_snap == INVALID_HANDLE_VALUE) { | |
abort("Could not create process snapshot."); | |
} | |
if (!Process32First(procs_snap, &proc_entry)) { | |
CloseHandle(procs_snap); | |
abort("Could not retrieve process info"); | |
} | |
// Walk through scan | |
while (Process32Next(procs_snap, &proc_entry)) { | |
// Append process PID to its map entry | |
procs[wstring(proc_entry.szExeFile)].push_back(proc_entry.th32ProcessID); | |
} | |
CloseHandle(procs_snap); | |
return procs; | |
} | |
void KillerDaemon::print_help() { | |
cout << "KillerDaemon." << endl << endl | |
<< "Usage:" << endl | |
<< " KillerDaemon <process_name>..." << endl | |
<< " KillerDaemon -i <interval> <process_name>..." << endl | |
<< " KillerDaemon -h" << endl << endl | |
<< "Options:" << endl | |
<< " -h Shows this help" << endl | |
<< " -i <interval> Seconds between each scan (default=10)" << endl; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment