Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:11

0001 //
0002 // boost/process/v2/windows/default_launcher.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 /// The default launcher for processes on windows.
0204 struct default_launcher
0205 {
0206   //// The process_attributes passed to CreateProcess
0207   SECURITY_ATTRIBUTES * process_attributes = nullptr;
0208   //// The thread_attributes passed to CreateProcess
0209   SECURITY_ATTRIBUTES * thread_attributes = nullptr;
0210   /// The bInheritHandles option. Needs to be set to true by any initializers using handles.
0211   bool inherit_handles = false;
0212   /// The creation flags of the process. Initializers may add to them; extended startupinfo is assumed.
0213   DWORD creation_flags{EXTENDED_STARTUPINFO_PRESENT};
0214   /// A pointer to the subprocess environment.
0215   void * environment = nullptr;
0216   /// The startup director. An empty path will get ignored.
0217   filesystem::path current_directory{};
0218 
0219   /// The full startup info passed to CreateProcess
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   /// The process_information that gets assigned after a call to CreateProcess
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 //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP