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