00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00019 #ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
00020 #define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
00021
00022 #include <boost/process/environment.hpp>
00023 #include <boost/process/detail/file_handle.hpp>
00024 #include <boost/process/detail/pipe.hpp>
00025 #include <boost/process/detail/stream_info.hpp>
00026 #include <boost/scoped_ptr.hpp>
00027 #include <boost/shared_array.hpp>
00028 #include <boost/scoped_array.hpp>
00029 #include <boost/assert.hpp>
00030 #include <boost/system/system_error.hpp>
00031 #include <boost/throw_exception.hpp>
00032 #include <vector>
00033 #include <string>
00034 #include <cstddef>
00035 #include <string.h>
00036 #include <windows.h>
00037
00038 namespace boost {
00039 namespace process {
00040 namespace detail {
00041
00053 template <class Arguments>
00054 inline boost::shared_array<char> collection_to_win32_cmdline(const Arguments &args)
00055 {
00056 typedef std::vector<std::string> arguments_t;
00057 arguments_t args2;
00058 typename Arguments::size_type i = 0;
00059 std::size_t size = 0;
00060 for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
00061 {
00062 std::string arg = *it;
00063
00064 std::string::size_type pos = 0;
00065 while ( (pos = arg.find('"', pos)) != std::string::npos)
00066 {
00067 arg.replace(pos, 1, "\\\"");
00068 pos += 2;
00069 }
00070
00071 if (arg.find(' ') != std::string::npos)
00072 arg = '\"' + arg + '\"';
00073
00074 if (i++ != args.size() - 1)
00075 arg += ' ';
00076
00077 args2.push_back(arg);
00078 size += arg.size() + 1;
00079 }
00080
00081 boost::shared_array<char> cmdline(new char[size]);
00082 cmdline.get()[0] = '\0';
00083 for (arguments_t::size_type i = 0; i < args.size(); ++i)
00084 #if defined(__CYGWIN__)
00085 ::strncat(cmdline.get(), args2[i].c_str(), args2[i].size());
00086 #else
00087 ::strcat_s(cmdline.get(), size, args2[i].c_str());
00088 #endif
00089
00090 return cmdline;
00091 }
00092
00105 inline boost::shared_array<char> environment_to_win32_strings(const environment &env)
00106 {
00107 boost::shared_array<char> envp;
00108
00109 if (env.empty())
00110 {
00111 envp.reset(new char[2]);
00112 ::ZeroMemory(envp.get(), 2);
00113 }
00114 else
00115 {
00116 std::string s;
00117 for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
00118 {
00119 s += it->first + "=" + it->second;
00120 s.push_back(0);
00121 }
00122
00123 envp.reset(new char[s.size() + 1]);
00124 #if defined(__CYGWIN__)
00125 ::memcpy(envp.get(), s.c_str(), s.size() + 1);
00126 #else
00127 ::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1);
00128 #endif
00129 }
00130
00131 return envp;
00132 }
00133
00144 struct win32_setup
00145 {
00152 std::string work_directory;
00153
00162 STARTUPINFOA *startupinfo;
00163 };
00164
00185 template <class Executable, class Arguments>
00186 inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup)
00187 {
00188 file_handle chin, chout, cherr;
00189
00190 BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA));
00191 BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES));
00192
00193 boost::scoped_ptr<STARTUPINFOA> si(new STARTUPINFOA);
00194 ::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo));
00195 si->dwFlags |= STARTF_USESTDHANDLES;
00196
00197 switch (infoin.type_)
00198 {
00199 case stream_info::close:
00200 {
00201 break;
00202 }
00203 case stream_info::inherit:
00204 {
00205 chin = file_handle::win32_std(STD_INPUT_HANDLE, true);
00206 break;
00207 }
00208 case stream_info::use_file:
00209 {
00210 HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00211 if (h == INVALID_HANDLE_VALUE)
00212 boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
00213 chin = file_handle(h);
00214 break;
00215 }
00216 case stream_info::use_handle:
00217 {
00218 chin = infoin.handle_;
00219 chin.win32_set_inheritable(true);
00220 break;
00221 }
00222 case stream_info::use_pipe:
00223 {
00224 infoin.pipe_->rend().win32_set_inheritable(true);
00225 chin = infoin.pipe_->rend();
00226 break;
00227 }
00228 default:
00229 {
00230 BOOST_ASSERT(false);
00231 break;
00232 }
00233 }
00234
00235 si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE;
00236
00237 switch (infoout.type_)
00238 {
00239 case stream_info::close:
00240 {
00241 break;
00242 }
00243 case stream_info::inherit:
00244 {
00245 chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true);
00246 break;
00247 }
00248 case stream_info::use_file:
00249 {
00250 HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00251 if (h == INVALID_HANDLE_VALUE)
00252 boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
00253 chout = file_handle(h);
00254 break;
00255 }
00256 case stream_info::use_handle:
00257 {
00258 chout = infoout.handle_;
00259 chout.win32_set_inheritable(true);
00260 break;
00261 }
00262 case stream_info::use_pipe:
00263 {
00264 infoout.pipe_->wend().win32_set_inheritable(true);
00265 chout = infoout.pipe_->wend();
00266 break;
00267 }
00268 default:
00269 {
00270 BOOST_ASSERT(false);
00271 break;
00272 }
00273 }
00274
00275 si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE;
00276
00277 switch (infoerr.type_)
00278 {
00279 case stream_info::close:
00280 {
00281 break;
00282 }
00283 case stream_info::inherit:
00284 {
00285 cherr = file_handle::win32_std(STD_ERROR_HANDLE, true);
00286 break;
00287 }
00288 case stream_info::redirect:
00289 {
00290 BOOST_ASSERT(infoerr.desc_to_ == 1);
00291 BOOST_ASSERT(chout.valid());
00292 cherr = file_handle::win32_dup(chout.get(), true);
00293 break;
00294 }
00295 case stream_info::use_file:
00296 {
00297 HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00298 if (h == INVALID_HANDLE_VALUE)
00299 boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
00300 cherr = file_handle(h);
00301 break;
00302 }
00303 case stream_info::use_handle:
00304 {
00305 cherr = infoerr.handle_;
00306 cherr.win32_set_inheritable(true);
00307 break;
00308 }
00309 case stream_info::use_pipe:
00310 {
00311 infoerr.pipe_->wend().win32_set_inheritable(true);
00312 cherr = infoerr.pipe_->wend();
00313 break;
00314 }
00315 default:
00316 {
00317 BOOST_ASSERT(false);
00318 break;
00319 }
00320 }
00321
00322 si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE;
00323
00324 PROCESS_INFORMATION pi;
00325 ::ZeroMemory(&pi, sizeof(pi));
00326
00327 boost::shared_array<char> cmdline = collection_to_win32_cmdline(args);
00328
00329 boost::scoped_array<char> executable(new char[exe.size() + 1]);
00330 #if defined(__CYGWIN__)
00331 ::strcpy(executable.get(), exe.c_str());
00332 #else
00333 ::strcpy_s(executable.get(), exe.size() + 1, exe.c_str());
00334 #endif
00335
00336 boost::scoped_array<char> workdir(new char[setup.work_directory.size() + 1]);
00337 #if defined(__CYGWIN__)
00338 ::strcpy(workdir.get(), setup.work_directory.c_str());
00339 #else
00340 ::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str());
00341 #endif
00342
00343 boost::shared_array<char> envstrs = environment_to_win32_strings(env);
00344
00345 if (!::CreateProcessA(executable.get(), cmdline.get(), NULL, NULL, TRUE, 0, envstrs.get(), workdir.get(), si.get(), &pi))
00346 boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed"));
00347
00348 return pi;
00349 }
00350
00351 }
00352 }
00353 }
00354
00355 #endif