Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 09:01:26

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<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   /// Allow batch files to be executed, which might pose a security threat.
0229   bool allow_batch_files = false;
0230                               
0231   /// The process_information that gets assigned after a call to CreateProcess
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 //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP