update dev300-m58
[ooovba.git] / sal / osl / w32 / procimpl.cxx
blob875d1a097ab27cad0d082af585c03345a337e77a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: procimpl.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
34 #define UNICODE
35 #define _UNICODE
37 #ifndef WIN32_LEAN_AND_MEAN
38 # define WIN32_LEAN_AND_MEAN
39 # ifdef _MSC_VER
40 # pragma warning(push,1) /* disable warnings within system headers */
41 # endif
42 # include <windows.h>
43 # ifdef _MSC_VER
44 # pragma warning(pop)
45 # endif
46 # include <tchar.h>
47 # undef WIN32_LEAN_AND_MEAN
48 #endif
49 #include "procimpl.h"
50 #include <rtl/ustring.hxx>
51 #include <rtl/ustrbuf.hxx>
52 #include "secimpl.h"
53 #include "rtl/allocator.hxx"
54 #include <osl/file.hxx>
56 #include <list>
57 #include <vector>
58 #include <algorithm>
59 #include <string>
61 //#################################################
62 extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags );
64 //#################################################
65 const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('=');
66 const sal_Char* SPACE = " ";
67 const rtl::OUString ENV_COMSPEC = rtl::OUString::createFromAscii("COMSPEC");
68 const rtl::OUString QUOTE = rtl::OUString::createFromAscii("\"");
70 namespace /* private */
72 //#################################################
73 typedef std::list<rtl::OUString, rtl::Allocator<rtl::OUString> > string_container_t;
74 typedef string_container_t::iterator string_container_iterator_t;
75 typedef string_container_t::const_iterator string_container_const_iterator_t;
76 typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t;
77 typedef std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > environment_container_t;
79 //#################################################
80 /* Function object that compares two strings that are
81 expected to be environment variables in the form
82 "name=value". Only the 'name' part will be compared.
83 The comparison is in upper case and returns true
84 if the first of both strings is less than the
85 second one. */
86 struct less_environment_variable :
87 public std::binary_function<rtl::OUString, rtl::OUString, bool>
89 bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const
91 OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \
92 (rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \
93 "Malformed environment variable");
95 // Windows compares environment variables uppercase
96 // so we do it, too
97 return (rtl_ustr_compare_WithLength(
98 lhs.toAsciiUpperCase().pData->buffer,
99 lhs.indexOf(NAME_VALUE_SEPARATOR),
100 rhs.toAsciiUpperCase().pData->buffer,
101 rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0);
105 //#################################################
106 /* Function object used by for_each algorithm to
107 calculate the sum of the length of all strings
108 in a string container. */
109 class sum_of_string_lengths
111 public:
112 //--------------------------------
113 sum_of_string_lengths() : sum_(0) {}
115 //--------------------------------
116 void operator() (const rtl::OUString& string)
118 OSL_ASSERT(string.getLength());
120 // always include the terminating '\0'
121 if (string.getLength())
122 sum_ += string.getLength() + 1;
125 //--------------------------------
126 operator size_t () const
128 return sum_;
130 private:
131 size_t sum_;
134 //#################################################
135 inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont)
137 return std::for_each(
138 string_cont.begin(), string_cont.end(), sum_of_string_lengths());
141 //#################################################
142 void read_environment(/*out*/ string_container_t* environment)
144 // GetEnvironmentStrings returns a sorted list, Windows
145 // sorts environment variables upper case
146 LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings());
147 LPTSTR p = env;
149 while (size_t l = _tcslen(p))
151 environment->push_back(reinterpret_cast<const sal_Unicode*>(p));
152 p += l + 1;
154 FreeEnvironmentStrings(env);
157 //#################################################
158 /* the environment list must be sorted, new values
159 should either replace existing ones or should be
160 added to the list, environment variables will
161 be handled case-insensitive */
162 bool create_merged_environment(
163 rtl_uString* env_vars[],
164 sal_uInt32 env_vars_count,
165 /*in|out*/ string_container_t* merged_env)
167 OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env);
169 read_environment(merged_env);
171 for (sal_uInt32 i = 0; i < env_vars_count; i++)
173 rtl::OUString env_var = rtl::OUString(env_vars[i]);
175 if ((env_var.getLength() == 0) ||
176 (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1))
177 return false;
179 iterator_pair_t iter_pair = std::equal_range(
180 merged_env->begin(),
181 merged_env->end(),
182 env_var,
183 less_environment_variable());
185 if (iter_pair.first != iter_pair.second) // found
186 *iter_pair.first = env_var;
187 else // not found
188 merged_env->insert(iter_pair.first, env_var);
190 return true;
193 //#################################################
194 /* Create a merged environment */
195 bool setup_process_environment(
196 rtl_uString* environment_vars[],
197 sal_uInt32 n_environment_vars,
198 /*in|out*/ environment_container_t& environment)
200 string_container_t merged_env;
201 if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env))
202 return false;
204 // reserve enough space for the '\0'-separated environment strings and
205 // a final '\0'
206 environment.reserve(calc_sum_of_string_lengths(merged_env) + 1);
208 string_container_const_iterator_t iter = merged_env.begin();
209 string_container_const_iterator_t iter_end = merged_env.end();
211 sal_uInt32 pos = 0;
212 for (/**/; iter != iter_end; ++iter)
214 rtl::OUString envv = *iter;
216 OSL_ASSERT(envv.getLength());
218 sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too
219 rtl_copyMemory(
220 reinterpret_cast<void*>(&environment[pos]),
221 reinterpret_cast<const void*>(envv.getStr()),
222 n * sizeof(sal_Unicode));
223 pos += n;
225 environment[pos] = 0; // append a final '\0'
227 return true;
230 //##########################################################
231 /* In contrast to the Win32 API function CreatePipe with
232 this function the caller is able to determine separately
233 which handle of the pipe is inheritable. */
234 bool create_pipe(
235 PHANDLE p_read_pipe,
236 bool b_read_pipe_inheritable,
237 PHANDLE p_write_pipe,
238 bool b_write_pipe_inheritable,
239 LPVOID p_security_descriptor = NULL,
240 DWORD pipe_size = 0)
242 SECURITY_ATTRIBUTES sa;
243 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
244 sa.lpSecurityDescriptor = p_security_descriptor;
245 sa.bInheritHandle = b_read_pipe_inheritable || b_write_pipe_inheritable;
247 BOOL bRet = FALSE;
248 HANDLE hTemp = NULL;
250 if (!b_read_pipe_inheritable && b_write_pipe_inheritable)
252 bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size);
254 if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
255 GetCurrentProcess(), p_read_pipe, 0, FALSE,
256 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
258 CloseHandle(hTemp);
259 CloseHandle(*p_read_pipe);
260 return false;
263 else if (b_read_pipe_inheritable && !b_write_pipe_inheritable)
265 bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size);
267 if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
268 GetCurrentProcess(), p_write_pipe, 0, FALSE,
269 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
271 CloseHandle(hTemp);
272 CloseHandle(*p_write_pipe);
273 return false;
276 else
278 bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size);
280 return bRet;
283 //#########################################################
284 // Add a quote sign to the start and the end of a string
285 // if not already present
286 rtl::OUString quote_string(const rtl::OUString& string)
288 rtl::OUStringBuffer quoted;
289 if (string.indexOf(QUOTE) != 0)
290 quoted.append(QUOTE);
292 quoted.append(string);
294 if (string.lastIndexOf(QUOTE) != (string.getLength() - 1))
295 quoted.append(QUOTE);
297 return quoted.makeStringAndClear();
300 //##########################################################
301 // Returns the system path of the executable which can either
302 // be provided via the strImageName parameter or as first
303 // element of the strArguments list.
304 // The returned path will be quoted if it contains spaces.
305 rtl::OUString get_executable_path(
306 rtl_uString* image_name,
307 rtl_uString* cmdline_args[],
308 sal_uInt32 n_cmdline_args,
309 bool search_path)
311 rtl::OUString exe_name;
313 if (image_name)
314 exe_name = image_name;
315 else if (n_cmdline_args)
316 exe_name = rtl::OUString(cmdline_args[0]);
318 rtl::OUString exe_url = exe_name;
319 if (search_path)
320 osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData);
322 rtl::OUString exe_path;
323 if (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path))
324 return rtl::OUString();
326 if (exe_path.indexOf(' ') != -1)
327 exe_path = quote_string(exe_path);
329 return exe_path;
332 //##########################################################
333 rtl::OUString get_file_extension(const rtl::OUString& file_name)
335 sal_Int32 index = file_name.lastIndexOf('.');
336 if ((index != -1) && ((index + 1) < file_name.getLength()))
337 return file_name.copy(index + 1);
339 return rtl::OUString();
342 //##########################################################
343 bool is_batch_file(const rtl::OUString& file_name)
345 rtl::OUString ext = get_file_extension(file_name);
346 return (ext.equalsIgnoreAsciiCaseAscii("bat") ||
347 ext.equalsIgnoreAsciiCaseAscii("cmd") ||
348 ext.equalsIgnoreAsciiCaseAscii("btm"));
351 //##########################################################
352 rtl::OUString get_batch_processor()
354 rtl::OUString comspec;
355 osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData);
357 OSL_ASSERT(comspec.getLength());
359 /* check if comspec path contains blanks and quote it if any */
360 if (comspec.indexOf(' ') != -1)
361 comspec = quote_string(comspec);
363 return comspec;
366 } // namespace private
369 //#################################################
370 oslProcessError SAL_CALL osl_executeProcess(
371 rtl_uString *strImageName,
372 rtl_uString *strArguments[],
373 sal_uInt32 nArguments,
374 oslProcessOption Options,
375 oslSecurity Security,
376 rtl_uString *strDirectory,
377 rtl_uString *strEnvironmentVars[],
378 sal_uInt32 nEnvironmentVars,
379 oslProcess *pProcess
382 return osl_executeProcess_WithRedirectedIO(
383 strImageName,
384 strArguments,
385 nArguments,
386 Options,
387 Security,
388 strDirectory,
389 strEnvironmentVars,
390 nEnvironmentVars,
391 pProcess,
392 NULL, NULL, NULL );
395 //#################################################
396 oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
397 rtl_uString *ustrImageName,
398 rtl_uString *ustrArguments[],
399 sal_uInt32 nArguments,
400 oslProcessOption Options,
401 oslSecurity Security,
402 rtl_uString *ustrDirectory,
403 rtl_uString *ustrEnvironmentVars[],
404 sal_uInt32 nEnvironmentVars,
405 oslProcess *pProcess,
406 oslFileHandle *pProcessInputWrite,
407 oslFileHandle *pProcessOutputRead,
408 oslFileHandle *pProcessErrorRead)
410 rtl::OUString exe_path = get_executable_path(
411 ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH));
413 if (0 == exe_path.getLength())
414 return osl_Process_E_NotFound;
416 if (pProcess == NULL)
417 return osl_Process_E_InvalidError;
419 DWORD flags = NORMAL_PRIORITY_CLASS;
420 rtl::OUStringBuffer command_line;
422 if (is_batch_file(exe_path))
424 rtl::OUString batch_processor = get_batch_processor();
426 if (batch_processor.getLength())
428 /* cmd.exe does not work without a console window */
429 if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED))
430 flags |= CREATE_NEW_CONSOLE;
432 command_line.append(batch_processor);
433 command_line.appendAscii(" /c ");
435 else
436 // should we return here in case of error?
437 return osl_Process_E_Unknown;
440 command_line.append(exe_path);
442 /* Add remaining arguments to command line. If ustrImageName is NULL
443 the first parameter is the name of the executable so we have to
444 start at 1 instead of 0 */
445 for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++)
447 command_line.appendAscii(SPACE);
449 /* Quote arguments containing blanks */
450 if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1)
451 command_line.append(quote_string(ustrArguments[n]));
452 else
453 command_line.append(ustrArguments[n]);
456 environment_container_t environment;
457 LPVOID p_environment = NULL;
459 if (nEnvironmentVars && ustrEnvironmentVars)
461 if (!setup_process_environment(
462 ustrEnvironmentVars, nEnvironmentVars, environment))
463 return osl_Process_E_InvalidError;
465 flags |= CREATE_UNICODE_ENVIRONMENT;
466 p_environment = &environment[0];
469 rtl::OUString cwd;
470 if (ustrDirectory && ustrDirectory->length && (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd)))
471 return osl_Process_E_InvalidError;
473 LPCWSTR p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL;
475 if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE))
476 flags |= DETACHED_PROCESS;
478 STARTUPINFO startup_info;
479 memset(&startup_info, 0, sizeof(STARTUPINFO));
481 startup_info.cb = sizeof(STARTUPINFO);
482 startup_info.dwFlags = STARTF_USESHOWWINDOW;
483 startup_info.lpDesktop = L"";
485 /* Create pipes for redirected IO */
486 HANDLE hInputRead = NULL;
487 HANDLE hInputWrite = NULL;
488 if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false))
489 startup_info.hStdInput = hInputRead;
491 HANDLE hOutputRead = NULL;
492 HANDLE hOutputWrite = NULL;
493 if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true))
494 startup_info.hStdOutput = hOutputWrite;
496 HANDLE hErrorRead = NULL;
497 HANDLE hErrorWrite = NULL;
498 if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true))
499 startup_info.hStdError = hErrorWrite;
501 bool b_inherit_handles = false;
502 if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead)
504 startup_info.dwFlags |= STARTF_USESTDHANDLES;
505 b_inherit_handles = true;
508 switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN))
510 case osl_Process_HIDDEN:
511 startup_info.wShowWindow = SW_HIDE;
512 flags |= CREATE_NO_WINDOW; // ignored for non-console
513 // applications; ignored on
514 // Win9x
515 break;
517 case osl_Process_MINIMIZED:
518 startup_info.wShowWindow = SW_MINIMIZE;
519 break;
521 case osl_Process_MAXIMIZED:
522 case osl_Process_FULLSCREEN:
523 startup_info.wShowWindow = SW_MAXIMIZE;
524 break;
526 default:
527 startup_info.wShowWindow = SW_NORMAL;
530 rtl::OUString cmdline = command_line.makeStringAndClear();
531 PROCESS_INFORMATION process_info;
532 BOOL bRet = FALSE;
534 if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL))
536 bRet = CreateProcessAsUser(
537 ((oslSecurityImpl*)Security)->m_hToken,
538 NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL,
539 b_inherit_handles, flags, p_environment, p_cwd,
540 &startup_info, &process_info);
542 else
544 bRet = CreateProcess(
545 NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL,
546 b_inherit_handles, flags, p_environment, p_cwd,
547 &startup_info, &process_info);
550 /* Now we can close the pipe ends that are used by the child process */
552 if (hInputRead)
553 CloseHandle(hInputRead);
555 if (hOutputWrite)
556 CloseHandle(hOutputWrite);
558 if (hErrorWrite)
559 CloseHandle(hErrorWrite);
561 if (bRet)
563 CloseHandle(process_info.hThread);
565 oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>(
566 rtl_allocateMemory(sizeof(oslProcessImpl)));
568 if (pProcImpl != NULL)
570 pProcImpl->m_hProcess = process_info.hProcess;
571 pProcImpl->m_IdProcess = process_info.dwProcessId;
573 *pProcess = (oslProcess)pProcImpl;
575 if (Options & osl_Process_WAIT)
576 WaitForSingleObject(pProcImpl->m_hProcess, INFINITE);
578 if (pProcessInputWrite)
579 *pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write);
581 if (pProcessOutputRead)
582 *pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read);
584 if (pProcessErrorRead)
585 *pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read);
587 return osl_Process_E_None;
591 /* if an error occured we have to close the server side pipe ends too */
593 if (hInputWrite)
594 CloseHandle(hInputWrite);
596 if (hOutputRead)
597 CloseHandle(hOutputRead);
599 if (hErrorRead)
600 CloseHandle(hErrorRead);
602 return osl_Process_E_Unknown;