// Copyright (c) 2022 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP #define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP #include #include #include #include #if defined(BOOST_PROCESS_V2_STANDALONE) #include #include #include #else #include #include #include #endif BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace detail { BOOST_PROCESS_V2_DECL void get_exit_code_( void * handle, native_exit_code_type & exit_code, error_code & ec); BOOST_PROCESS_V2_DECL void * open_process_(pid_type pid); BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle); BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec); BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec); BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec); BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code); BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec); BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status); template struct basic_process_handle_win { typedef BOOST_PROCESS_V2_ASIO_NAMESPACE::windows::basic_object_handle handle_type; typedef typename handle_type::native_handle_type native_handle_type; typedef Executor executor_type; executor_type get_executor() { return handle_.get_executor(); } /// Rebinds the process_handle to another executor. template struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_process_handle_win other; }; template basic_process_handle_win(ExecutionContext &context, typename std::enable_if< std::is_convertible::value >::type = 0) : pid_(0), handle_(context) { } basic_process_handle_win(Executor executor) : pid_(0), handle_(executor) { } basic_process_handle_win(Executor executor, pid_type pid) : pid_(pid), handle_(executor, detail::open_process_(pid)) { } basic_process_handle_win(Executor executor, pid_type pid, native_handle_type process_handle) : pid_(pid), handle_(executor, process_handle) { } template basic_process_handle_win(basic_process_handle_win && handle) : pid_(handle.pid_), handle_(handle.handle_.get_executor()) { } basic_process_handle_win(basic_process_handle_win && handle) { pid_ = handle.id(); handle_ = std::move(handle.handle_); handle.pid_ = static_cast(-1); } basic_process_handle_win& operator=(basic_process_handle_win && handle) { pid_ = handle.pid_; handle_ = std::mopve(handle_)) handle.pid_ = static_cast(-1); return *this; } ~basic_process_handle_win() { if (handle_.is_open()) { error_code ec; handle_.close(ec); } } native_handle_type native_handle() { return handle_.native_handle(); } pid_type id() const { return pid_; } void terminate_if_running(error_code &) { detail::terminate_if_running_(handle_.native_handle()); } void terminate_if_running() { detail::terminate_if_running_(handle_.native_handle()); } void wait(native_exit_code_type &exit_status, error_code &ec) { if (!detail::check_handle_(handle_.native_handle(), ec)) return; handle_.wait(ec); if (!ec) detail::get_exit_code_(handle_.native_handle(), exit_status, ec); } void wait(native_exit_code_type &exit_status) { error_code ec; wait(exit_status, ec); if (ec) detail::throw_error(ec, "wait(pid)"); } void interrupt(error_code &ec) { if (!detail::check_pid_(pid_, ec)) return; detail::interrupt_(pid_, ec); } void interrupt() { error_code ec; interrupt(ec); if (ec) detail::throw_error(ec, "interrupt"); } void request_exit(error_code &ec) { if (!detail::check_pid_(pid_, ec)) return; detail::request_exit_(pid_, ec); } void request_exit() { error_code ec; request_exit(ec); if (ec) detail::throw_error(ec, "request_exit"); } void terminate(native_exit_code_type &exit_status, error_code &ec) { if (!detail::check_handle_(handle_.native_handle(), ec)) return; detail::terminate_(handle_.native_handle(), ec, exit_status); if (!ec) wait(exit_status, ec); } void terminate(native_exit_code_type &exit_status) { error_code ec; terminate(exit_status, ec); if (ec) detail::throw_error(ec, "terminate"); } bool running(native_exit_code_type &exit_code, error_code & ec) { if (!detail::check_handle_(handle_.native_handle(), ec)) return false; native_exit_code_type code; //single value, not needed in the winapi. detail::check_running_(handle_.native_handle(), ec, code); if (ec) return false; if (process_is_running(code)) return true; else { exit_code = code; return false; } } bool running(native_exit_code_type &exit_code) { error_code ec; bool res = running(exit_code, ec); if (ec) detail::throw_error(ec, "is_running"); return res; } bool is_open() const { return handle_.is_open(); } template BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type)) async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose( async_wait_op_{handle_}, handler, handle_ ); } template friend struct basic_process_handle_win; private: pid_type pid_; handle_type handle_; struct async_wait_op_ { handle_type &handle; template void operator()(Self &&self) { handle.async_wait(std::move(self)); } template void operator()(Self &&self, error_code ec) { native_exit_code_type exit_code{}; if (!ec) detail::get_exit_code_(handle.native_handle(), exit_code, ec); std::move(self).complete(ec, exit_code); } }; }; #if !defined(BOOST_PROCESS_V2_HEADER_ONLY) extern template struct basic_process_handle_win<>; #endif } BOOST_PROCESS_V2_END_NAMESPACE #endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP