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