Skip to content

Instantly share code, notes, and snippets.

@matcap
Created May 30, 2017 13:25
Show Gist options
  • Save matcap/dbcce28b4c321eb89a273473dca36cce to your computer and use it in GitHub Desktop.
Save matcap/dbcce28b4c321eb89a273473dca36cce to your computer and use it in GitHub Desktop.
A simple process killer for Windows.
#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