73342dbb82
A final pass through the code, converting code to use the new OUString and OString methods that can detect string literals. Change-Id: Ifa6382335e5650a1c67e52006b26354e0692c710
634 lines
21 KiB
C++
634 lines
21 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# ifdef _MSC_VER
|
|
# pragma warning(push,1) /* disable warnings within system headers */
|
|
# endif
|
|
# include <windows.h>
|
|
# ifdef _MSC_VER
|
|
# pragma warning(pop)
|
|
# endif
|
|
# include <tchar.h>
|
|
# undef WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include "procimpl.h"
|
|
#include <rtl/ustring.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include "secimpl.h"
|
|
#include "rtl/allocator.hxx"
|
|
#include <osl/file.hxx>
|
|
|
|
#include <list>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <string.h>
|
|
|
|
//#################################################
|
|
extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags );
|
|
|
|
//#################################################
|
|
const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('=');
|
|
const sal_Char* SPACE = " ";
|
|
const rtl::OUString ENV_COMSPEC ("COMSPEC");
|
|
const rtl::OUString QUOTE("\"");
|
|
|
|
namespace /* private */
|
|
{
|
|
//#################################################
|
|
typedef std::list<rtl::OUString> string_container_t;
|
|
typedef string_container_t::iterator string_container_iterator_t;
|
|
typedef string_container_t::const_iterator string_container_const_iterator_t;
|
|
typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t;
|
|
typedef std::vector<sal_Unicode> environment_container_t;
|
|
|
|
//#################################################
|
|
/* Function object that compares two strings that are
|
|
expected to be environment variables in the form
|
|
"name=value". Only the 'name' part will be compared.
|
|
The comparison is in upper case and returns true
|
|
if the first of both strings is less than the
|
|
second one. */
|
|
struct less_environment_variable :
|
|
public std::binary_function<rtl::OUString, rtl::OUString, bool>
|
|
{
|
|
bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const
|
|
{
|
|
OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \
|
|
(rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \
|
|
"Malformed environment variable");
|
|
|
|
// Windows compares environment variables uppercase
|
|
// so we do it, too
|
|
return (rtl_ustr_compare_WithLength(
|
|
lhs.toAsciiUpperCase().pData->buffer,
|
|
lhs.indexOf(NAME_VALUE_SEPARATOR),
|
|
rhs.toAsciiUpperCase().pData->buffer,
|
|
rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0);
|
|
}
|
|
};
|
|
|
|
//#################################################
|
|
/* Function object used by for_each algorithm to
|
|
calculate the sum of the length of all strings
|
|
in a string container. */
|
|
class sum_of_string_lengths
|
|
{
|
|
public:
|
|
//--------------------------------
|
|
sum_of_string_lengths() : sum_(0) {}
|
|
|
|
//--------------------------------
|
|
void operator() (const rtl::OUString& string)
|
|
{
|
|
OSL_ASSERT(string.getLength());
|
|
|
|
// always include the terminating '\0'
|
|
if (string.getLength())
|
|
sum_ += string.getLength() + 1;
|
|
}
|
|
|
|
//--------------------------------
|
|
operator size_t () const
|
|
{
|
|
return sum_;
|
|
}
|
|
private:
|
|
size_t sum_;
|
|
};
|
|
|
|
//#################################################
|
|
inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont)
|
|
{
|
|
return std::for_each(
|
|
string_cont.begin(), string_cont.end(), sum_of_string_lengths());
|
|
}
|
|
|
|
//#################################################
|
|
void read_environment(/*out*/ string_container_t* environment)
|
|
{
|
|
// GetEnvironmentStrings returns a sorted list, Windows
|
|
// sorts environment variables upper case
|
|
LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings());
|
|
LPTSTR p = env;
|
|
|
|
while (size_t l = _tcslen(p))
|
|
{
|
|
environment->push_back(reinterpret_cast<const sal_Unicode*>(p));
|
|
p += l + 1;
|
|
}
|
|
FreeEnvironmentStrings(env);
|
|
}
|
|
|
|
//#################################################
|
|
/* the environment list must be sorted, new values
|
|
should either replace existing ones or should be
|
|
added to the list, environment variables will
|
|
be handled case-insensitive */
|
|
bool create_merged_environment(
|
|
rtl_uString* env_vars[],
|
|
sal_uInt32 env_vars_count,
|
|
/*in|out*/ string_container_t* merged_env)
|
|
{
|
|
OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env);
|
|
|
|
read_environment(merged_env);
|
|
|
|
for (sal_uInt32 i = 0; i < env_vars_count; i++)
|
|
{
|
|
rtl::OUString env_var = rtl::OUString(env_vars[i]);
|
|
|
|
if (env_var.getLength() == 0)
|
|
return false;
|
|
|
|
iterator_pair_t iter_pair = std::equal_range(
|
|
merged_env->begin(),
|
|
merged_env->end(),
|
|
env_var,
|
|
less_environment_variable());
|
|
|
|
if (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1)
|
|
{
|
|
merged_env->erase(iter_pair.first, iter_pair.second);
|
|
}
|
|
else
|
|
{
|
|
if (iter_pair.first != iter_pair.second) // found
|
|
*iter_pair.first = env_var;
|
|
else // not found
|
|
merged_env->insert(iter_pair.first, env_var);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//#################################################
|
|
/* Create a merged environment */
|
|
bool setup_process_environment(
|
|
rtl_uString* environment_vars[],
|
|
sal_uInt32 n_environment_vars,
|
|
/*in|out*/ environment_container_t& environment)
|
|
{
|
|
string_container_t merged_env;
|
|
if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env))
|
|
return false;
|
|
|
|
// allocate enough space for the '\0'-separated environment strings and
|
|
// a final '\0'
|
|
environment.resize(calc_sum_of_string_lengths(merged_env) + 1);
|
|
|
|
string_container_const_iterator_t iter = merged_env.begin();
|
|
string_container_const_iterator_t iter_end = merged_env.end();
|
|
|
|
sal_uInt32 pos = 0;
|
|
for (/**/; iter != iter_end; ++iter)
|
|
{
|
|
rtl::OUString envv = *iter;
|
|
|
|
OSL_ASSERT(envv.getLength());
|
|
|
|
sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too
|
|
memcpy(
|
|
reinterpret_cast<void*>(&environment[pos]),
|
|
reinterpret_cast<const void*>(envv.getStr()),
|
|
n * sizeof(sal_Unicode));
|
|
pos += n;
|
|
}
|
|
environment[pos] = 0; // append a final '\0'
|
|
|
|
return true;
|
|
}
|
|
|
|
//##########################################################
|
|
/* In contrast to the Win32 API function CreatePipe with
|
|
this function the caller is able to determine separately
|
|
which handle of the pipe is inheritable. */
|
|
bool 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)
|
|
{
|
|
SECURITY_ATTRIBUTES sa;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = p_security_descriptor;
|
|
sa.bInheritHandle = b_read_pipe_inheritable || b_write_pipe_inheritable;
|
|
|
|
BOOL bRet = FALSE;
|
|
HANDLE hTemp = NULL;
|
|
|
|
if (!b_read_pipe_inheritable && b_write_pipe_inheritable)
|
|
{
|
|
bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size);
|
|
|
|
if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
|
|
GetCurrentProcess(), p_read_pipe, 0, FALSE,
|
|
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
|
|
{
|
|
CloseHandle(hTemp);
|
|
CloseHandle(*p_read_pipe);
|
|
return false;
|
|
}
|
|
}
|
|
else if (b_read_pipe_inheritable && !b_write_pipe_inheritable)
|
|
{
|
|
bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size);
|
|
|
|
if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
|
|
GetCurrentProcess(), p_write_pipe, 0, FALSE,
|
|
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
|
|
{
|
|
CloseHandle(hTemp);
|
|
CloseHandle(*p_write_pipe);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//#########################################################
|
|
// Add a quote sign to the start and the end of a string
|
|
// if not already present
|
|
rtl::OUString quote_string(const rtl::OUString& string)
|
|
{
|
|
rtl::OUStringBuffer quoted;
|
|
if (string.indexOf(QUOTE) != 0)
|
|
quoted.append(QUOTE);
|
|
|
|
quoted.append(string);
|
|
|
|
if (string.lastIndexOf(QUOTE) != (string.getLength() - 1))
|
|
quoted.append(QUOTE);
|
|
|
|
return quoted.makeStringAndClear();
|
|
}
|
|
|
|
//The parameter path must be a system path. If it is longer than 260 characters
|
|
//then it is shortened using the GetShortPathName function. This function only
|
|
//works if the path exists. Because "path" can be the path to an executable, it
|
|
//may not have the file extension ".exe". However, if the file on disk has the
|
|
//".exe" extension, then the function will fail. In this case a second attempt
|
|
//is started by adding the parameter "extension" to "path".
|
|
rtl::OUString getShortPath(rtl::OUString const & path, rtl::OUString const & extension)
|
|
{
|
|
rtl::OUString ret(path);
|
|
if (path.getLength() > 260)
|
|
{
|
|
std::vector<sal_Unicode> vec(path.getLength() + 1);
|
|
//GetShortPathNameW only works if the file can be found!
|
|
const DWORD len = GetShortPathNameW(
|
|
reinterpret_cast<LPCWSTR>(path.getStr()), reinterpret_cast<LPWSTR>(&vec[0]), path.getLength() + 1);
|
|
|
|
if (!len && GetLastError() == ERROR_FILE_NOT_FOUND
|
|
&& extension.getLength())
|
|
{
|
|
const rtl::OUString extPath(path + extension);
|
|
std::vector<sal_Unicode> vec2(
|
|
extPath.getLength() + 1);
|
|
const DWORD len2 = GetShortPathNameW(
|
|
reinterpret_cast<LPCWSTR>(extPath.getStr()), reinterpret_cast<LPWSTR>(&vec2[0]), extPath.getLength() + 1);
|
|
ret = rtl::OUString(&vec2[0], len2);
|
|
}
|
|
else
|
|
{
|
|
ret = rtl::OUString(&vec[0], len);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
//##########################################################
|
|
// Returns the system path of the executable which can either
|
|
// be provided via the strImageName parameter or as first
|
|
// element of the strArguments list.
|
|
// The returned path will be quoted if it contains spaces.
|
|
rtl::OUString get_executable_path(
|
|
rtl_uString* image_name,
|
|
rtl_uString* cmdline_args[],
|
|
sal_uInt32 n_cmdline_args,
|
|
bool search_path)
|
|
{
|
|
rtl::OUString exe_name;
|
|
|
|
if (image_name)
|
|
exe_name = image_name;
|
|
else if (n_cmdline_args)
|
|
exe_name = rtl::OUString(cmdline_args[0]);
|
|
|
|
rtl::OUString exe_url = exe_name;
|
|
if (search_path)
|
|
osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData);
|
|
|
|
rtl::OUString exe_path;
|
|
if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path))
|
|
return rtl::OUString();
|
|
|
|
exe_path = getShortPath(exe_path, rtl::OUString(".exe"));
|
|
|
|
if (exe_path.indexOf(' ') != -1)
|
|
exe_path = quote_string(exe_path);
|
|
|
|
return exe_path;
|
|
}
|
|
|
|
//##########################################################
|
|
rtl::OUString get_file_extension(const rtl::OUString& file_name)
|
|
{
|
|
sal_Int32 index = file_name.lastIndexOf('.');
|
|
if ((index != -1) && ((index + 1) < file_name.getLength()))
|
|
return file_name.copy(index + 1);
|
|
|
|
return rtl::OUString();
|
|
}
|
|
|
|
//##########################################################
|
|
bool is_batch_file(const rtl::OUString& file_name)
|
|
{
|
|
rtl::OUString ext = get_file_extension(file_name);
|
|
return (ext.equalsIgnoreAsciiCase("bat") ||
|
|
ext.equalsIgnoreAsciiCase("cmd") ||
|
|
ext.equalsIgnoreAsciiCase("btm"));
|
|
}
|
|
|
|
//##########################################################
|
|
rtl::OUString get_batch_processor()
|
|
{
|
|
rtl::OUString comspec;
|
|
osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData);
|
|
|
|
OSL_ASSERT(comspec.getLength());
|
|
|
|
/* check if comspec path contains blanks and quote it if any */
|
|
if (comspec.indexOf(' ') != -1)
|
|
comspec = quote_string(comspec);
|
|
|
|
return comspec;
|
|
}
|
|
|
|
} // namespace private
|
|
|
|
|
|
//#################################################
|
|
oslProcessError SAL_CALL 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
|
|
)
|
|
{
|
|
return osl_executeProcess_WithRedirectedIO(
|
|
strImageName,
|
|
strArguments,
|
|
nArguments,
|
|
Options,
|
|
Security,
|
|
strDirectory,
|
|
strEnvironmentVars,
|
|
nEnvironmentVars,
|
|
pProcess,
|
|
NULL, NULL, NULL );
|
|
}
|
|
|
|
//#################################################
|
|
oslProcessError SAL_CALL 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)
|
|
{
|
|
rtl::OUString exe_path = get_executable_path(
|
|
ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH));
|
|
|
|
if (0 == exe_path.getLength())
|
|
return osl_Process_E_NotFound;
|
|
|
|
if (pProcess == NULL)
|
|
return osl_Process_E_InvalidError;
|
|
|
|
DWORD flags = NORMAL_PRIORITY_CLASS;
|
|
rtl::OUStringBuffer command_line;
|
|
|
|
if (is_batch_file(exe_path))
|
|
{
|
|
rtl::OUString batch_processor = get_batch_processor();
|
|
|
|
if (batch_processor.getLength())
|
|
{
|
|
/* cmd.exe does not work without a console window */
|
|
if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED))
|
|
flags |= CREATE_NEW_CONSOLE;
|
|
|
|
command_line.append(batch_processor);
|
|
command_line.appendAscii(" /c ");
|
|
}
|
|
else
|
|
// should we return here in case of error?
|
|
return osl_Process_E_Unknown;
|
|
}
|
|
|
|
command_line.append(exe_path);
|
|
|
|
/* Add remaining arguments to command line. If ustrImageName is NULL
|
|
the first parameter is the name of the executable so we have to
|
|
start at 1 instead of 0 */
|
|
for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++)
|
|
{
|
|
command_line.appendAscii(SPACE);
|
|
|
|
/* Quote arguments containing blanks */
|
|
if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1)
|
|
command_line.append(quote_string(ustrArguments[n]));
|
|
else
|
|
command_line.append(ustrArguments[n]);
|
|
}
|
|
|
|
environment_container_t environment;
|
|
LPVOID p_environment = NULL;
|
|
|
|
if (nEnvironmentVars && ustrEnvironmentVars)
|
|
{
|
|
if (!setup_process_environment(
|
|
ustrEnvironmentVars, nEnvironmentVars, environment))
|
|
return osl_Process_E_InvalidError;
|
|
|
|
flags |= CREATE_UNICODE_ENVIRONMENT;
|
|
p_environment = &environment[0];
|
|
}
|
|
|
|
rtl::OUString cwd;
|
|
if (ustrDirectory && ustrDirectory->length && (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd)))
|
|
return osl_Process_E_InvalidError;
|
|
|
|
LPCWSTR p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL;
|
|
|
|
if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE))
|
|
flags |= DETACHED_PROCESS;
|
|
|
|
STARTUPINFO startup_info;
|
|
memset(&startup_info, 0, sizeof(STARTUPINFO));
|
|
|
|
startup_info.cb = sizeof(STARTUPINFO);
|
|
startup_info.dwFlags = STARTF_USESHOWWINDOW;
|
|
startup_info.lpDesktop = const_cast<LPWSTR>(L"");
|
|
|
|
/* Create pipes for redirected IO */
|
|
HANDLE hInputRead = NULL;
|
|
HANDLE hInputWrite = NULL;
|
|
if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false))
|
|
startup_info.hStdInput = hInputRead;
|
|
|
|
HANDLE hOutputRead = NULL;
|
|
HANDLE hOutputWrite = NULL;
|
|
if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true))
|
|
startup_info.hStdOutput = hOutputWrite;
|
|
|
|
HANDLE hErrorRead = NULL;
|
|
HANDLE hErrorWrite = NULL;
|
|
if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true))
|
|
startup_info.hStdError = hErrorWrite;
|
|
|
|
bool b_inherit_handles = false;
|
|
if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead)
|
|
{
|
|
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
|
b_inherit_handles = true;
|
|
}
|
|
|
|
switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN))
|
|
{
|
|
case osl_Process_HIDDEN:
|
|
startup_info.wShowWindow = SW_HIDE;
|
|
flags |= CREATE_NO_WINDOW; // ignored for non-console
|
|
// applications; ignored on
|
|
// Win9x
|
|
break;
|
|
|
|
case osl_Process_MINIMIZED:
|
|
startup_info.wShowWindow = SW_MINIMIZE;
|
|
break;
|
|
|
|
case osl_Process_MAXIMIZED:
|
|
case osl_Process_FULLSCREEN:
|
|
startup_info.wShowWindow = SW_MAXIMIZE;
|
|
break;
|
|
|
|
default:
|
|
startup_info.wShowWindow = SW_NORMAL;
|
|
}
|
|
|
|
rtl::OUString cmdline = command_line.makeStringAndClear();
|
|
PROCESS_INFORMATION process_info;
|
|
BOOL bRet = FALSE;
|
|
|
|
if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL))
|
|
{
|
|
bRet = CreateProcessAsUser(
|
|
((oslSecurityImpl*)Security)->m_hToken,
|
|
NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL,
|
|
b_inherit_handles, flags, p_environment, p_cwd,
|
|
&startup_info, &process_info);
|
|
}
|
|
else
|
|
{
|
|
bRet = CreateProcess(
|
|
NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL,
|
|
b_inherit_handles, flags, p_environment, p_cwd,
|
|
&startup_info, &process_info);
|
|
}
|
|
|
|
/* Now we can close the pipe ends that are used by the child process */
|
|
|
|
if (hInputRead)
|
|
CloseHandle(hInputRead);
|
|
|
|
if (hOutputWrite)
|
|
CloseHandle(hOutputWrite);
|
|
|
|
if (hErrorWrite)
|
|
CloseHandle(hErrorWrite);
|
|
|
|
if (bRet)
|
|
{
|
|
CloseHandle(process_info.hThread);
|
|
|
|
oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>(
|
|
rtl_allocateMemory(sizeof(oslProcessImpl)));
|
|
|
|
if (pProcImpl != NULL)
|
|
{
|
|
pProcImpl->m_hProcess = process_info.hProcess;
|
|
pProcImpl->m_IdProcess = process_info.dwProcessId;
|
|
|
|
*pProcess = (oslProcess)pProcImpl;
|
|
|
|
if (Options & osl_Process_WAIT)
|
|
WaitForSingleObject(pProcImpl->m_hProcess, INFINITE);
|
|
|
|
if (pProcessInputWrite)
|
|
*pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write);
|
|
|
|
if (pProcessOutputRead)
|
|
*pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read);
|
|
|
|
if (pProcessErrorRead)
|
|
*pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read);
|
|
|
|
return osl_Process_E_None;
|
|
}
|
|
}
|
|
|
|
/* if an error occurred we have to close the server side pipe ends too */
|
|
|
|
if (hInputWrite)
|
|
CloseHandle(hInputWrite);
|
|
|
|
if (hOutputRead)
|
|
CloseHandle(hOutputRead);
|
|
|
|
if (hErrorRead)
|
|
CloseHandle(hErrorRead);
|
|
|
|
return osl_Process_E_Unknown;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|