Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:02:57

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 <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 & /*launcher*/, const filesystem::path &executable, std::wstring &cmd_line,
0049                                   Init && /*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 & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/)
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 & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/,
0093                             const error_code & /*ec*/, Init && /*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<std::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 & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/,
0120                      const error_code & /*ec*/)
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 & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/,
0136                               Init && /*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 & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/)
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 /// The default launcher for processes on windows.
0206 struct default_launcher
0207 {
0208   //// The process_attributes passed to CreateProcess
0209   SECURITY_ATTRIBUTES * process_attributes = nullptr;
0210   //// The thread_attributes passed to CreateProcess
0211   SECURITY_ATTRIBUTES * thread_attributes = nullptr;
0212   /// The inhreited_handles option. bInheritHandles will be true if not empty..
0213   std::vector<HANDLE> inherited_handles;
0214   /// The creation flags of the process. Initializers may add to them; extended startupinfo is assumed.
0215   DWORD creation_flags{EXTENDED_STARTUPINFO_PRESENT};
0216   /// A pointer to the subprocess environment.
0217   void * environment = nullptr;
0218   /// The startup director. An empty path will get ignored.
0219   filesystem::path current_directory{};
0220 
0221   /// The full startup info passed to CreateProcess
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   /// The process_information that gets assigned after a call to CreateProcess
0229   PROCESS_INFORMATION process_information{nullptr, nullptr, 0,0};
0230 
0231   template<typename Executor, typename ... Inits>
0232   using enable_init = typename std::enable_if< 
0233                                     detail::all_are_initializers<default_launcher, Inits...>::value, 
0234                                     basic_process<Executor>>::type;
0235 
0236   default_launcher() = default;
0237 
0238   template<typename ExecutionContext, typename Args, typename ... Inits>
0239   auto operator()(ExecutionContext & context,
0240                   const typename std::enable_if<std::is_convertible<
0241                              ExecutionContext&, net::execution_context&>::value,
0242                              filesystem::path >::type & executable,
0243                   Args && args,
0244                   Inits && ... inits ) -> enable_init<typename ExecutionContext::executor_type, Inits...>
0245   {
0246       error_code ec;
0247       auto proc =  (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0248 
0249       if (ec)
0250           v2::detail::throw_error(ec, "default_launcher");
0251 
0252       return proc;
0253   }
0254 
0255 
0256   template<typename ExecutionContext, typename Args, typename ... Inits>
0257   auto operator()(ExecutionContext & context,
0258                   error_code & ec,
0259                   const typename std::enable_if<std::is_convertible<
0260                              ExecutionContext&, net::execution_context&>::value,
0261                              filesystem::path >::type & executable,
0262                   Args && args,
0263                   Inits && ... inits ) -> enable_init<typename ExecutionContext::executor_type, Inits...>
0264   {
0265       return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0266   }
0267 
0268   template<typename Executor, typename Args, typename ... Inits>
0269   auto operator()(Executor exec,
0270                   const typename std::enable_if<
0271                              net::execution::is_executor<Executor>::value
0272                           || net::is_executor<Executor>::value,
0273                              filesystem::path >::type & executable,
0274                   Args && args,
0275                   Inits && ... inits ) -> enable_init<Executor, Inits...>
0276   {
0277       error_code ec;
0278       auto proc =  (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0279 
0280       if (ec)
0281           detail::throw_error(ec, "default_launcher");
0282 
0283       return proc;
0284   }
0285 
0286   template<typename Executor, typename Args, typename ... Inits>
0287   auto operator()(Executor exec,
0288                   error_code & ec,
0289                   const typename std::enable_if<
0290                              net::execution::is_executor<Executor>::value ||
0291                              net::is_executor<Executor>::value,
0292                              filesystem::path >::type & executable,
0293                   Args && args,
0294                   Inits && ... inits ) -> enable_init<Executor, Inits...>
0295   {
0296     auto command_line = this->build_command_line(executable, std::forward<Args>(args));
0297 
0298     ec = detail::on_setup(*this, executable, command_line, inits...);
0299 
0300     if (ec)
0301     {
0302       detail::on_error(*this, executable, command_line, ec, inits...);
0303       return basic_process<Executor>(exec);
0304     }
0305 
0306     if (!inherited_handles.empty())
0307     {
0308       set_handle_list(ec);
0309       if (ec)
0310         return basic_process<Executor>(exec);
0311     }
0312 
0313     auto ok = ::CreateProcessW(
0314         executable.empty() ? nullptr : executable.c_str(),
0315         command_line.empty() ? nullptr : &command_line.front(),
0316         process_attributes,
0317         thread_attributes,
0318         inherited_handles.empty() ? FALSE : TRUE,
0319         creation_flags,
0320         environment,
0321         current_directory.empty() ? nullptr : current_directory.c_str(),
0322         &startup_info.StartupInfo,
0323         &process_information);
0324 
0325     if (ok == 0)
0326     {
0327       BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
0328       detail::on_error(*this, executable, command_line, ec, inits...);
0329 
0330       if (process_information.hProcess != INVALID_HANDLE_VALUE)
0331         ::CloseHandle(process_information.hProcess);
0332       if (process_information.hThread != INVALID_HANDLE_VALUE)
0333         ::CloseHandle(process_information.hThread);
0334 
0335       return basic_process<Executor>(exec);
0336     }
0337     else
0338     {
0339       detail::on_success(*this, executable, command_line, inits...);
0340 
0341       if (process_information.hThread != INVALID_HANDLE_VALUE)
0342         ::CloseHandle(process_information.hThread);
0343 
0344       return basic_process<Executor>(exec,
0345                      this->process_information.dwProcessId,
0346                      this->process_information.hProcess);
0347     }
0348   }
0349   
0350   BOOST_PROCESS_V2_DECL static 
0351   std::size_t escaped_argv_length(basic_string_view<wchar_t> ws);
0352   BOOST_PROCESS_V2_DECL static 
0353   std::size_t escape_argv_string(wchar_t * itr, std::size_t max_size, 
0354                                  basic_string_view<wchar_t> ws);
0355                                         
0356 
0357 
0358 
0359   template<typename Argv>
0360   static std::wstring build_command_line_impl(
0361               const filesystem::path & pt, 
0362               const Argv & argv, 
0363               basic_string_view<wchar_t> args)
0364   {
0365       std::size_t req_size = std::accumulate(
0366           std::begin(argv), std::end(argv),  escaped_argv_length(pt.native()),
0367           [](std::size_t sz, basic_string_view<wchar_t> arg) -> std::size_t
0368           {
0369               return sz + 1u + escaped_argv_length(arg);
0370           });
0371 
0372       std::wstring res;
0373       res.resize(req_size, L' ');
0374       
0375       wchar_t * itr = &res.front();
0376       itr += escape_argv_string(itr, res.size(), pt.native());
0377       for (const auto & a : argv)
0378       {
0379         itr++;
0380         itr += escape_argv_string(itr, std::distance(itr, &res.back() + 1), a);
0381       }
0382       return res;
0383   }
0384 
0385   template<typename Argv>
0386   static std::wstring build_command_line_impl(
0387               const filesystem::path & pt, 
0388               const Argv & argv,
0389               basic_string_view<char> args)
0390   {
0391     std::vector<std::wstring> argw;
0392     argw.resize(std::distance(std::begin(argv), std::end(argv)));
0393     std::transform(std::begin(argv), std::end(argv), argw.begin(), 
0394                    [](basic_string_view <char> arg)
0395                    {
0396                       return detail::conv_string<wchar_t>(arg.data(), arg.size());
0397                    });
0398     return build_command_line_impl(pt, argw, L"");
0399   }
0400 
0401   template<typename Args,
0402            typename Char = decltype(*std::begin(std::declval<Args>()))>
0403   static std::wstring build_command_line(const filesystem::path & pt, const Args & args)
0404   {
0405     if (std::begin(args) == std::end(args))
0406       return pt.native();
0407 
0408     return build_command_line_impl(pt, args, *std::begin(args));
0409   }
0410 
0411   static std::wstring build_command_line(const filesystem::path & pt, const wchar_t * args)
0412   {
0413     return args;
0414   }
0415 
0416   struct lpproc_thread_closer
0417   {
0418     void operator()(::LPPROC_THREAD_ATTRIBUTE_LIST l)
0419     {
0420       ::DeleteProcThreadAttributeList(l);
0421       ::HeapFree(GetProcessHeap(), 0, l);
0422     }
0423   };
0424   std::unique_ptr<std::remove_pointer<LPPROC_THREAD_ATTRIBUTE_LIST>::type, lpproc_thread_closer> proc_attribute_list_storage;
0425 
0426   BOOST_PROCESS_V2_DECL LPPROC_THREAD_ATTRIBUTE_LIST get_thread_attribute_list(error_code & ec);
0427   BOOST_PROCESS_V2_DECL void set_handle_list(error_code & ec);
0428 };
0429 
0430 
0431 }
0432 BOOST_PROCESS_V2_END_NAMESPACE
0433 
0434 
0435 
0436 #endif //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP