diff options
-rw-r--r-- | include/winapi/process.hpp | 4 | ||||
-rw-r--r-- | src/process.cpp | 27 | ||||
-rw-r--r-- | test/unit_tests/process.cpp | 17 |
3 files changed, 47 insertions, 1 deletions
diff --git a/include/winapi/process.hpp b/include/winapi/process.hpp index 05411cd..5c9e3c9 100644 --- a/include/winapi/process.hpp +++ b/include/winapi/process.hpp @@ -26,8 +26,10 @@ public: static Process runas(const CommandLine&); + bool is_running() const; void wait() const; - + void terminate(int ec = 0) const; + void shut_down(int ec = 0) const; int get_exit_code() const; static std::string get_exe_path(); diff --git a/src/process.cpp b/src/process.cpp index a9f24cc..c5e68d7 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -110,6 +110,22 @@ Process Process::runas(const CommandLine& cmd_line) { return Process{shell_execute(cmd_line)}; } +bool Process::is_running() const { + const auto ret = ::WaitForSingleObject(static_cast<HANDLE>(m_handle), 0); + + switch (ret) { + case WAIT_OBJECT_0: + return false; + case WAIT_TIMEOUT: + return true; + case WAIT_FAILED: + throw error::windows(GetLastError(), "WaitForSingleObject"); + default: + // Shouldn't happen. + throw error::custom(ret, "WaitForSingleObject"); + } +} + void Process::wait() const { const auto ret = ::WaitForSingleObject(static_cast<HANDLE>(m_handle), INFINITE); @@ -124,6 +140,17 @@ void Process::wait() const { } } +void Process::terminate(int ec) const { + if (!::TerminateProcess(static_cast<HANDLE>(m_handle), static_cast<UINT>(ec))) { + throw error::windows(GetLastError(), "TerminateProcess"); + } +} + +void Process::shut_down(int ec) const { + terminate(ec); + wait(); +} + int Process::get_exit_code() const { DWORD ec = 0; diff --git a/test/unit_tests/process.cpp b/test/unit_tests/process.cpp index 715364f..cfc50f4 100644 --- a/test/unit_tests/process.cpp +++ b/test/unit_tests/process.cpp @@ -15,6 +15,8 @@ #include <boost/test/unit_test.hpp> +#include <chrono> +#include <thread> #include <utility> using namespace winapi; @@ -89,4 +91,19 @@ BOOST_FIXTURE_TEST_CASE(echo_runas, WithEchoExe) { BOOST_TEST(process.get_exit_code() == 0); } +BOOST_FIXTURE_TEST_CASE(echo_terminate, WithEchoExe) { + const CommandLine cmd_line{get_echo_exe()}; + const auto process = Process::create(cmd_line); + + // echo.exe is stuck trying to read stdin. + BOOST_TEST(process.is_running()); + std::this_thread::sleep_for(std::chrono::seconds{3}); + BOOST_TEST(process.is_running()); + + process.shut_down(123); + + BOOST_TEST(!process.is_running()); + BOOST_TEST(process.get_exit_code() == 123); +} + BOOST_AUTO_TEST_SUITE_END() |