Add support for specifying child process cwd and env to wxExecute().

Add an optional wxExecuteEnv parameter to wxExecute() which allows to specify
the initial working directory and custom environment for the child process.

Closes #12163.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65896 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-10-24 22:40:11 +00:00
parent fab8784c71
commit 164db92c14
11 changed files with 424 additions and 43 deletions

View File

@@ -405,6 +405,7 @@ Major new features in this release
All: All:
- Added cwd and env arguments to wxExecute() (Emilien Kia).
- Added "rest" argument to wxString::Before{First,Last}(). - Added "rest" argument to wxString::Before{First,Last}().
- Added wxThread::OnKill() and OnDelete() callbacks. - Added wxThread::OnKill() and OnDelete() callbacks.

View File

@@ -19,6 +19,7 @@
#include "wx/object.h" #include "wx/object.h"
#include "wx/list.h" #include "wx/list.h"
#include "wx/filefn.h" #include "wx/filefn.h"
#include "wx/hashmap.h"
#if wxUSE_GUI #if wxUSE_GUI
#include "wx/gdicmn.h" #include "wx/gdicmn.h"
@@ -313,6 +314,17 @@ enum
wxEXEC_BLOCK = wxEXEC_SYNC | wxEXEC_NOEVENTS wxEXEC_BLOCK = wxEXEC_SYNC | wxEXEC_NOEVENTS
}; };
// Map storing environment variables.
typedef wxStringToStringHashMap wxEnvVariableHashMap;
// Used to pass additional parameters for child process to wxExecute(). Could
// be extended with other fields later.
struct wxExecuteEnv
{
wxString cwd; // If empty, CWD is not changed.
wxEnvVariableHashMap env; // If empty, environment is unchanged.
};
// Execute another program. // Execute another program.
// //
// If flags contain wxEXEC_SYNC, return -1 on failure and the exit code of the // If flags contain wxEXEC_SYNC, return -1 on failure and the exit code of the
@@ -320,27 +332,32 @@ enum
// failure and the PID of the launched process if ok. // failure and the PID of the launched process if ok.
WXDLLIMPEXP_BASE long wxExecute(const wxString& command, WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
int flags = wxEXEC_ASYNC, int flags = wxEXEC_ASYNC,
wxProcess *process = NULL); wxProcess *process = NULL,
const wxExecuteEnv *env = NULL);
WXDLLIMPEXP_BASE long wxExecute(char **argv, WXDLLIMPEXP_BASE long wxExecute(char **argv,
int flags = wxEXEC_ASYNC, int flags = wxEXEC_ASYNC,
wxProcess *process = NULL); wxProcess *process = NULL,
const wxExecuteEnv *env = NULL);
#if wxUSE_UNICODE #if wxUSE_UNICODE
WXDLLIMPEXP_BASE long wxExecute(wchar_t **argv, WXDLLIMPEXP_BASE long wxExecute(wchar_t **argv,
int flags = wxEXEC_ASYNC, int flags = wxEXEC_ASYNC,
wxProcess *process = NULL); wxProcess *process = NULL,
const wxExecuteEnv *env = NULL);
#endif // wxUSE_UNICODE #endif // wxUSE_UNICODE
// execute the command capturing its output into an array line by line, this is // execute the command capturing its output into an array line by line, this is
// always synchronous // always synchronous
WXDLLIMPEXP_BASE long wxExecute(const wxString& command, WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
wxArrayString& output, wxArrayString& output,
int flags = 0); int flags = 0,
const wxExecuteEnv *env = NULL);
// also capture stderr (also synchronous) // also capture stderr (also synchronous)
WXDLLIMPEXP_BASE long wxExecute(const wxString& command, WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
wxArrayString& output, wxArrayString& output,
wxArrayString& error, wxArrayString& error,
int flags = 0); int flags = 0,
const wxExecuteEnv *env = NULL);
#if defined(__WXMSW__) && wxUSE_IPC #if defined(__WXMSW__) && wxUSE_IPC
// ask a DDE server to execute the DDE request with given parameters // ask a DDE server to execute the DDE request with given parameters
@@ -479,6 +496,10 @@ inline bool wxSetEnv(const wxString& var, int value)
} }
#endif // WXWIN_COMPATIBILITY_2_8 #endif // WXWIN_COMPATIBILITY_2_8
// Retrieve the complete environment by filling specified map.
// Returns true on success or false if an error occurred.
WXDLLIMPEXP_BASE bool wxGetEnvMap(wxEnvVariableHashMap *map);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Network and username functions. // Network and username functions.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -157,6 +157,18 @@ void wxInfoMessageBox(wxWindow parent = NULL);
/** @addtogroup group_funcmacro_env */ /** @addtogroup group_funcmacro_env */
//@{ //@{
/**
A map type containing environment variables names and values.
This type is used with wxGetEnvMap() function and wxExecuteEnv structure
optionally passed to wxExecute().
@since 2.9.2
@header{wx/utils.h}
*/
typedef wxStringToStringHashMap wxEnvVariableHashMap;
/** /**
This is a macro defined as @c getenv() or its wide char version in Unicode This is a macro defined as @c getenv() or its wide char version in Unicode
mode. mode.
@@ -218,6 +230,22 @@ bool wxSetEnv(const wxString& var, const wxString& value);
*/ */
bool wxUnsetEnv(const wxString& var); bool wxUnsetEnv(const wxString& var);
/**
Fill a map with the complete content of current environment.
The map will contain the environment variable names as keys and their
values as values.
@param map
The environment map to fill, must be non-@NULL.
@return
@true if environment was successfully retrieved or @false otherwise.
@header{wx/utils.h}
@since 2.9.2
*/
bool wxGetEnvMap(wxEnvVariableHashMap *map);
//@} //@}
@@ -735,6 +763,36 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
/** @addtogroup group_funcmacro_procctrl */ /** @addtogroup group_funcmacro_procctrl */
//@{ //@{
/**
@struct wxExecuteEnv
This structure can optionally be passed to wxExecute() to specify
additional options to use for the child process.
@since 2.9.2
@header{wx/utils.h}
*/
struct wxExecuteEnv
{
/**
The initial working directory for the new process.
If this field is empty, the current working directory of this process
is used.
*/
wxString cwd;
/**
The environment variable map.
If the map is empty, the environment variables of the current process
are also used for the child one, otherwise only the variables defined
in this map are used.
*/
wxEnvVariableHashMap env;
};
/** /**
Executes another program in Unix or Windows. Executes another program in Unix or Windows.
@@ -800,6 +858,10 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
their combination, in wxEXEC_SYNC case. their combination, in wxEXEC_SYNC case.
@param callback @param callback
An optional pointer to wxProcess. An optional pointer to wxProcess.
@param env
An optional pointer to additional parameters for the child process,
such as its initial working directory and environment variables. This
parameter is available in wxWidgets 2.9.2 and later only.
@see wxShell(), wxProcess, @ref page_samples_exec, @see wxShell(), wxProcess, @ref page_samples_exec,
wxLaunchDefaultApplication(), wxLaunchDefaultBrowser() wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -811,8 +873,8 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
@endWxPerlOnly @endWxPerlOnly
*/ */
long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC, long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
wxProcess* callback = NULL); wxProcess* callback = NULL,
const wxExecuteEnv* env = NULL);
//@} //@}
/** @addtogroup group_funcmacro_procctrl */ /** @addtogroup group_funcmacro_procctrl */
@@ -835,6 +897,10 @@ long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
their combination, in wxEXEC_SYNC case. their combination, in wxEXEC_SYNC case.
@param callback @param callback
An optional pointer to wxProcess. An optional pointer to wxProcess.
@param env
An optional pointer to additional parameters for the child process,
such as its initial working directory and environment variables. This
parameter is available in wxWidgets 2.9.2 and later only.
@see wxShell(), wxProcess, @ref page_samples_exec, @see wxShell(), wxProcess, @ref page_samples_exec,
wxLaunchDefaultApplication(), wxLaunchDefaultBrowser() wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -846,9 +912,11 @@ long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
@endWxPerlOnly @endWxPerlOnly
*/ */
long wxExecute(char** argv, int flags = wxEXEC_ASYNC, long wxExecute(char** argv, int flags = wxEXEC_ASYNC,
wxProcess* callback = NULL); wxProcess* callback = NULL,
const wxExecuteEnv *env = NULL);
long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC, long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
wxProcess* callback = NULL); wxProcess* callback = NULL,
const wxExecuteEnv *env = NULL);
//@} //@}
/** @addtogroup group_funcmacro_procctrl */ /** @addtogroup group_funcmacro_procctrl */
@@ -871,6 +939,10 @@ long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or
wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to
their combination. wxEXEC_SYNC is always implicitly added to the flags. their combination. wxEXEC_SYNC is always implicitly added to the flags.
@param env
An optional pointer to additional parameters for the child process,
such as its initial working directory and environment variables. This
parameter is available in wxWidgets 2.9.2 and later only.
@see wxShell(), wxProcess, @ref page_samples_exec, @see wxShell(), wxProcess, @ref page_samples_exec,
wxLaunchDefaultApplication(), wxLaunchDefaultBrowser() wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -883,7 +955,8 @@ long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
where @c output in an array reference. where @c output in an array reference.
@endWxPerlOnly @endWxPerlOnly
*/ */
long wxExecute(const wxString& command, wxArrayString& output, int flags = 0); long wxExecute(const wxString& command, wxArrayString& output, int flags = 0,
const wxExecuteEnv *env = NULL);
/** /**
This is an overloaded version of wxExecute(const wxString&,int,wxProcess*), This is an overloaded version of wxExecute(const wxString&,int,wxProcess*),
@@ -904,6 +977,10 @@ long wxExecute(const wxString& command, wxArrayString& output, int flags = 0);
May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or
wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to
their combination. wxEXEC_SYNC is always implicitly added to the flags. their combination. wxEXEC_SYNC is always implicitly added to the flags.
@param env
An optional pointer to additional parameters for the child process,
such as its initial working directory and environment variables. This
parameter is available in wxWidgets 2.9.2 and later only.
@see wxShell(), wxProcess, @ref page_samples_exec, @see wxShell(), wxProcess, @ref page_samples_exec,
wxLaunchDefaultApplication(), wxLaunchDefaultBrowser() wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -917,7 +994,8 @@ long wxExecute(const wxString& command, wxArrayString& output, int flags = 0);
@endWxPerlOnly @endWxPerlOnly
*/ */
long wxExecute(const wxString& command, wxArrayString& output, long wxExecute(const wxString& command, wxArrayString& output,
wxArrayString& errors, int flags = 0); wxArrayString& errors, int flags = 0,
const wxExecuteEnv *env = NULL);
/** /**
Returns the number uniquely identifying the current process in the system. Returns the number uniquely identifying the current process in the system.

View File

@@ -43,6 +43,8 @@
#include "wx/choicdlg.h" #include "wx/choicdlg.h"
#include "wx/button.h" #include "wx/button.h"
#include "wx/checkbox.h"
#include "wx/stattext.h"
#include "wx/textctrl.h" #include "wx/textctrl.h"
#include "wx/listbox.h" #include "wx/listbox.h"
@@ -666,6 +668,147 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
} }
} }
// ----------------------------------------------------------------------------
// execution options dialog
// ----------------------------------------------------------------------------
enum ExecQueryDialogID
{
TEXT_EXECUTABLE,
TEXT_CWD,
TEXT_ENVIRONMENT
};
class ExecQueryDialog : public wxDialog
{
public:
ExecQueryDialog(const wxString& cmd);
wxString GetExecutable() const
{
return m_executable->GetValue();
}
wxString GetWorkDir() const
{
return m_useCWD->GetValue() ? m_cwdtext->GetValue() : wxString();
}
void GetEnvironment(wxEnvVariableHashMap& env);
private:
void OnUpdateWorkingDirectoryUI(wxUpdateUIEvent& event)
{
event.Enable(m_useCWD->GetValue());
}
void OnUpdateEnvironmentUI(wxUpdateUIEvent& event)
{
event.Enable(m_useEnv->GetValue());
}
wxTextCtrl* m_executable;
wxTextCtrl* m_cwdtext;
wxTextCtrl* m_envtext;
wxCheckBox* m_useCWD;
wxCheckBox* m_useEnv;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(ExecQueryDialog, wxDialog)
EVT_UPDATE_UI(TEXT_CWD, ExecQueryDialog::OnUpdateWorkingDirectoryUI)
EVT_UPDATE_UI(TEXT_ENVIRONMENT, ExecQueryDialog::OnUpdateEnvironmentUI)
END_EVENT_TABLE()
ExecQueryDialog::ExecQueryDialog(const wxString& cmd)
: wxDialog(NULL, wxID_ANY, DIALOG_TITLE,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxSizer* globalSizer = new wxBoxSizer(wxVERTICAL);
m_executable = new wxTextCtrl(this, TEXT_EXECUTABLE, wxString());
m_cwdtext = new wxTextCtrl(this, TEXT_CWD, wxString());
m_envtext = new wxTextCtrl(this, TEXT_ENVIRONMENT, wxString(),
wxDefaultPosition, wxSize(300, 200),
wxTE_MULTILINE|wxHSCROLL);
const wxSizerFlags flagsExpand = wxSizerFlags().Expand().Border();
globalSizer->Add(new wxStaticText(this, wxID_ANY, "Enter the command: "),
flagsExpand);
globalSizer->Add(m_executable, flagsExpand);
m_useCWD = new wxCheckBox(this, wxID_ANY, "Working directory: ");
globalSizer->Add(m_useCWD, flagsExpand);
globalSizer->Add(m_cwdtext, flagsExpand);
m_useEnv = new wxCheckBox(this, wxID_ANY, "Environment: ");
globalSizer->Add(m_useEnv, flagsExpand);
globalSizer->Add(m_envtext, wxSizerFlags(flagsExpand).Proportion(1));
globalSizer->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL), flagsExpand);
SetSizerAndFit(globalSizer);
m_executable->SetValue(cmd);
m_cwdtext->SetValue(wxGetCwd());
wxEnvVariableHashMap env;
if ( wxGetEnvMap(&env) )
{
for ( wxEnvVariableHashMap::iterator it = env.begin();
it != env.end();
++it )
{
m_envtext->AppendText(it->first + '=' + it->second + '\n');
}
}
m_useCWD->SetValue(false);
m_useEnv->SetValue(false);
}
void ExecQueryDialog::GetEnvironment(wxEnvVariableHashMap& env)
{
env.clear();
if ( m_useEnv->GetValue() )
{
wxString name,
value;
const int nb = m_envtext->GetNumberOfLines();
for ( int l = 0; l < nb; l++ )
{
const wxString line = m_envtext->GetLineText(l).Trim();
if ( !line.empty() )
{
name = line.BeforeFirst('=', &value);
if ( name.empty() )
{
wxLogWarning("Skipping invalid environment line \"%s\".", line);
continue;
}
env[name] = value;
}
}
}
}
static bool QueryExec(wxString& cmd, wxExecuteEnv& env)
{
ExecQueryDialog dialog(cmd);
if ( dialog.ShowModal() != wxID_OK )
return false;
cmd = dialog.GetExecutable();
env.cwd = dialog.GetWorkDir();
dialog.GetEnvironment(env.env);
return true;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// event handlers: exec menu // event handlers: exec menu
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -694,16 +837,14 @@ void MyFrame::DoAsyncExec(const wxString& cmd)
void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
{ {
wxString cmd = wxGetTextFromUser(wxT("Enter the command: "), wxString cmd;
DIALOG_TITLE, wxExecuteEnv env;
m_cmdLast); if ( !QueryExec(cmd, env) )
if ( !cmd )
return; return;
wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() ); wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
int code = wxExecute(cmd, wxEXEC_SYNC); int code = wxExecute(cmd, wxEXEC_SYNC, NULL, &env);
wxLogStatus(wxT("Process '%s' terminated with exit code %d."), wxLogStatus(wxT("Process '%s' terminated with exit code %d."),
cmd.c_str(), code); cmd.c_str(), code);

View File

@@ -142,7 +142,8 @@ WX_IMPLEMENT_GET_OBJC_CLASS(wxTaskHandler,NSObject)
long wxExecute(const wxString& command, long wxExecute(const wxString& command,
int sync, int sync,
wxProcess *handle) wxProcess *handle,
const wxExecuteEnv *env)
{ {
NSTask* theTask = [[NSTask alloc] init]; NSTask* theTask = [[NSTask alloc] init];

View File

@@ -543,6 +543,43 @@ wxString wxGetCurrentDir()
#endif // 0 #endif // 0
// ----------------------------------------------------------------------------
// Environment
// ----------------------------------------------------------------------------
bool wxGetEnvMap(wxEnvVariableHashMap *map)
{
wxCHECK_MSG( map, false, wxS("output pointer can't be NULL") );
#if defined(__VISUALC__)
wxChar **env = _tenviron;
#else // non-MSVC
// Not sure if other compilers have _tenviron so use the (more standard)
// ANSI version only for them.
char ** env = environ;
#endif
if ( env )
{
wxString name,
value;
while ( *env )
{
const wxString var(*env);
name = var.BeforeFirst(wxS('='), &value);
(*map)[name] = value;
env++;
}
return true;
}
return false;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxExecute // wxExecute
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -590,13 +627,14 @@ static bool ReadAll(wxInputStream *is, wxArrayString& output)
static long wxDoExecuteWithCapture(const wxString& command, static long wxDoExecuteWithCapture(const wxString& command,
wxArrayString& output, wxArrayString& output,
wxArrayString* error, wxArrayString* error,
int flags) int flags,
const wxExecuteEnv *env)
{ {
// create a wxProcess which will capture the output // create a wxProcess which will capture the output
wxProcess *process = new wxProcess; wxProcess *process = new wxProcess;
process->Redirect(); process->Redirect();
long rc = wxExecute(command, wxEXEC_SYNC | flags, process); long rc = wxExecute(command, wxEXEC_SYNC | flags, process, env);
#if wxUSE_STREAMS #if wxUSE_STREAMS
if ( rc != -1 ) if ( rc != -1 )
@@ -621,17 +659,19 @@ static long wxDoExecuteWithCapture(const wxString& command,
return rc; return rc;
} }
long wxExecute(const wxString& command, wxArrayString& output, int flags) long wxExecute(const wxString& command, wxArrayString& output, int flags,
const wxExecuteEnv *env)
{ {
return wxDoExecuteWithCapture(command, output, NULL, flags); return wxDoExecuteWithCapture(command, output, NULL, flags, env);
} }
long wxExecute(const wxString& command, long wxExecute(const wxString& command,
wxArrayString& output, wxArrayString& output,
wxArrayString& error, wxArrayString& error,
int flags) int flags,
const wxExecuteEnv *env)
{ {
return wxDoExecuteWithCapture(command, output, &error, flags); return wxDoExecuteWithCapture(command, output, &error, flags, env);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -314,7 +314,8 @@ bool wxShell(const wxString& command /*=wxEmptyString*/)
return result == 0; return result == 0;
} }
long wxExecute(const wxString& command, int flags, wxProcess *process) long wxExecute(const wxString& command, int flags, wxProcess *process,
const wxExecuteEnv *env)
{ {
// FIXME: shouldn't depend on wxCmdLineParser // FIXME: shouldn't depend on wxCmdLineParser
wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command)); wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command));
@@ -439,7 +440,8 @@ wxString wxRedirectableFd::Release()
// wxExecute implementation // wxExecute implementation
// //
long wxExecute(wxChar **argv, int flags, wxProcess *process) long wxExecute(wxChar **argv, int flags, wxProcess *process,
const wxString* cwd, const wxEnvVariableHashMap* env)
{ {
#if wxUSE_STREAMS #if wxUSE_STREAMS
const int STDIN = 0; const int STDIN = 0;

View File

@@ -610,7 +610,8 @@ wxExecuteDDE(const wxString& ddeServer,
#endif // wxUSE_IPC #endif // wxUSE_IPC
long wxExecute(const wxString& cmd, int flags, wxProcess *handler) long wxExecute(const wxString& cmd, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") ); wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
@@ -800,6 +801,55 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
wxString arguments = command.AfterFirst(wxT(' ')); wxString arguments = command.AfterFirst(wxT(' '));
#endif #endif
wxWxCharBuffer envBuffer;
bool useCwd = false;
if ( env )
{
useCwd = !env->cwd.empty();
// Translate environment variable map into NUL-terminated list of
// NUL-terminated strings.
if ( !env->env.empty() )
{
#if wxUSE_UNICODE
// Environment variables can contain non-ASCII characters. We could
// check for it and not use this flag if everything is really ASCII
// only but there doesn't seem to be any reason to do it so just
// assume Unicode by default.
dwFlags |= CREATE_UNICODE_ENVIRONMENT;
#endif // wxUSE_UNICODE
wxEnvVariableHashMap::const_iterator it;
size_t envSz = 1; // ending '\0'
for ( it = env->env.begin(); it != env->env.end(); ++it )
{
// Add size of env variable name and value, and '=' char and
// ending '\0'
envSz += it->first.length() + it->second.length() + 2;
}
envBuffer.extend(envSz);
wxChar *p = envBuffer.data();
for ( it = env->env.begin(); it != env->env.end(); ++it )
{
const wxString line = it->first + wxS("=") + it->second;
// Include the trailing NUL which will always terminate the
// buffer returned by t_str().
const size_t len = line.length() + 1;
wxTmemcpy(p, line.t_str(), len);
p += len;
}
// And another NUL to terminate the list of NUL-terminated strings.
*p = 0;
}
}
bool ok = ::CreateProcess bool ok = ::CreateProcess
( (
// WinCE requires appname to be non null // WinCE requires appname to be non null
@@ -818,8 +868,10 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
NULL, // the process and its main thread NULL, // the process and its main thread
redirect, // inherit handles if we use pipes redirect, // inherit handles if we use pipes
dwFlags, // process creation flags dwFlags, // process creation flags
NULL, // environment (use the same) envBuffer.data(), // environment (may be NULL which is fine)
NULL, // current directory (use the same) useCwd // initial working directory
? const_cast<wxChar *>(env->cwd.wx_str())
: NULL, // (or use the same)
&si, // startup info (unused here) &si, // startup info (unused here)
&pi // process info &pi // process info
) != 0; ) != 0;
@@ -1039,7 +1091,8 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
} }
template <typename CharType> template <typename CharType>
long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler) long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
wxString command; wxString command;
command.reserve(1024); command.reserve(1024);
@@ -1078,19 +1131,21 @@ long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
command += ' '; command += ' ';
} }
return wxExecute(command, flags, handler); return wxExecute(command, flags, handler, env);
} }
long wxExecute(char **argv, int flags, wxProcess *handler) long wxExecute(char **argv, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
return wxExecuteImpl(argv, flags, handler); return wxExecuteImpl(argv, flags, handler, env);
} }
#if wxUSE_UNICODE #if wxUSE_UNICODE
long wxExecute(wchar_t **argv, int flags, wxProcess *handler) long wxExecute(wchar_t **argv, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
return wxExecuteImpl(argv, flags, handler); return wxExecuteImpl(argv, flags, handler, env);
} }
#endif // wxUSE_UNICODE #endif // wxUSE_UNICODE

View File

@@ -128,7 +128,8 @@ MRESULT APIENTRY wxExecuteWindowCbk( HWND hWnd,
long wxExecute( const wxString& rCommand, long wxExecute( const wxString& rCommand,
int flags, int flags,
wxProcess* pHandler) wxProcess* pHandler,
const wxExecuteEnv *env)
{ {
if (rCommand.empty()) if (rCommand.empty())
{ {
@@ -219,6 +220,7 @@ long wxExecute(
char** ppArgv char** ppArgv
, int flags , int flags
, wxProcess* pHandler , wxProcess* pHandler
, const wxExecuteEnv *env
) )
{ {
wxString sCommand; wxString sCommand;
@@ -234,6 +236,7 @@ long wxExecute(
return wxExecute( sCommand return wxExecute( sCommand
,flags ,flags
,pHandler ,pHandler
, env
); );
} }

View File

@@ -87,12 +87,14 @@ static bool wxExecuteDDE(const wxString& ddeServer,
#endif // wxUSE_IPC #endif // wxUSE_IPC
long wxExecute(const wxString& cmd, int flags, wxProcess *handler) long wxExecute(const wxString& cmd, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
return 0; return 0;
} }
long wxExecute(wxChar **argv, int flags, wxProcess *handler) long wxExecute(wxChar **argv, int flags, wxProcess *handler,
const wxExecuteEnv *env)
{ {
return 0; return 0;
} }

View File

@@ -442,27 +442,30 @@ private:
bool wxMacLaunch(char **argv); bool wxMacLaunch(char **argv);
#endif #endif
long wxExecute(const wxString& command, int flags, wxProcess *process) long wxExecute(const wxString& command, int flags, wxProcess *process,
const wxExecuteEnv *env)
{ {
ArgsArray argv(wxCmdLineParser::ConvertStringToArgs(command, ArgsArray argv(wxCmdLineParser::ConvertStringToArgs(command,
wxCMD_LINE_SPLIT_UNIX)); wxCMD_LINE_SPLIT_UNIX));
return wxExecute(argv, flags, process); return wxExecute(argv, flags, process, env);
} }
#if wxUSE_UNICODE #if wxUSE_UNICODE
long wxExecute(wchar_t **wargv, int flags, wxProcess *process) long wxExecute(wchar_t **wargv, int flags, wxProcess *process,
const wxExecuteEnv *env)
{ {
ArgsArray argv(wargv); ArgsArray argv(wargv);
return wxExecute(argv, flags, process); return wxExecute(argv, flags, process, env);
} }
#endif // wxUSE_UNICODE #endif // wxUSE_UNICODE
// wxExecute: the real worker function // wxExecute: the real worker function
long wxExecute(char **argv, int flags, wxProcess *process) long wxExecute(char **argv, int flags, wxProcess *process,
const wxExecuteEnv *env)
{ {
// for the sync execution, we return -1 to indicate failure, but for async // for the sync execution, we return -1 to indicate failure, but for async
// case we return 0 which is never a valid PID // case we return 0 which is never a valid PID
@@ -577,6 +580,40 @@ long wxExecute(char **argv, int flags, wxProcess *process)
pipeErr.Close(); pipeErr.Close();
} }
// Process additional options if we have any
if ( env )
{
// Change working directory if it is specified
if ( !env->cwd.empty() )
wxSetWorkingDirectory(env->cwd);
// Change environment if needed.
//
// NB: We can't use execve() currently because we allow using
// non full paths to wxExecute(), i.e. we want to search for
// the program in PATH. However it just might be simpler/better
// to do the search manually and use execve() envp parameter to
// set up the environment of the child process explicitly
// instead of doing what we do below.
if ( !env->env.empty() )
{
wxEnvVariableHashMap oldenv;
wxGetEnvMap(&oldenv);
// Remove unwanted variables
wxEnvVariableHashMap::const_iterator it;
for ( it = oldenv.begin(); it != oldenv.end(); ++it )
{
if ( env->env.find(it->first) == env->env.end() )
wxUnsetEnv(it->first);
}
// And add the new ones (possibly replacing the old values)
for ( it = env->env.begin(); it != env->env.end(); ++it )
wxSetEnv(it->first, it->second);
}
}
execvp(*argv, argv); execvp(*argv, argv);
fprintf(stderr, "execvp("); fprintf(stderr, "execvp(");