.. _program_listing_file__tmp_ws_src_rosbag2_rosbag2_test_common_include_rosbag2_test_common_process_execution_helpers_windows.hpp: Program Listing for File process_execution_helpers_windows.hpp ============================================================== |exhale_lsh| :ref:`Return to documentation for file ` (``/tmp/ws/src/rosbag2/rosbag2_test_common/include/rosbag2_test_common/process_execution_helpers_windows.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // Copyright 2018, Bosch Software Innovations GmbH. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ROSBAG2_TEST_COMMON__PROCESS_EXECUTION_HELPERS_WINDOWS_HPP_ #define ROSBAG2_TEST_COMMON__PROCESS_EXECUTION_HELPERS_WINDOWS_HPP_ #include #include #include #include #include #include #include #include using namespace ::testing; // NOLINT struct Process { PROCESS_INFORMATION process_info; HANDLE job_handle; }; using ProcessHandle = Process; PROCESS_INFORMATION create_process(TCHAR * command, const char * path = nullptr) { STARTUPINFO start_up_info{}; PROCESS_INFORMATION process_info{}; CreateProcess( nullptr, command, nullptr, nullptr, false, 0, nullptr, path, &start_up_info, &process_info); return process_info; } void close_process_handles(const PROCESS_INFORMATION & process) { CloseHandle(process.hProcess); CloseHandle(process.hThread); } void const_char_to_tchar(const char * source, TCHAR * destination) { size_t length = strlen(source); memcpy(destination, source, length + 1); } int execute_and_wait_until_completion(const std::string & command, const std::string & path) { TCHAR * command_char = new TCHAR[strlen(command.c_str()) + 1]; const_char_to_tchar(command.c_str(), command_char); auto process = create_process(command_char, path.c_str()); DWORD exit_code = 259; // 259 is the code one gets if the process is still active. while (exit_code == 259) { GetExitCodeProcess(process.hProcess, &exit_code); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } close_process_handles(process); delete[] command_char; return static_cast(exit_code); } ProcessHandle start_execution(const std::string & command) { auto h_job = CreateJobObject(nullptr, nullptr); JOBOBJECT_EXTENDED_LIMIT_INFORMATION info{}; info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(h_job, JobObjectExtendedLimitInformation, &info, sizeof(info)); TCHAR * command_char = new TCHAR[strlen(command.c_str()) + 1]; const_char_to_tchar(command.c_str(), command_char); auto process_info = create_process(command_char); AssignProcessToJobObject(h_job, process_info.hProcess); Process process; process.process_info = process_info; process.job_handle = h_job; delete[] command_char; return process; } void stop_execution(const ProcessHandle & handle, int signum = SIGINT) { // Match the Unix version by allowing for int signum argument - however Windows does not have // Linux signals in the same way, so there isn't a 1:1 mapping to dispatch e.g. SIGTERM DWORD exit_code; GetExitCodeProcess(handle.process_info.hProcess, &exit_code); // 259 indicates that the process is still active: we want to make sure that the process is // still running properly before killing it. ASSERT_THAT(exit_code, Eq(259)); GenerateConsoleCtrlEvent(CTRL_C_EVENT, handle.process_info.dwThreadId); close_process_handles(handle.process_info); CloseHandle(handle.job_handle); } #endif // ROSBAG2_TEST_COMMON__PROCESS_EXECUTION_HELPERS_WINDOWS_HPP_