File indexing completed on 2025-01-18 09:50:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
0012 #define BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
0013
0014 #include <boost/process/v2/cstring_ref.hpp>
0015 #include <boost/process/v2/detail/config.hpp>
0016 #include <boost/process/v2/detail/last_error.hpp>
0017 #include <boost/process/v2/detail/throw_error.hpp>
0018 #include <boost/process/v2/detail/utf8.hpp>
0019 #include <boost/process/v2/error.hpp>
0020
0021 #include <numeric>
0022 #include <windows.h>
0023
0024 #if defined(BOOST_PROCESS_V2_STANDALONE)
0025 #include <asio/execution/executor.hpp>
0026 #include <asio/is_executor.hpp>
0027 #include <asio/execution_context.hpp>
0028 #else
0029 #include <boost/asio/execution/executor.hpp>
0030 #include <boost/asio/is_executor.hpp>
0031 #include <boost/asio/execution_context.hpp>
0032 #endif
0033
0034 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0035
0036 template<typename Executor>
0037 struct basic_process;
0038
0039 namespace detail
0040 {
0041
0042 struct base {};
0043 struct derived : base {};
0044
0045 template<typename Launcher, typename Init>
0046 inline error_code invoke_on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0047 Init && init, base && )
0048 {
0049 return error_code{};
0050 }
0051
0052 template<typename Launcher, typename Init>
0053 inline auto invoke_on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0054 Init && init, derived && )
0055 -> decltype(init.on_setup(launcher, executable, cmd_line))
0056 {
0057 return init.on_setup(launcher, executable, cmd_line);
0058 }
0059
0060 template<typename Launcher, typename Init>
0061 inline std::false_type probe_on_setup(
0062 Launcher & launcher, Init && init, base && );
0063
0064 template<typename Launcher, typename Init>
0065 inline auto probe_on_setup(Launcher & launcher, Init && init, derived && )
0066 -> std::is_same<error_code, decltype(init.on_setup(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>()))>;
0067
0068 template<typename Launcher, typename Init>
0069 using has_on_setup = decltype(probe_on_setup(std::declval<Launcher&>(), std::declval<Init>(), derived{}));
0070
0071 template<typename Launcher>
0072 inline error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line)
0073 {
0074 return error_code{};
0075 }
0076
0077 template<typename Launcher, typename Init1, typename ... Inits>
0078 inline error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0079 Init1 && init1, Inits && ... inits)
0080 {
0081 auto ec = invoke_on_setup(launcher, executable, cmd_line, init1, derived{});
0082 if (ec)
0083 return ec;
0084 else
0085 return on_setup(launcher, executable, cmd_line, inits...);
0086 }
0087
0088
0089 template<typename Launcher, typename Init>
0090 inline void invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0091 const error_code & ec, Init && init, base && )
0092 {
0093 }
0094
0095 template<typename Launcher, typename Init>
0096 inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0097 const error_code & ec, Init && init, derived && )
0098 -> decltype(init.on_error(launcher, ec, executable, cmd_line, ec))
0099 {
0100 init.on_error(launcher, executable, cmd_line, ec);
0101 }
0102
0103
0104 template<typename Launcher, typename Init>
0105 inline std::false_type probe_on_error(
0106 Launcher & launcher, Init && init, base && );
0107
0108 template<typename Launcher, typename Init>
0109 inline auto probe_on_error(Launcher & launcher, Init && init, derived && )
0110 -> std::is_same<error_code, decltype(init.on_error(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>(), std::declval<std::error_code&>()))>;
0111
0112 template<typename Launcher, typename Init>
0113 using has_on_error = decltype(probe_on_error(std::declval<Launcher&>(), std::declval<Init>(), derived{}));
0114
0115
0116 template<typename Launcher>
0117 inline void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0118 const error_code & ec)
0119 {
0120 }
0121
0122 template<typename Launcher, typename Init1, typename ... Inits>
0123 inline void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0124 const error_code & ec,
0125 Init1 && init1,
0126 Inits && ... inits)
0127 {
0128 invoke_on_error(launcher, executable, cmd_line, ec, init1, derived{});
0129 on_error(launcher, executable, cmd_line, ec, inits...);
0130 }
0131
0132 template<typename Launcher, typename Init>
0133 inline void invoke_on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0134 Init && init, base && )
0135 {
0136 }
0137
0138 template<typename Launcher, typename Init>
0139 inline auto invoke_on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0140 Init && init, derived && )
0141 -> decltype(init.on_success(launcher, executable, cmd_line))
0142 {
0143 init.on_success(launcher, executable, cmd_line);
0144 }
0145
0146 template<typename Launcher, typename Init>
0147 inline std::false_type probe_on_success(
0148 Launcher & launcher, Init && init, base && );
0149
0150 template<typename Launcher, typename Init>
0151 inline auto probe_on_success(Launcher & launcher, Init && init, derived && )
0152 -> std::is_same<error_code, decltype(init.on_success(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>()))>;
0153
0154 template<typename Launcher, typename Init>
0155 using has_on_success = decltype(probe_on_success(std::declval<Launcher&>(), std::declval<Init>(), derived{}));
0156
0157 template<typename Launcher>
0158 inline void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line)
0159 {
0160 }
0161
0162 template<typename Launcher, typename Init1, typename ... Inits>
0163 inline void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
0164 Init1 && init1, Inits && ... inits)
0165 {
0166 invoke_on_success(launcher, executable, cmd_line, init1, derived{});
0167 on_success(launcher, executable, cmd_line, inits...);
0168 }
0169
0170 template<typename Launcher, typename Init>
0171 struct is_initializer : std::integral_constant<bool,
0172 has_on_setup<Launcher, Init>::value ||
0173 has_on_error<Launcher, Init>::value ||
0174 has_on_success<Launcher, Init>::value>
0175 {
0176 };
0177
0178 template<typename Launcher, typename ... Inits>
0179 struct all_are_initializers;
0180
0181 template<typename Launcher>
0182 struct all_are_initializers<Launcher> : std::true_type {};
0183
0184
0185 template<typename Launcher, typename Init>
0186 struct all_are_initializers<Launcher, Init> : is_initializer<Launcher, Init> {};
0187
0188 template<typename Launcher, typename Init, typename ... Tail>
0189 struct all_are_initializers<Launcher, Init, Tail...>
0190 : std::integral_constant<bool, is_initializer<Launcher, Init>::value && all_are_initializers<Launcher, Tail...>::value>
0191 {
0192 };
0193
0194
0195 }
0196
0197 template<typename Executor>
0198 struct basic_process;
0199
0200 namespace windows
0201 {
0202
0203
0204 struct default_launcher
0205 {
0206
0207 SECURITY_ATTRIBUTES * process_attributes = nullptr;
0208
0209 SECURITY_ATTRIBUTES * thread_attributes = nullptr;
0210
0211 bool inherit_handles = false;
0212
0213 DWORD creation_flags{EXTENDED_STARTUPINFO_PRESENT};
0214
0215 void * environment = nullptr;
0216
0217 filesystem::path current_directory{};
0218
0219
0220 STARTUPINFOEXW startup_info{{sizeof(STARTUPINFOEXW), nullptr, nullptr, nullptr,
0221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
0222 INVALID_HANDLE_VALUE,
0223 INVALID_HANDLE_VALUE,
0224 INVALID_HANDLE_VALUE},
0225 nullptr};
0226
0227 PROCESS_INFORMATION process_information{nullptr, nullptr, 0,0};
0228
0229 template<typename Executor, typename ... Inits>
0230 using enable_init = typename std::enable_if<
0231 detail::all_are_initializers<default_launcher, Inits...>::value,
0232 basic_process<Executor>>::type;
0233
0234 default_launcher() = default;
0235
0236 template<typename ExecutionContext, typename Args, typename ... Inits>
0237 auto operator()(ExecutionContext & context,
0238 const typename std::enable_if<std::is_convertible<
0239 ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0240 filesystem::path >::type & executable,
0241 Args && args,
0242 Inits && ... inits ) -> enable_init<typename ExecutionContext::executor_type, Inits...>
0243 {
0244 error_code ec;
0245 auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0246
0247 if (ec)
0248 v2::detail::throw_error(ec, "default_launcher");
0249
0250 return proc;
0251 }
0252
0253
0254 template<typename ExecutionContext, typename Args, typename ... Inits>
0255 auto operator()(ExecutionContext & context,
0256 error_code & ec,
0257 const typename std::enable_if<std::is_convertible<
0258 ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0259 filesystem::path >::type & executable,
0260 Args && args,
0261 Inits && ... inits ) -> enable_init<typename ExecutionContext::executor_type, Inits...>
0262 {
0263 return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0264 }
0265
0266 template<typename Executor, typename Args, typename ... Inits>
0267 auto operator()(Executor exec,
0268 const typename std::enable_if<
0269 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value
0270 || BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
0271 filesystem::path >::type & executable,
0272 Args && args,
0273 Inits && ... inits ) -> enable_init<Executor, Inits...>
0274 {
0275 error_code ec;
0276 auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0277
0278 if (ec)
0279 detail::throw_error(ec, "default_launcher");
0280
0281 return proc;
0282 }
0283
0284 template<typename Executor, typename Args, typename ... Inits>
0285 auto operator()(Executor exec,
0286 error_code & ec,
0287 const typename std::enable_if<
0288 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
0289 BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
0290 filesystem::path >::type & executable,
0291 Args && args,
0292 Inits && ... inits ) -> enable_init<Executor, Inits...>
0293 {
0294 auto command_line = this->build_command_line(executable, std::forward<Args>(args));
0295
0296 ec = detail::on_setup(*this, executable, command_line, inits...);
0297 if (ec)
0298 {
0299 detail::on_error(*this, executable, command_line, ec, inits...);
0300 return basic_process<Executor>(exec);
0301 }
0302
0303 auto ok = ::CreateProcessW(
0304 executable.empty() ? nullptr : executable.c_str(),
0305 command_line.empty() ? nullptr : &command_line.front(),
0306 process_attributes,
0307 thread_attributes,
0308 inherit_handles ? TRUE : FALSE,
0309 creation_flags,
0310 environment,
0311 current_directory.empty() ? nullptr : current_directory.c_str(),
0312 &startup_info.StartupInfo,
0313 &process_information);
0314
0315 if (ok == 0)
0316 {
0317 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0318 detail::on_error(*this, executable, command_line, ec, inits...);
0319
0320 if (process_information.hProcess != INVALID_HANDLE_VALUE)
0321 ::CloseHandle(process_information.hProcess);
0322 if (process_information.hThread != INVALID_HANDLE_VALUE)
0323 ::CloseHandle(process_information.hThread);
0324
0325 return basic_process<Executor>(exec);
0326 }
0327 else
0328 {
0329 detail::on_success(*this, executable, command_line, inits...);
0330
0331 if (process_information.hThread != INVALID_HANDLE_VALUE)
0332 ::CloseHandle(process_information.hThread);
0333
0334 return basic_process<Executor>(exec,
0335 this->process_information.dwProcessId,
0336 this->process_information.hProcess);
0337 }
0338 }
0339
0340 BOOST_PROCESS_V2_DECL static
0341 std::size_t escaped_argv_length(basic_string_view<wchar_t> ws);
0342 BOOST_PROCESS_V2_DECL static
0343 std::size_t escape_argv_string(wchar_t * itr, std::size_t max_size,
0344 basic_string_view<wchar_t> ws);
0345
0346
0347
0348
0349 template<typename Argv>
0350 static std::wstring build_command_line_impl(
0351 const filesystem::path & pt,
0352 const Argv & argv,
0353 basic_string_view<wchar_t> args)
0354 {
0355 std::size_t req_size = std::accumulate(
0356 std::begin(argv), std::end(argv), escaped_argv_length(pt.native()),
0357 [](std::size_t sz, basic_string_view<wchar_t> arg) -> std::size_t
0358 {
0359 return sz + 1u + escaped_argv_length(arg);
0360 });
0361
0362 std::wstring res;
0363 res.resize(req_size, L' ');
0364
0365 wchar_t * itr = &res.front();
0366 itr += escape_argv_string(itr, res.size(), pt.native());
0367 for (const auto & a : argv)
0368 {
0369 itr++;
0370 itr += escape_argv_string(itr, std::distance(itr, &res.back() + 1), a);
0371 }
0372 return res;
0373 }
0374
0375 template<typename Argv>
0376 static std::wstring build_command_line_impl(
0377 const filesystem::path & pt,
0378 const Argv & argv,
0379 basic_string_view<char> args)
0380 {
0381 std::vector<std::wstring> argw;
0382 argw.resize(std::distance(std::begin(argv), std::end(argv)));
0383 std::transform(std::begin(argv), std::end(argv), argw.begin(),
0384 [](basic_string_view <char> arg)
0385 {
0386 return detail::conv_string<wchar_t>(arg.data(), arg.size());
0387 });
0388 return build_command_line_impl(pt, argw, L"");
0389 }
0390
0391 template<typename Args,
0392 typename Char = decltype(*std::begin(std::declval<Args>()))>
0393 static std::wstring build_command_line(const filesystem::path & pt, const Args & args)
0394 {
0395 if (std::begin(args) == std::end(args))
0396 return pt.native();
0397
0398 return build_command_line_impl(pt, args, *std::begin(args));
0399 }
0400
0401 static std::wstring build_command_line(const filesystem::path & pt, const wchar_t * args)
0402 {
0403 return args;
0404 }
0405
0406 };
0407
0408
0409 }
0410 BOOST_PROCESS_V2_END_NAMESPACE
0411
0412 #if defined(BOOST_PROCESS_V2_HEADER_ONLY)
0413 #include <boost/process/v2/windows/impl/default_launcher.ipp>
0414 #endif
0415
0416 #endif