diff options
-rw-r--r-- | include/winapi/process.hpp | 2 | ||||
-rw-r--r-- | src/process.cpp | 31 | ||||
-rw-r--r-- | test/unit_tests/process.cpp | 7 |
3 files changed, 40 insertions, 0 deletions
diff --git a/include/winapi/process.hpp b/include/winapi/process.hpp index d52ad0a..05411cd 100644 --- a/include/winapi/process.hpp +++ b/include/winapi/process.hpp @@ -24,6 +24,8 @@ public: static Process create(const CommandLine&); static Process create(const CommandLine&, process::IO); + static Process runas(const CommandLine&); + void wait() const; int get_exit_code() const; diff --git a/src/process.cpp b/src/process.cpp index 9fe19e5..a9f24cc 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -12,7 +12,10 @@ #include <boost/config.hpp> +// clang-format off #include <windows.h> +#include <shellapi.h> +// clang-format on #include <cstddef> #include <cstring> @@ -69,6 +72,30 @@ Handle create_process(const CommandLine& cmd_line, process::IO& io) { return create_process(escape_command_line(cmd_line), io); } +Handle shell_execute(const CommandLine& cmd_line) { + BOOST_STATIC_CONSTEXPR unsigned long flags = + SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE; + + const auto exe_path = widen(cmd_line.get_argv0()); + const auto args = widen(cmd_line.args_to_string()); + + SHELLEXECUTEINFOW info; + std::memset(&info, 0, sizeof(info)); + info.cbSize = sizeof(info); + info.fMask = flags; + info.lpVerb = L"runas"; + info.lpFile = exe_path.c_str(); + if (!args.empty()) + info.lpParameters = args.c_str(); + info.nShow = SW_SHOWDEFAULT; + + if (!::ShellExecuteExW(&info)) { + throw error::windows(GetLastError(), "ShellExecuteExW"); + } + + return Handle{info.hProcess}; +} + } // namespace Process Process::create(const CommandLine& cmd_line) { @@ -79,6 +106,10 @@ Process Process::create(const CommandLine& cmd_line, process::IO io) { return Process{create_process(cmd_line, io)}; } +Process Process::runas(const CommandLine& cmd_line) { + return Process{shell_execute(cmd_line)}; +} + void Process::wait() const { const auto ret = ::WaitForSingleObject(static_cast<HANDLE>(m_handle), INFINITE); diff --git a/test/unit_tests/process.cpp b/test/unit_tests/process.cpp index a126f86..715364f 100644 --- a/test/unit_tests/process.cpp +++ b/test/unit_tests/process.cpp @@ -82,4 +82,11 @@ BOOST_FIXTURE_TEST_CASE(echo_stdin_from_file, WithEchoExe) { BOOST_TEST(stdout8 == stdin8); } +BOOST_FIXTURE_TEST_CASE(echo_runas, WithEchoExe) { + const CommandLine cmd_line{get_echo_exe(), {"foo", "bar"}}; + const auto process = Process::runas(cmd_line); + process.wait(); + BOOST_TEST(process.get_exit_code() == 0); +} + BOOST_AUTO_TEST_SUITE_END() |