#include #include #include #include using namespace std::string_literals; class Process { public: Process() = default; Process(const Process&) = delete; Process operator=(const Process&) = delete; virtual ~Process() {}; virtual HANDLE handle() const = 0; virtual void wait() const = 0; }; class AttachProcess : public Process { private: HANDLE h; public: explicit AttachProcess(DWORD pid) { h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (h == NULL) throw std::runtime_error("Failed to open process"); } ~AttachProcess() { CloseHandle(h); } HANDLE handle() const override { return h; } void wait() const override { WaitForSingleObject(h, INFINITE); } }; class ChildProcess : public Process { private: STARTUPINFOA si; PROCESS_INFORMATION pi; public: ChildProcess(const ChildProcess&) = delete; ChildProcess operator=(const ChildProcess&) = delete; explicit ChildProcess(LPCSTR applicationPath) { ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); if (!CreateProcessA(applicationPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { throw std::runtime_error("Failed to create child process!"); } } void start() { ResumeThread(pi.hThread); } void wait() const override { WaitForSingleObject(pi.hProcess, INFINITE); } HANDLE handle() const override { return pi.hProcess; } ~ChildProcess() { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } }; class JobObjectInformation { public: JobObjectInformation() = default; JobObjectInformation(const JobObjectInformation&) = delete; JobObjectInformation operator=(const JobObjectInformation&) = delete; virtual JOBOBJECTINFOCLASS getClass() const = 0; virtual DWORD length() const = 0; virtual LPVOID informationPtr() const = 0; virtual ~JobObjectInformation() {}; }; class JobObject { public: JobObject(const JobObject&) = delete; JobObject operator=(const JobObject&) = delete; JobObject() { jobHandle = CreateJobObjectA(NULL, NULL); if (jobHandle == NULL) { throw std::runtime_error("Create job failed!"); } } HANDLE getHandle() { return jobHandle; } void assignProcess(const Process &p) { if (AssignProcessToJobObject(jobHandle, p.handle()) == 0) throw std::runtime_error("Failed to assgin process to job: "s + std::to_string(GetLastError())); } BOOL setInformation(const JobObjectInformation& i) { return SetInformationJobObject(jobHandle, i.getClass(), i.informationPtr(), i.length()); } ~JobObject() { CloseHandle(jobHandle); } private: HANDLE jobHandle{}; }; class CpuRateJobObjectInformation : public JobObjectInformation { public: CpuRateJobObjectInformation(int rate) { information.ControlFlags = JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP; if (rate <= 0 || rate > 100) throw std::runtime_error("Invalid argument"); information.CpuRate = rate * 100; } virtual JOBOBJECTINFOCLASS getClass() const override { return JOBOBJECTINFOCLASS::JobObjectCpuRateControlInformation; } virtual DWORD length() const override { return sizeof(information); } virtual LPVOID informationPtr() const override { return (LPVOID) &information; } private: JOBOBJECT_CPU_RATE_CONTROL_INFORMATION information{}; }; int main(int argc, const char **argv) { JobObject jobObject; CpuRateJobObjectInformation information{20}; jobObject.setInformation(information); ChildProcess childProcess{ "C:\\xiangqi.exe"}; jobObject.assignProcess(childProcess); childProcess.start(); childProcess.wait(); DWORD pid; std::cout << "Input PID:" << std::endl; std::cin >> pid; AttachProcess attachProcess{ pid }; try { jobObject.assignProcess(attachProcess); } catch (const std::exception& e) { std::cout << e.what(); } attachProcess.wait(); return 0; }