diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex index 780c285fa8..3b4823d267 100644 --- a/docs/latex/wx/function.tex +++ b/docs/latex/wx/function.tex @@ -1319,6 +1319,8 @@ wxWindows errors. See also \helpref{wxFatalError}{wxfatalerror}. \func{long}{wxExecute}{\param{const wxString\& }{command}, \param{wxArrayString\& }{output}} +\func{long}{wxExecute}{\param{const wxString\& }{command}, \param{wxArrayString\& }{output}, \param{wxArrayString\& }{errors}} + Executes another program in Unix or Windows. The first form takes a command string, such as {\tt "emacs file.txt"}. @@ -1326,8 +1328,8 @@ The first form takes a command string, such as {\tt "emacs file.txt"}. The second form takes an array of values: a command, any number of arguments, terminated by NULL. -The semantics of the third version is different from the first two and is -described in more details below. +The semantics of the third and fourth versions is different from the first two +and is described in more details below. If {\it sync} is FALSE (the default), flow of control immediately returns. If TRUE, the current application waits until the other program has terminated. @@ -1350,7 +1352,8 @@ the process finishes. Finally, you may use the third overloaded version of this function to execute a process (always synchronously) and capture its output in the array -{\it output}. +{\it output}. The fourth version adds the possibility to additionally capture +the messages from standard error output in the {\it errors} array. See also \helpref{wxShell}{wxshell}, \helpref{wxProcess}{wxprocess}, \helpref{Exec sample}{sampleexec}. diff --git a/docs/latex/wx/process.tex b/docs/latex/wx/process.tex index d677829035..95cf13eb19 100644 --- a/docs/latex/wx/process.tex +++ b/docs/latex/wx/process.tex @@ -14,6 +14,15 @@ However, if it is not processed, the object will delete itself and so the library users should only delete those objects whose notifications have been processed (and call \helpref{Detach()}{wxprocessdetach} for others). +wxProcess also supports IO redirection of the child process. For this, you have +to call its \helpref{Redirect}{wxprocessredirect} method before passing it to +\helpref{wxExecute}{wxexecute}. If the child process was launched successfully, +\helpref{GetInputStream}{wxprocessgetinputstream}, +\helpref{GetOutputStream}{wxprocessgetoutputstream} and +\helpref{GetErrorStream}{wxprocessgeterrorstream} can then be used to retrieve +the streams corresponding to the child process stdandard output, input and +error output respectively. + \wxheading{Derived from} \helpref{wxEvtHandler}{wxevthandler} @@ -22,6 +31,11 @@ processed (and call \helpref{Detach()}{wxprocessdetach} for others). +\wxheading{See also} + +\helpref{wxExecute}{wxexecute}\\ +\helpref{exec sample}{sampleexec} + \latexignore{\rtfignore{\wxheading{Members}}} \membersection{wxProcess::wxProcess}\label{wxprocessconstr} @@ -62,19 +76,26 @@ from its parent, no notification events will be sent to the parent and the object will delete itself upon reception of the process termination notification. +\membersection{wxProcess::GetErrorStream}\label{wxprocessgeterrorstream} + +\constfunc{wxInputStream* }{GetErrorStream}{\void} + +Returns an input stream which corresponds to the standard error output (stderr) +of the child process. + \membersection{wxProcess::GetInputStream}\label{wxprocessgetinputstream} \constfunc{wxInputStream* }{GetInputStream}{\void} -It returns a output stream corresponding to the input stream of the subprocess. -If it is NULL, you have not turned on the redirection. +It returns a output stream corresponding to the standard output stream of the +subprocess. If it is NULL, you have not turned on the redirection. See \helpref{wxProcess::Redirect}{wxprocessredirect}. \membersection{wxProcess::GetOutputStream}\label{wxprocessgetoutputstream} \constfunc{wxOutputStream* }{GetOutputStream}{\void} -It returns an output stream correspoding to the output stream of the subprocess. +It returns an output stream correspoding to the input stream of the subprocess. If it is NULL, you have not turned on the redirection. See \helpref{wxProcess::Redirect}{wxprocessredirect}. diff --git a/docs/latex/wx/tsamples.tex b/docs/latex/wx/tsamples.tex index 9ea71aebb9..6c448dc45c 100644 --- a/docs/latex/wx/tsamples.tex +++ b/docs/latex/wx/tsamples.tex @@ -151,6 +151,9 @@ The exec sample demonstrates the \helpref{wxExecute}{wxexecute} and external programs and the sample shows how to do this synchronously (waiting until the program terminates) or asynchronously (notification will come later). +It also shows how to capture the output of the child process in both +synchronous and asynchronous cases. + \subsection{Scroll subwindow sample}\label{samplescrollsub} This sample demonstrates the use of the \helpref{wxScrolledWindow}{wxscrolledwindow} diff --git a/docs/latex/wx/wx.hpj b/docs/latex/wx/wx.hpj index 5bf567ae88..aee3b962f3 100644 --- a/docs/latex/wx/wx.hpj +++ b/docs/latex/wx/wx.hpj @@ -1,14 +1,14 @@ [OPTIONS] -BMROOT=d:\wx2\wxWind~1\docs/latex/wx ; Assume that bitmaps are where the source is +;BMROOT=L:\wxWindows\docs\latex\wx ; Assume that bitmaps are where the source is TITLE=wxWindows Manual CONTENTS=Contents COMPRESS=HIGH [FILES] -wx.rtf +Wx.rtf [CONFIG] -CreateButton("Up", "&Up", "JumpId(`wx.hlp', `Contents')") +CreateButton("Up", "&Up", "JumpId(`Wx.hlp', `Contents')") BrowseButtons() [MAP] diff --git a/include/wx/msw/colordlg.h b/include/wx/msw/colordlg.h index 5643ef6f2f..ae9bcefc37 100644 --- a/include/wx/msw/colordlg.h +++ b/include/wx/msw/colordlg.h @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: colordlg.h +// Name: wx/msw/colordlg.h // Purpose: wxColourDialog class // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifndef _WX_COLORDLG_H_ @@ -20,25 +20,31 @@ #include "wx/dialog.h" #include "wx/cmndata.h" -/* - * COLOUR DIALOG - */ +// ---------------------------------------------------------------------------- +// wxColourDialog: dialog for choosing a colours +// ---------------------------------------------------------------------------- -class WXDLLEXPORT wxColourDialog: public wxDialog +class WXDLLEXPORT wxColourDialog : public wxDialog { -DECLARE_DYNAMIC_CLASS(wxColourDialog) public: - wxColourDialog(void); + wxColourDialog(); wxColourDialog(wxWindow *parent, wxColourData *data = NULL); bool Create(wxWindow *parent, wxColourData *data = NULL); - int ShowModal(void); - wxColourData& GetColourData(void) { return m_colourData; } + wxColourData& GetColourData() { return m_colourData; } + + // override some base class virtuals + virtual void SetTitle(const wxString& title); + virtual wxString GetTitle(); + virtual int ShowModal(); protected: wxColourData m_colourData; wxWindow* m_dialogParent; + wxString m_title; + + DECLARE_DYNAMIC_CLASS(wxColourDialog) }; #endif diff --git a/include/wx/utils.h b/include/wx/utils.h index e24ce7c2fa..04c5a868ba 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -148,7 +148,13 @@ WXDLLEXPORT long wxExecute(const wxString& command, bool sync = FALSE, wxProcess *process = (wxProcess *) NULL); // execute the command capturing its output into an array line by line -WXDLLEXPORT long wxExecute(const wxString& command, wxArrayString& output); +WXDLLEXPORT long wxExecute(const wxString& command, + wxArrayString& output); + +// also capture stderr +WXDLLEXPORT long wxExecute(const wxString& command, + wxArrayString& output, + wxArrayString& error); enum wxSignal { diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp index 28fc29f693..5ddfb2442a 100644 --- a/src/common/utilscmn.cpp +++ b/src/common/utilscmn.cpp @@ -1208,12 +1208,18 @@ wxString wxGetCurrentDir() // wxExecute // ---------------------------------------------------------------------------- -long wxExecute(const wxString& command, wxArrayString& output) +// this is a private function because it hasn't a clean interface: the first +// array is passed by reference, the second by pointer - instead we have 2 +// public versions of wxExecute() below +static long wxDoExecuteWithCapture(const wxString& command, + wxArrayString& output, + wxArrayString* error) { #ifdef __WIN16__ wxFAIL_MSG("Sorry, this version of wxExecute not implemented on WIN16."); + return 0; -#else +#else // !Win16 // create a wxProcess which will capture the output wxProcess *process = new wxProcess; process->Redirect(); @@ -1223,19 +1229,68 @@ long wxExecute(const wxString& command, wxArrayString& output) #if wxUSE_STREAMS if ( rc != -1 ) { - wxInputStream& is = *process->GetInputStream(); - wxTextInputStream tis(is); - while ( !is.Eof() && is.IsOk() ) - { - wxString line = tis.ReadLine(); - if ( is.LastError() ) - break; + wxInputStream* is = process->GetInputStream(); + wxCHECK_MSG( is, -1, _T("if wxExecute() succeded, stream can't be NULL") ); + wxTextInputStream tis(*is); - output.Add(line); + wxTextInputStream *tes = NULL; + wxInputStream *es = NULL; + if ( error ) + { + es = process->GetErrorStream(); + + wxCHECK_MSG( es, -1, _T("stderr can't be NULL") ); + + tes = new wxTextInputStream(*es); } + + bool cont; + do + { + cont = FALSE; + + if ( !is->Eof() && is->IsOk() ) + { + wxString line = tis.ReadLine(); + if ( is->LastError() ) + break; + + cont = TRUE; + + output.Add(line); + } + + if ( error && !es->Eof() && es->IsOk() ) + { + wxString line = tes->ReadLine(); + if ( es->LastError() ) + break; + + cont = TRUE; + + error->Add(line); + } + } + while ( cont ); + + delete tes; } -#endif +#endif // wxUSE_STREAMS + + delete process; return rc; -#endif +#endif // IO redirection supoprted +} + +long wxExecute(const wxString& command, wxArrayString& output) +{ + return wxDoExecuteWithCapture(command, output, NULL); +} + +long wxExecute(const wxString& command, + wxArrayString& output, + wxArrayString& error) +{ + return wxDoExecuteWithCapture(command, output, &error); } diff --git a/src/msw/colordlg.cpp b/src/msw/colordlg.cpp index 66e0a3ef73..3d5f0ecf77 100644 --- a/src/msw/colordlg.cpp +++ b/src/msw/colordlg.cpp @@ -1,43 +1,51 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: colordlg.cpp +// Name: src/msw/colordlg.cpp // Purpose: wxColourDialog class // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "colordlg.h" + #pragma implementation "colordlg.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include -#include "wx/defs.h" -#include "wx/bitmap.h" -#include "wx/pen.h" -#include "wx/brush.h" -#include "wx/colour.h" -#include "wx/gdicmn.h" -#include "wx/utils.h" -#include "wx/frame.h" -#include "wx/dialog.h" -#include "wx/msgdlg.h" + #include + #include "wx/defs.h" + #include "wx/bitmap.h" + #include "wx/pen.h" + #include "wx/brush.h" + #include "wx/colour.h" + #include "wx/gdicmn.h" + #include "wx/utils.h" + #include "wx/frame.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" #endif #include #if !defined(__WIN32__) || defined(__SALFORDC__) || defined(__WXWINE__) -#include + #include #endif #include "wx/msw/private.h" @@ -48,16 +56,41 @@ #include #include -#define wxDIALOG_DEFAULT_X 300 -#define wxDIALOG_DEFAULT_Y 300 +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS(wxColourDialog, wxDialog) -/* - * wxColourDialog - */ +// ============================================================================ +// implementation +// ============================================================================ -wxColourDialog::wxColourDialog(void) +// ---------------------------------------------------------------------------- +// colour dialog hook proc +// ---------------------------------------------------------------------------- + +UINT CALLBACK wxColourDialogHookProc(HWND hwnd, + UINT uiMsg, + WPARAM wParam, + LPARAM lParam) +{ + if ( uiMsg == WM_INITDIALOG ) + { + CHOOSECOLOR *pCC = (CHOOSECOLOR *)lParam; + wxColourDialog *dialog = (wxColourDialog *)pCC->lCustData; + + ::SetWindowText(hwnd, dialog->GetTitle()); + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// wxColourDialog +// ---------------------------------------------------------------------------- + +wxColourDialog::wxColourDialog() { m_dialogParent = NULL; } @@ -76,7 +109,7 @@ bool wxColourDialog::Create(wxWindow *parent, wxColourData *data) return TRUE; } -int wxColourDialog::ShowModal(void) +int wxColourDialog::ShowModal() { CHOOSECOLOR chooseColorStruct; COLORREF custColours[16]; @@ -84,20 +117,23 @@ int wxColourDialog::ShowModal(void) int i; for (i = 0; i < 16; i++) - custColours[i] = RGB(m_colourData.custColours[i].Red(), m_colourData.custColours[i].Green(), m_colourData.custColours[i].Blue()); + custColours[i] = wxColourToRGB(m_colourData.custColours[i]); chooseColorStruct.lStructSize = sizeof(CHOOSECOLOR); - chooseColorStruct.hwndOwner = (HWND) (m_dialogParent ? (HWND) m_dialogParent->GetHWND() : (HWND) NULL); - chooseColorStruct.rgbResult = RGB(m_colourData.dataColour.Red(), m_colourData.dataColour.Green(), m_colourData.dataColour.Blue()); + if ( m_dialogParent ) + chooseColorStruct.hwndOwner = GetHwndOf(m_dialogParent); + chooseColorStruct.rgbResult = wxColourToRGB(m_colourData.dataColour); chooseColorStruct.lpCustColors = custColours; - chooseColorStruct.Flags = CC_RGBINIT; + chooseColorStruct.Flags = CC_RGBINIT | CC_ENABLEHOOK; + chooseColorStruct.lCustData = (LPARAM)this; + chooseColorStruct.lpfnHook = wxColourDialogHookProc; if (!m_colourData.GetChooseFull()) chooseColorStruct.Flags |= CC_PREVENTFULLOPEN; // Do the modal dialog - bool success = (ChooseColor(&(chooseColorStruct)) != 0); + bool success = ::ChooseColor(&(chooseColorStruct)) != 0; // Try to highlight the correct window (the parent) HWND hWndParent = 0; @@ -112,13 +148,21 @@ int wxColourDialog::ShowModal(void) // Restore values for (i = 0; i < 16; i++) { - m_colourData.custColours[i].Set(GetRValue(custColours[i]), GetGValue(custColours[i]), - GetBValue(custColours[i])); + wxRGBToColour(m_colourData.custColours[i], custColours[i]); } - m_colourData.dataColour.Set(GetRValue(chooseColorStruct.rgbResult), GetGValue(chooseColorStruct.rgbResult), - GetBValue(chooseColorStruct.rgbResult)); + wxRGBToColour(m_colourData.dataColour, chooseColorStruct.rgbResult); return success ? wxID_OK : wxID_CANCEL; } +void wxColourDialog::SetTitle(const wxString& title) +{ + m_title = title; +} + +wxString wxColourDialog::GetTitle() +{ + return m_title; +} + diff --git a/src/msw/gauge95.cpp b/src/msw/gauge95.cpp index 18d6f85897..4f1bff7201 100644 --- a/src/msw/gauge95.cpp +++ b/src/msw/gauge95.cpp @@ -1,16 +1,24 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: gauge95.cpp +// Name: src/msw/gauge95.cpp // Purpose: wxGauge95 class // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "gauge95.h" + #pragma implementation "gauge95.h" #endif // For compilers that support precompilation, includes "wx.h". @@ -21,7 +29,7 @@ #endif #ifndef WX_PRECOMP -#include "wx/defs.h" + #include "wx/defs.h" #endif #if wxUSE_GAUGE && defined(__WIN95__) @@ -33,8 +41,37 @@ #include #endif +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// old commctrl.h (< 4.71) don't have those +#ifndef PBS_SMOOTH + #define PBS_SMOOTH 0x01 +#endif + +#ifndef PBS_VERTICAL + #define PBS_VERTICAL 0x04 +#endif + +#ifndef PBM_SETBARCOLOR + #define PBM_SETBARCOLOR (WM_USER+9) +#endif + +#ifndef PBM_SETBKCOLOR + #define PBM_SETBKCOLOR 0x2001 +#endif + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + IMPLEMENT_DYNAMIC_CLASS(wxGauge95, wxControl) +// ============================================================================ +// implementation +// ============================================================================ + bool wxGauge95::Create(wxWindow *parent, wxWindowID id, int range, const wxPoint& pos, @@ -52,8 +89,8 @@ bool wxGauge95::Create(wxWindow *parent, wxWindowID id, m_rangeMax = range; m_gaugePos = 0; - SetBackgroundColour(parent->GetBackgroundColour()) ; - SetForegroundColour(parent->GetForegroundColour()) ; + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); m_windowStyle = style; @@ -67,19 +104,11 @@ bool wxGauge95::Create(wxWindow *parent, wxWindowID id, int width = size.x; int height = size.y; - long msFlags = WS_CHILD | WS_VISIBLE /* | WS_CLIPSIBLINGS */ ; - -#ifndef PBS_VERTICAL -#define PBS_VERTICAL 0x04 -#endif + long msFlags = WS_CHILD | WS_VISIBLE /* | WS_CLIPSIBLINGS */; if (m_windowStyle & wxGA_VERTICAL) msFlags |= PBS_VERTICAL; -#ifndef PBS_SMOOTH -#define PBS_SMOOTH 0x01 -#endif - if (m_windowStyle & wxGA_SMOOTH) msFlags |= PBS_SMOOTH; @@ -130,22 +159,22 @@ void wxGauge95::SetValue(int pos) SendMessage((HWND) GetHWND(), PBM_SETPOS, pos, 0); } -int wxGauge95::GetShadowWidth(void) const +int wxGauge95::GetShadowWidth() const { return 0; } -int wxGauge95::GetBezelFace(void) const +int wxGauge95::GetBezelFace() const { return 0; } -int wxGauge95::GetRange(void) const +int wxGauge95::GetRange() const { return m_rangeMax; } -int wxGauge95::GetValue(void) const +int wxGauge95::GetValue() const { return m_gaugePos; } @@ -155,7 +184,7 @@ bool wxGauge95::SetForegroundColour(const wxColour& col) if ( !wxControl::SetForegroundColour(col) ) return FALSE; - m_foregroundColour = col ; + SendMessage(GetHwnd(), PBM_SETBARCOLOR, 0, (LPARAM)wxColourToRGB(col)); return TRUE; } @@ -165,7 +194,7 @@ bool wxGauge95::SetBackgroundColour(const wxColour& col) if ( !wxControl::SetBackgroundColour(col) ) return FALSE; - m_backgroundColour = col ; + SendMessage(GetHwnd(), PBM_SETBKCOLOR, 0, (LPARAM)wxColourToRGB(col)); return TRUE; } diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 17de6a6068..9bbb661b03 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -2218,9 +2218,11 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) switch ( hdr->code ) { case NM_DBLCLK: - // return TRUE to prevent the default processing which consists in - // toggling the state of the item under the mouse - *result = processed; + // we translate NM_DBLCLK into ACTIVATED event, so don't interpret + // the return code of this event handler as the return value for + // NM_DBLCLK - otherwise, double clicking the item to toggle its + // expanded status would never work + *result = FALSE; break; case TVN_BEGINDRAG: diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 09049b1e55..105305a563 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -398,7 +398,8 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) #if wxUSE_STREAMS // the first elements are reading ends, the second are the writing ones HANDLE hpipeStdin[2], - hpipeStdout[2]; + hpipeStdout[2], + hpipeStderr[2]; // open the pipes to which child process IO will be redirected if needed if ( handler && handler->IsRedirected() ) @@ -430,6 +431,8 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) return sync ? -1 : 0; } + (void)::CreatePipe(&hpipeStderr[0], &hpipeStderr[1], &security, 0); + redirect = TRUE; } #endif // wxUSE_STREAMS @@ -442,9 +445,15 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) #if wxUSE_STREAMS if ( redirect ) { - si.dwFlags = STARTF_USESTDHANDLES; + // when the std IO is redirected, we don't show the (console) process + // window + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.hStdInput = hpipeStdin[0]; si.hStdOutput = hpipeStdout[1]; + si.hStdError = hpipeStderr[1]; + + si.wShowWindow = SW_HIDE; } #endif // wxUSE_STREAMS @@ -472,6 +481,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) { ::CloseHandle(hpipeStdin[0]); ::CloseHandle(hpipeStdout[1]); + ::CloseHandle(hpipeStderr[1]); } #endif // wxUSE_STREAMS @@ -483,6 +493,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) { ::CloseHandle(hpipeStdin[1]); ::CloseHandle(hpipeStdout[0]); + ::CloseHandle(hpipeStderr[0]); } #endif // wxUSE_STREAMS @@ -495,10 +506,11 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) if ( redirect ) { // We can now initialize the wxStreams - wxInputStream *inStream = new wxPipeInputStream(hpipeStdout[0]); + wxInputStream *inStream = new wxPipeInputStream(hpipeStdout[0]), + *errStream = new wxPipeInputStream(hpipeStderr[0]); wxOutputStream *outStream = new wxPipeOutputStream(hpipeStdin[1]); - handler->SetPipeStreams(inStream, outStream, NULL); + handler->SetPipeStreams(inStream, outStream, errStream); } #endif // wxUSE_STREAMS