1*87d2adbcSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*87d2adbcSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*87d2adbcSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*87d2adbcSAndrew Rist * distributed with this work for additional information 6*87d2adbcSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*87d2adbcSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*87d2adbcSAndrew Rist * "License"); you may not use this file except in compliance 9*87d2adbcSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*87d2adbcSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*87d2adbcSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*87d2adbcSAndrew Rist * software distributed under the License is distributed on an 15*87d2adbcSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*87d2adbcSAndrew Rist * KIND, either express or implied. See the License for the 17*87d2adbcSAndrew Rist * specific language governing permissions and limitations 18*87d2adbcSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*87d2adbcSAndrew Rist *************************************************************/ 21*87d2adbcSAndrew Rist 22*87d2adbcSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_sal.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #define UNICODE 28cdf0e10cSrcweir #define _UNICODE 29cdf0e10cSrcweir 30cdf0e10cSrcweir #ifndef WIN32_LEAN_AND_MEAN 31cdf0e10cSrcweir # define WIN32_LEAN_AND_MEAN 32cdf0e10cSrcweir # ifdef _MSC_VER 33cdf0e10cSrcweir # pragma warning(push,1) /* disable warnings within system headers */ 34cdf0e10cSrcweir # endif 35cdf0e10cSrcweir # include <windows.h> 36cdf0e10cSrcweir # ifdef _MSC_VER 37cdf0e10cSrcweir # pragma warning(pop) 38cdf0e10cSrcweir # endif 39cdf0e10cSrcweir # include <tchar.h> 40cdf0e10cSrcweir # undef WIN32_LEAN_AND_MEAN 41cdf0e10cSrcweir #endif 42cdf0e10cSrcweir #include "procimpl.h" 43cdf0e10cSrcweir #include <rtl/ustring.hxx> 44cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 45cdf0e10cSrcweir #include "secimpl.h" 46cdf0e10cSrcweir #include "rtl/allocator.hxx" 47cdf0e10cSrcweir #include <osl/file.hxx> 48cdf0e10cSrcweir 49cdf0e10cSrcweir #include <list> 50cdf0e10cSrcweir #include <vector> 51cdf0e10cSrcweir #include <algorithm> 52cdf0e10cSrcweir #include <string> 53cdf0e10cSrcweir 54cdf0e10cSrcweir //################################################# 55cdf0e10cSrcweir extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags ); 56cdf0e10cSrcweir 57cdf0e10cSrcweir //################################################# 58cdf0e10cSrcweir const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('='); 59cdf0e10cSrcweir const sal_Char* SPACE = " "; 60cdf0e10cSrcweir const rtl::OUString ENV_COMSPEC = rtl::OUString::createFromAscii("COMSPEC"); 61cdf0e10cSrcweir const rtl::OUString QUOTE = rtl::OUString::createFromAscii("\""); 62cdf0e10cSrcweir 63cdf0e10cSrcweir namespace /* private */ 64cdf0e10cSrcweir { 65cdf0e10cSrcweir //################################################# 66cdf0e10cSrcweir typedef std::list<rtl::OUString, rtl::Allocator<rtl::OUString> > string_container_t; 67cdf0e10cSrcweir typedef string_container_t::iterator string_container_iterator_t; 68cdf0e10cSrcweir typedef string_container_t::const_iterator string_container_const_iterator_t; 69cdf0e10cSrcweir typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t; 70cdf0e10cSrcweir typedef std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > environment_container_t; 71cdf0e10cSrcweir 72cdf0e10cSrcweir //################################################# 73cdf0e10cSrcweir /* Function object that compares two strings that are 74cdf0e10cSrcweir expected to be environment variables in the form 75cdf0e10cSrcweir "name=value". Only the 'name' part will be compared. 76cdf0e10cSrcweir The comparison is in upper case and returns true 77cdf0e10cSrcweir if the first of both strings is less than the 78cdf0e10cSrcweir second one. */ 79cdf0e10cSrcweir struct less_environment_variable : 80cdf0e10cSrcweir public std::binary_function<rtl::OUString, rtl::OUString, bool> 81cdf0e10cSrcweir { 82cdf0e10cSrcweir bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const 83cdf0e10cSrcweir { 84cdf0e10cSrcweir OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \ 85cdf0e10cSrcweir (rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \ 86cdf0e10cSrcweir "Malformed environment variable"); 87cdf0e10cSrcweir 88cdf0e10cSrcweir // Windows compares environment variables uppercase 89cdf0e10cSrcweir // so we do it, too 90cdf0e10cSrcweir return (rtl_ustr_compare_WithLength( 91cdf0e10cSrcweir lhs.toAsciiUpperCase().pData->buffer, 92cdf0e10cSrcweir lhs.indexOf(NAME_VALUE_SEPARATOR), 93cdf0e10cSrcweir rhs.toAsciiUpperCase().pData->buffer, 94cdf0e10cSrcweir rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0); 95cdf0e10cSrcweir } 96cdf0e10cSrcweir }; 97cdf0e10cSrcweir 98cdf0e10cSrcweir //################################################# 99cdf0e10cSrcweir /* Function object used by for_each algorithm to 100cdf0e10cSrcweir calculate the sum of the length of all strings 101cdf0e10cSrcweir in a string container. */ 102cdf0e10cSrcweir class sum_of_string_lengths 103cdf0e10cSrcweir { 104cdf0e10cSrcweir public: 105cdf0e10cSrcweir //-------------------------------- 106cdf0e10cSrcweir sum_of_string_lengths() : sum_(0) {} 107cdf0e10cSrcweir 108cdf0e10cSrcweir //-------------------------------- 109cdf0e10cSrcweir void operator() (const rtl::OUString& string) 110cdf0e10cSrcweir { 111cdf0e10cSrcweir OSL_ASSERT(string.getLength()); 112cdf0e10cSrcweir 113cdf0e10cSrcweir // always include the terminating '\0' 114cdf0e10cSrcweir if (string.getLength()) 115cdf0e10cSrcweir sum_ += string.getLength() + 1; 116cdf0e10cSrcweir } 117cdf0e10cSrcweir 118cdf0e10cSrcweir //-------------------------------- 119cdf0e10cSrcweir operator size_t () const 120cdf0e10cSrcweir { 121cdf0e10cSrcweir return sum_; 122cdf0e10cSrcweir } 123cdf0e10cSrcweir private: 124cdf0e10cSrcweir size_t sum_; 125cdf0e10cSrcweir }; 126cdf0e10cSrcweir 127cdf0e10cSrcweir //################################################# 128cdf0e10cSrcweir inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont) 129cdf0e10cSrcweir { 130cdf0e10cSrcweir return std::for_each( 131cdf0e10cSrcweir string_cont.begin(), string_cont.end(), sum_of_string_lengths()); 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir //################################################# 135cdf0e10cSrcweir void read_environment(/*out*/ string_container_t* environment) 136cdf0e10cSrcweir { 137cdf0e10cSrcweir // GetEnvironmentStrings returns a sorted list, Windows 138cdf0e10cSrcweir // sorts environment variables upper case 139cdf0e10cSrcweir LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings()); 140cdf0e10cSrcweir LPTSTR p = env; 141cdf0e10cSrcweir 142cdf0e10cSrcweir while (size_t l = _tcslen(p)) 143cdf0e10cSrcweir { 144cdf0e10cSrcweir environment->push_back(reinterpret_cast<const sal_Unicode*>(p)); 145cdf0e10cSrcweir p += l + 1; 146cdf0e10cSrcweir } 147cdf0e10cSrcweir FreeEnvironmentStrings(env); 148cdf0e10cSrcweir } 149cdf0e10cSrcweir 150cdf0e10cSrcweir //################################################# 151cdf0e10cSrcweir /* the environment list must be sorted, new values 152cdf0e10cSrcweir should either replace existing ones or should be 153cdf0e10cSrcweir added to the list, environment variables will 154cdf0e10cSrcweir be handled case-insensitive */ 155cdf0e10cSrcweir bool create_merged_environment( 156cdf0e10cSrcweir rtl_uString* env_vars[], 157cdf0e10cSrcweir sal_uInt32 env_vars_count, 158cdf0e10cSrcweir /*in|out*/ string_container_t* merged_env) 159cdf0e10cSrcweir { 160cdf0e10cSrcweir OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env); 161cdf0e10cSrcweir 162cdf0e10cSrcweir read_environment(merged_env); 163cdf0e10cSrcweir 164cdf0e10cSrcweir for (sal_uInt32 i = 0; i < env_vars_count; i++) 165cdf0e10cSrcweir { 166cdf0e10cSrcweir rtl::OUString env_var = rtl::OUString(env_vars[i]); 167cdf0e10cSrcweir 168cdf0e10cSrcweir if (env_var.getLength() == 0) 169cdf0e10cSrcweir return false; 170cdf0e10cSrcweir 171cdf0e10cSrcweir iterator_pair_t iter_pair = std::equal_range( 172cdf0e10cSrcweir merged_env->begin(), 173cdf0e10cSrcweir merged_env->end(), 174cdf0e10cSrcweir env_var, 175cdf0e10cSrcweir less_environment_variable()); 176cdf0e10cSrcweir 177cdf0e10cSrcweir if (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1) 178cdf0e10cSrcweir { 179cdf0e10cSrcweir merged_env->erase(iter_pair.first, iter_pair.second); 180cdf0e10cSrcweir } 181cdf0e10cSrcweir else 182cdf0e10cSrcweir { 183cdf0e10cSrcweir if (iter_pair.first != iter_pair.second) // found 184cdf0e10cSrcweir *iter_pair.first = env_var; 185cdf0e10cSrcweir else // not found 186cdf0e10cSrcweir merged_env->insert(iter_pair.first, env_var); 187cdf0e10cSrcweir } 188cdf0e10cSrcweir } 189cdf0e10cSrcweir return true; 190cdf0e10cSrcweir } 191cdf0e10cSrcweir 192cdf0e10cSrcweir //################################################# 193cdf0e10cSrcweir /* Create a merged environment */ 194cdf0e10cSrcweir bool setup_process_environment( 195cdf0e10cSrcweir rtl_uString* environment_vars[], 196cdf0e10cSrcweir sal_uInt32 n_environment_vars, 197cdf0e10cSrcweir /*in|out*/ environment_container_t& environment) 198cdf0e10cSrcweir { 199cdf0e10cSrcweir string_container_t merged_env; 200cdf0e10cSrcweir if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env)) 201cdf0e10cSrcweir return false; 202cdf0e10cSrcweir 203cdf0e10cSrcweir // allocate enough space for the '\0'-separated environment strings and 204cdf0e10cSrcweir // a final '\0' 205cdf0e10cSrcweir environment.resize(calc_sum_of_string_lengths(merged_env) + 1); 206cdf0e10cSrcweir 207cdf0e10cSrcweir string_container_const_iterator_t iter = merged_env.begin(); 208cdf0e10cSrcweir string_container_const_iterator_t iter_end = merged_env.end(); 209cdf0e10cSrcweir 210cdf0e10cSrcweir sal_uInt32 pos = 0; 211cdf0e10cSrcweir for (/**/; iter != iter_end; ++iter) 212cdf0e10cSrcweir { 213cdf0e10cSrcweir rtl::OUString envv = *iter; 214cdf0e10cSrcweir 215cdf0e10cSrcweir OSL_ASSERT(envv.getLength()); 216cdf0e10cSrcweir 217cdf0e10cSrcweir sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too 218cdf0e10cSrcweir rtl_copyMemory( 219cdf0e10cSrcweir reinterpret_cast<void*>(&environment[pos]), 220cdf0e10cSrcweir reinterpret_cast<const void*>(envv.getStr()), 221cdf0e10cSrcweir n * sizeof(sal_Unicode)); 222cdf0e10cSrcweir pos += n; 223cdf0e10cSrcweir } 224cdf0e10cSrcweir environment[pos] = 0; // append a final '\0' 225cdf0e10cSrcweir 226cdf0e10cSrcweir return true; 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir //########################################################## 230cdf0e10cSrcweir /* In contrast to the Win32 API function CreatePipe with 231cdf0e10cSrcweir this function the caller is able to determine separately 232cdf0e10cSrcweir which handle of the pipe is inheritable. */ 233cdf0e10cSrcweir bool create_pipe( 234cdf0e10cSrcweir PHANDLE p_read_pipe, 235cdf0e10cSrcweir bool b_read_pipe_inheritable, 236cdf0e10cSrcweir PHANDLE p_write_pipe, 237cdf0e10cSrcweir bool b_write_pipe_inheritable, 238cdf0e10cSrcweir LPVOID p_security_descriptor = NULL, 239cdf0e10cSrcweir DWORD pipe_size = 0) 240cdf0e10cSrcweir { 241cdf0e10cSrcweir SECURITY_ATTRIBUTES sa; 242cdf0e10cSrcweir sa.nLength = sizeof(SECURITY_ATTRIBUTES); 243cdf0e10cSrcweir sa.lpSecurityDescriptor = p_security_descriptor; 244cdf0e10cSrcweir sa.bInheritHandle = b_read_pipe_inheritable || b_write_pipe_inheritable; 245cdf0e10cSrcweir 246cdf0e10cSrcweir BOOL bRet = FALSE; 247cdf0e10cSrcweir HANDLE hTemp = NULL; 248cdf0e10cSrcweir 249cdf0e10cSrcweir if (!b_read_pipe_inheritable && b_write_pipe_inheritable) 250cdf0e10cSrcweir { 251cdf0e10cSrcweir bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size); 252cdf0e10cSrcweir 253cdf0e10cSrcweir if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, 254cdf0e10cSrcweir GetCurrentProcess(), p_read_pipe, 0, FALSE, 255cdf0e10cSrcweir DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) 256cdf0e10cSrcweir { 257cdf0e10cSrcweir CloseHandle(hTemp); 258cdf0e10cSrcweir CloseHandle(*p_read_pipe); 259cdf0e10cSrcweir return false; 260cdf0e10cSrcweir } 261cdf0e10cSrcweir } 262cdf0e10cSrcweir else if (b_read_pipe_inheritable && !b_write_pipe_inheritable) 263cdf0e10cSrcweir { 264cdf0e10cSrcweir bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size); 265cdf0e10cSrcweir 266cdf0e10cSrcweir if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, 267cdf0e10cSrcweir GetCurrentProcess(), p_write_pipe, 0, FALSE, 268cdf0e10cSrcweir DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) 269cdf0e10cSrcweir { 270cdf0e10cSrcweir CloseHandle(hTemp); 271cdf0e10cSrcweir CloseHandle(*p_write_pipe); 272cdf0e10cSrcweir return false; 273cdf0e10cSrcweir } 274cdf0e10cSrcweir } 275cdf0e10cSrcweir else 276cdf0e10cSrcweir { 277cdf0e10cSrcweir bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size); 278cdf0e10cSrcweir } 279cdf0e10cSrcweir return bRet; 280cdf0e10cSrcweir } 281cdf0e10cSrcweir 282cdf0e10cSrcweir //######################################################### 283cdf0e10cSrcweir // Add a quote sign to the start and the end of a string 284cdf0e10cSrcweir // if not already present 285cdf0e10cSrcweir rtl::OUString quote_string(const rtl::OUString& string) 286cdf0e10cSrcweir { 287cdf0e10cSrcweir rtl::OUStringBuffer quoted; 288cdf0e10cSrcweir if (string.indexOf(QUOTE) != 0) 289cdf0e10cSrcweir quoted.append(QUOTE); 290cdf0e10cSrcweir 291cdf0e10cSrcweir quoted.append(string); 292cdf0e10cSrcweir 293cdf0e10cSrcweir if (string.lastIndexOf(QUOTE) != (string.getLength() - 1)) 294cdf0e10cSrcweir quoted.append(QUOTE); 295cdf0e10cSrcweir 296cdf0e10cSrcweir return quoted.makeStringAndClear(); 297cdf0e10cSrcweir } 298cdf0e10cSrcweir 299cdf0e10cSrcweir //The parameter path must be a system path. If it is longer than 260 characters 300cdf0e10cSrcweir //then it is shortened using the GetShortPathName function. This function only 301cdf0e10cSrcweir //works if the path exists. Because "path" can be the path to an executable, it 302cdf0e10cSrcweir //may not have the file extension ".exe". However, if the file on disk has the 303cdf0e10cSrcweir //".exe" extension, then the function will fail. In this case a second attempt 304cdf0e10cSrcweir //is started by adding the parameter "extension" to "path". 305cdf0e10cSrcweir rtl::OUString getShortPath(rtl::OUString const & path, rtl::OUString const & extension) 306cdf0e10cSrcweir { 307cdf0e10cSrcweir rtl::OUString ret(path); 308cdf0e10cSrcweir if (path.getLength() > 260) 309cdf0e10cSrcweir { 310cdf0e10cSrcweir std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec(path.getLength() + 1); 311cdf0e10cSrcweir //GetShortPathNameW only works if the file can be found! 312cdf0e10cSrcweir const DWORD len = GetShortPathNameW( 313cdf0e10cSrcweir reinterpret_cast<LPCWSTR>(path.getStr()), reinterpret_cast<LPWSTR>(&vec[0]), path.getLength() + 1); 314cdf0e10cSrcweir 315cdf0e10cSrcweir if (!len && GetLastError() == ERROR_FILE_NOT_FOUND 316cdf0e10cSrcweir && extension.getLength()) 317cdf0e10cSrcweir { 318cdf0e10cSrcweir const rtl::OUString extPath(path + extension); 319cdf0e10cSrcweir std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec2( 320cdf0e10cSrcweir extPath.getLength() + 1); 321cdf0e10cSrcweir const DWORD len2 = GetShortPathNameW( 322cdf0e10cSrcweir reinterpret_cast<LPCWSTR>(extPath.getStr()), reinterpret_cast<LPWSTR>(&vec2[0]), extPath.getLength() + 1); 323cdf0e10cSrcweir ret = rtl::OUString(&vec2[0], len2); 324cdf0e10cSrcweir } 325cdf0e10cSrcweir else 326cdf0e10cSrcweir { 327cdf0e10cSrcweir ret = rtl::OUString(&vec[0], len); 328cdf0e10cSrcweir } 329cdf0e10cSrcweir } 330cdf0e10cSrcweir return ret; 331cdf0e10cSrcweir } 332cdf0e10cSrcweir //########################################################## 333cdf0e10cSrcweir // Returns the system path of the executable which can either 334cdf0e10cSrcweir // be provided via the strImageName parameter or as first 335cdf0e10cSrcweir // element of the strArguments list. 336cdf0e10cSrcweir // The returned path will be quoted if it contains spaces. 337cdf0e10cSrcweir rtl::OUString get_executable_path( 338cdf0e10cSrcweir rtl_uString* image_name, 339cdf0e10cSrcweir rtl_uString* cmdline_args[], 340cdf0e10cSrcweir sal_uInt32 n_cmdline_args, 341cdf0e10cSrcweir bool search_path) 342cdf0e10cSrcweir { 343cdf0e10cSrcweir rtl::OUString exe_name; 344cdf0e10cSrcweir 345cdf0e10cSrcweir if (image_name) 346cdf0e10cSrcweir exe_name = image_name; 347cdf0e10cSrcweir else if (n_cmdline_args) 348cdf0e10cSrcweir exe_name = rtl::OUString(cmdline_args[0]); 349cdf0e10cSrcweir 350cdf0e10cSrcweir rtl::OUString exe_url = exe_name; 351cdf0e10cSrcweir if (search_path) 352cdf0e10cSrcweir osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData); 353cdf0e10cSrcweir 354cdf0e10cSrcweir rtl::OUString exe_path; 355cdf0e10cSrcweir if (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path)) 356cdf0e10cSrcweir return rtl::OUString(); 357cdf0e10cSrcweir 358cdf0e10cSrcweir exe_path = getShortPath(exe_path, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".exe"))); 359cdf0e10cSrcweir 360cdf0e10cSrcweir if (exe_path.indexOf(' ') != -1) 361cdf0e10cSrcweir exe_path = quote_string(exe_path); 362cdf0e10cSrcweir 363cdf0e10cSrcweir return exe_path; 364cdf0e10cSrcweir } 365cdf0e10cSrcweir 366cdf0e10cSrcweir //########################################################## 367cdf0e10cSrcweir rtl::OUString get_file_extension(const rtl::OUString& file_name) 368cdf0e10cSrcweir { 369cdf0e10cSrcweir sal_Int32 index = file_name.lastIndexOf('.'); 370cdf0e10cSrcweir if ((index != -1) && ((index + 1) < file_name.getLength())) 371cdf0e10cSrcweir return file_name.copy(index + 1); 372cdf0e10cSrcweir 373cdf0e10cSrcweir return rtl::OUString(); 374cdf0e10cSrcweir } 375cdf0e10cSrcweir 376cdf0e10cSrcweir //########################################################## 377cdf0e10cSrcweir bool is_batch_file(const rtl::OUString& file_name) 378cdf0e10cSrcweir { 379cdf0e10cSrcweir rtl::OUString ext = get_file_extension(file_name); 380cdf0e10cSrcweir return (ext.equalsIgnoreAsciiCaseAscii("bat") || 381cdf0e10cSrcweir ext.equalsIgnoreAsciiCaseAscii("cmd") || 382cdf0e10cSrcweir ext.equalsIgnoreAsciiCaseAscii("btm")); 383cdf0e10cSrcweir } 384cdf0e10cSrcweir 385cdf0e10cSrcweir //########################################################## 386cdf0e10cSrcweir rtl::OUString get_batch_processor() 387cdf0e10cSrcweir { 388cdf0e10cSrcweir rtl::OUString comspec; 389cdf0e10cSrcweir osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData); 390cdf0e10cSrcweir 391cdf0e10cSrcweir OSL_ASSERT(comspec.getLength()); 392cdf0e10cSrcweir 393cdf0e10cSrcweir /* check if comspec path contains blanks and quote it if any */ 394cdf0e10cSrcweir if (comspec.indexOf(' ') != -1) 395cdf0e10cSrcweir comspec = quote_string(comspec); 396cdf0e10cSrcweir 397cdf0e10cSrcweir return comspec; 398cdf0e10cSrcweir } 399cdf0e10cSrcweir 400cdf0e10cSrcweir } // namespace private 401cdf0e10cSrcweir 402cdf0e10cSrcweir 403cdf0e10cSrcweir //################################################# 404cdf0e10cSrcweir oslProcessError SAL_CALL osl_executeProcess( 405cdf0e10cSrcweir rtl_uString *strImageName, 406cdf0e10cSrcweir rtl_uString *strArguments[], 407cdf0e10cSrcweir sal_uInt32 nArguments, 408cdf0e10cSrcweir oslProcessOption Options, 409cdf0e10cSrcweir oslSecurity Security, 410cdf0e10cSrcweir rtl_uString *strDirectory, 411cdf0e10cSrcweir rtl_uString *strEnvironmentVars[], 412cdf0e10cSrcweir sal_uInt32 nEnvironmentVars, 413cdf0e10cSrcweir oslProcess *pProcess 414cdf0e10cSrcweir ) 415cdf0e10cSrcweir { 416cdf0e10cSrcweir return osl_executeProcess_WithRedirectedIO( 417cdf0e10cSrcweir strImageName, 418cdf0e10cSrcweir strArguments, 419cdf0e10cSrcweir nArguments, 420cdf0e10cSrcweir Options, 421cdf0e10cSrcweir Security, 422cdf0e10cSrcweir strDirectory, 423cdf0e10cSrcweir strEnvironmentVars, 424cdf0e10cSrcweir nEnvironmentVars, 425cdf0e10cSrcweir pProcess, 426cdf0e10cSrcweir NULL, NULL, NULL ); 427cdf0e10cSrcweir } 428cdf0e10cSrcweir 429cdf0e10cSrcweir //################################################# 430cdf0e10cSrcweir oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( 431cdf0e10cSrcweir rtl_uString *ustrImageName, 432cdf0e10cSrcweir rtl_uString *ustrArguments[], 433cdf0e10cSrcweir sal_uInt32 nArguments, 434cdf0e10cSrcweir oslProcessOption Options, 435cdf0e10cSrcweir oslSecurity Security, 436cdf0e10cSrcweir rtl_uString *ustrDirectory, 437cdf0e10cSrcweir rtl_uString *ustrEnvironmentVars[], 438cdf0e10cSrcweir sal_uInt32 nEnvironmentVars, 439cdf0e10cSrcweir oslProcess *pProcess, 440cdf0e10cSrcweir oslFileHandle *pProcessInputWrite, 441cdf0e10cSrcweir oslFileHandle *pProcessOutputRead, 442cdf0e10cSrcweir oslFileHandle *pProcessErrorRead) 443cdf0e10cSrcweir { 444cdf0e10cSrcweir rtl::OUString exe_path = get_executable_path( 445cdf0e10cSrcweir ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH)); 446cdf0e10cSrcweir 447cdf0e10cSrcweir if (0 == exe_path.getLength()) 448cdf0e10cSrcweir return osl_Process_E_NotFound; 449cdf0e10cSrcweir 450cdf0e10cSrcweir if (pProcess == NULL) 451cdf0e10cSrcweir return osl_Process_E_InvalidError; 452cdf0e10cSrcweir 453cdf0e10cSrcweir DWORD flags = NORMAL_PRIORITY_CLASS; 454cdf0e10cSrcweir rtl::OUStringBuffer command_line; 455cdf0e10cSrcweir 456cdf0e10cSrcweir if (is_batch_file(exe_path)) 457cdf0e10cSrcweir { 458cdf0e10cSrcweir rtl::OUString batch_processor = get_batch_processor(); 459cdf0e10cSrcweir 460cdf0e10cSrcweir if (batch_processor.getLength()) 461cdf0e10cSrcweir { 462cdf0e10cSrcweir /* cmd.exe does not work without a console window */ 463cdf0e10cSrcweir if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED)) 464cdf0e10cSrcweir flags |= CREATE_NEW_CONSOLE; 465cdf0e10cSrcweir 466cdf0e10cSrcweir command_line.append(batch_processor); 467cdf0e10cSrcweir command_line.appendAscii(" /c "); 468cdf0e10cSrcweir } 469cdf0e10cSrcweir else 470cdf0e10cSrcweir // should we return here in case of error? 471cdf0e10cSrcweir return osl_Process_E_Unknown; 472cdf0e10cSrcweir } 473cdf0e10cSrcweir 474cdf0e10cSrcweir command_line.append(exe_path); 475cdf0e10cSrcweir 476cdf0e10cSrcweir /* Add remaining arguments to command line. If ustrImageName is NULL 477cdf0e10cSrcweir the first parameter is the name of the executable so we have to 478cdf0e10cSrcweir start at 1 instead of 0 */ 479cdf0e10cSrcweir for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++) 480cdf0e10cSrcweir { 481cdf0e10cSrcweir command_line.appendAscii(SPACE); 482cdf0e10cSrcweir 483cdf0e10cSrcweir /* Quote arguments containing blanks */ 484cdf0e10cSrcweir if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1) 485cdf0e10cSrcweir command_line.append(quote_string(ustrArguments[n])); 486cdf0e10cSrcweir else 487cdf0e10cSrcweir command_line.append(ustrArguments[n]); 488cdf0e10cSrcweir } 489cdf0e10cSrcweir 490cdf0e10cSrcweir environment_container_t environment; 491cdf0e10cSrcweir LPVOID p_environment = NULL; 492cdf0e10cSrcweir 493cdf0e10cSrcweir if (nEnvironmentVars && ustrEnvironmentVars) 494cdf0e10cSrcweir { 495cdf0e10cSrcweir if (!setup_process_environment( 496cdf0e10cSrcweir ustrEnvironmentVars, nEnvironmentVars, environment)) 497cdf0e10cSrcweir return osl_Process_E_InvalidError; 498cdf0e10cSrcweir 499cdf0e10cSrcweir flags |= CREATE_UNICODE_ENVIRONMENT; 500cdf0e10cSrcweir p_environment = &environment[0]; 501cdf0e10cSrcweir } 502cdf0e10cSrcweir 503cdf0e10cSrcweir rtl::OUString cwd; 504cdf0e10cSrcweir if (ustrDirectory && ustrDirectory->length && (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd))) 505cdf0e10cSrcweir return osl_Process_E_InvalidError; 506cdf0e10cSrcweir 507cdf0e10cSrcweir LPCWSTR p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL; 508cdf0e10cSrcweir 509cdf0e10cSrcweir if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE)) 510cdf0e10cSrcweir flags |= DETACHED_PROCESS; 511cdf0e10cSrcweir 512cdf0e10cSrcweir STARTUPINFO startup_info; 513cdf0e10cSrcweir memset(&startup_info, 0, sizeof(STARTUPINFO)); 514cdf0e10cSrcweir 515cdf0e10cSrcweir startup_info.cb = sizeof(STARTUPINFO); 516cdf0e10cSrcweir startup_info.dwFlags = STARTF_USESHOWWINDOW; 517cdf0e10cSrcweir startup_info.lpDesktop = L""; 518cdf0e10cSrcweir 519cdf0e10cSrcweir /* Create pipes for redirected IO */ 520cdf0e10cSrcweir HANDLE hInputRead = NULL; 521cdf0e10cSrcweir HANDLE hInputWrite = NULL; 522cdf0e10cSrcweir if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false)) 523cdf0e10cSrcweir startup_info.hStdInput = hInputRead; 524cdf0e10cSrcweir 525cdf0e10cSrcweir HANDLE hOutputRead = NULL; 526cdf0e10cSrcweir HANDLE hOutputWrite = NULL; 527cdf0e10cSrcweir if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true)) 528cdf0e10cSrcweir startup_info.hStdOutput = hOutputWrite; 529cdf0e10cSrcweir 530cdf0e10cSrcweir HANDLE hErrorRead = NULL; 531cdf0e10cSrcweir HANDLE hErrorWrite = NULL; 532cdf0e10cSrcweir if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true)) 533cdf0e10cSrcweir startup_info.hStdError = hErrorWrite; 534cdf0e10cSrcweir 535cdf0e10cSrcweir bool b_inherit_handles = false; 536cdf0e10cSrcweir if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead) 537cdf0e10cSrcweir { 538cdf0e10cSrcweir startup_info.dwFlags |= STARTF_USESTDHANDLES; 539cdf0e10cSrcweir b_inherit_handles = true; 540cdf0e10cSrcweir } 541cdf0e10cSrcweir 542cdf0e10cSrcweir switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN)) 543cdf0e10cSrcweir { 544cdf0e10cSrcweir case osl_Process_HIDDEN: 545cdf0e10cSrcweir startup_info.wShowWindow = SW_HIDE; 546cdf0e10cSrcweir flags |= CREATE_NO_WINDOW; // ignored for non-console 547cdf0e10cSrcweir // applications; ignored on 548cdf0e10cSrcweir // Win9x 549cdf0e10cSrcweir break; 550cdf0e10cSrcweir 551cdf0e10cSrcweir case osl_Process_MINIMIZED: 552cdf0e10cSrcweir startup_info.wShowWindow = SW_MINIMIZE; 553cdf0e10cSrcweir break; 554cdf0e10cSrcweir 555cdf0e10cSrcweir case osl_Process_MAXIMIZED: 556cdf0e10cSrcweir case osl_Process_FULLSCREEN: 557cdf0e10cSrcweir startup_info.wShowWindow = SW_MAXIMIZE; 558cdf0e10cSrcweir break; 559cdf0e10cSrcweir 560cdf0e10cSrcweir default: 561cdf0e10cSrcweir startup_info.wShowWindow = SW_NORMAL; 562cdf0e10cSrcweir } 563cdf0e10cSrcweir 564cdf0e10cSrcweir rtl::OUString cmdline = command_line.makeStringAndClear(); 565cdf0e10cSrcweir PROCESS_INFORMATION process_info; 566cdf0e10cSrcweir BOOL bRet = FALSE; 567cdf0e10cSrcweir 568cdf0e10cSrcweir if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL)) 569cdf0e10cSrcweir { 570cdf0e10cSrcweir bRet = CreateProcessAsUser( 571cdf0e10cSrcweir ((oslSecurityImpl*)Security)->m_hToken, 572cdf0e10cSrcweir NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, 573cdf0e10cSrcweir b_inherit_handles, flags, p_environment, p_cwd, 574cdf0e10cSrcweir &startup_info, &process_info); 575cdf0e10cSrcweir } 576cdf0e10cSrcweir else 577cdf0e10cSrcweir { 578cdf0e10cSrcweir bRet = CreateProcess( 579cdf0e10cSrcweir NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, 580cdf0e10cSrcweir b_inherit_handles, flags, p_environment, p_cwd, 581cdf0e10cSrcweir &startup_info, &process_info); 582cdf0e10cSrcweir } 583cdf0e10cSrcweir 584cdf0e10cSrcweir /* Now we can close the pipe ends that are used by the child process */ 585cdf0e10cSrcweir 586cdf0e10cSrcweir if (hInputRead) 587cdf0e10cSrcweir CloseHandle(hInputRead); 588cdf0e10cSrcweir 589cdf0e10cSrcweir if (hOutputWrite) 590cdf0e10cSrcweir CloseHandle(hOutputWrite); 591cdf0e10cSrcweir 592cdf0e10cSrcweir if (hErrorWrite) 593cdf0e10cSrcweir CloseHandle(hErrorWrite); 594cdf0e10cSrcweir 595cdf0e10cSrcweir if (bRet) 596cdf0e10cSrcweir { 597cdf0e10cSrcweir CloseHandle(process_info.hThread); 598cdf0e10cSrcweir 599cdf0e10cSrcweir oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>( 600cdf0e10cSrcweir rtl_allocateMemory(sizeof(oslProcessImpl))); 601cdf0e10cSrcweir 602cdf0e10cSrcweir if (pProcImpl != NULL) 603cdf0e10cSrcweir { 604cdf0e10cSrcweir pProcImpl->m_hProcess = process_info.hProcess; 605cdf0e10cSrcweir pProcImpl->m_IdProcess = process_info.dwProcessId; 606cdf0e10cSrcweir 607cdf0e10cSrcweir *pProcess = (oslProcess)pProcImpl; 608cdf0e10cSrcweir 609cdf0e10cSrcweir if (Options & osl_Process_WAIT) 610cdf0e10cSrcweir WaitForSingleObject(pProcImpl->m_hProcess, INFINITE); 611cdf0e10cSrcweir 612cdf0e10cSrcweir if (pProcessInputWrite) 613cdf0e10cSrcweir *pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write); 614cdf0e10cSrcweir 615cdf0e10cSrcweir if (pProcessOutputRead) 616cdf0e10cSrcweir *pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read); 617cdf0e10cSrcweir 618cdf0e10cSrcweir if (pProcessErrorRead) 619cdf0e10cSrcweir *pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read); 620cdf0e10cSrcweir 621cdf0e10cSrcweir return osl_Process_E_None; 622cdf0e10cSrcweir } 623cdf0e10cSrcweir } 624cdf0e10cSrcweir 625cdf0e10cSrcweir /* if an error occured we have to close the server side pipe ends too */ 626cdf0e10cSrcweir 627cdf0e10cSrcweir if (hInputWrite) 628cdf0e10cSrcweir CloseHandle(hInputWrite); 629cdf0e10cSrcweir 630cdf0e10cSrcweir if (hOutputRead) 631cdf0e10cSrcweir CloseHandle(hOutputRead); 632cdf0e10cSrcweir 633cdf0e10cSrcweir if (hErrorRead) 634cdf0e10cSrcweir CloseHandle(hErrorRead); 635cdf0e10cSrcweir 636cdf0e10cSrcweir return osl_Process_E_Unknown; 637cdf0e10cSrcweir } 638