+
+// ============================================================================
+// MyPipeFrame implementation
+// ============================================================================
+
+MyPipeFrame::MyPipeFrame(wxFrame *parent,
+ const wxString& cmd,
+ wxProcess *process)
+ : wxFrame(parent, wxID_ANY, cmd),
+ m_process(process),
+ // in a real program we'd check that the streams are !NULL here
+ m_out(*process->GetOutputStream()),
+ m_in(*process->GetInputStream()),
+ m_err(*process->GetErrorStream())
+{
+ m_process->SetNextHandler(this);
+
+ wxPanel *panel = new wxPanel(this, wxID_ANY);
+
+ m_textOut = new wxTextCtrl(panel, wxID_ANY, _T(""),
+ wxDefaultPosition, wxDefaultSize,
+ wxTE_PROCESS_ENTER);
+ m_textIn = new wxTextCtrl(panel, wxID_ANY, _T(""),
+ wxDefaultPosition, wxDefaultSize,
+ wxTE_MULTILINE | wxTE_RICH);
+ m_textIn->SetEditable(false);
+ m_textErr = new wxTextCtrl(panel, wxID_ANY, _T(""),
+ wxDefaultPosition, wxDefaultSize,
+ wxTE_MULTILINE | wxTE_RICH);
+ m_textErr->SetEditable(false);
+
+ wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
+ sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
+
+ wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
+ sizerBtns->
+ Add(new wxButton(panel, Exec_Btn_Send, _T("&Send")), 0, wxALL, 5);
+ sizerBtns->
+ Add(new wxButton(panel, Exec_Btn_SendFile, _T("&File...")), 0, wxALL, 5);
+ sizerBtns->
+ Add(new wxButton(panel, Exec_Btn_Get, _T("&Get")), 0, wxALL, 5);
+ sizerBtns->
+ Add(new wxButton(panel, Exec_Btn_Close, _T("&Close")), 0, wxALL, 5);
+
+ sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
+ sizerTop->Add(m_textIn, 1, wxGROW | wxALL, 5);
+ sizerTop->Add(m_textErr, 1, wxGROW | wxALL, 5);
+
+ panel->SetSizer(sizerTop);
+ sizerTop->Fit(this);
+
+ Show();
+}
+
+void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event))
+{
+ wxFileDialog filedlg(this, _T("Select file to send"));
+ if ( filedlg.ShowModal() != wxID_OK )
+ return;
+
+ wxFFile file(filedlg.GetFilename(), _T("r"));
+ wxString data;
+ if ( !file.IsOpened() || !file.ReadAll(&data) )
+ return;
+
+ // can't write the entire string at once, this risk overflowing the pipe
+ // and we would dead lock
+ size_t len = data.length();
+ const wxChar *pc = data.c_str();
+ while ( len )
+ {
+ const size_t CHUNK_SIZE = 4096;
+ m_out.Write(pc, len > CHUNK_SIZE ? CHUNK_SIZE : len);
+
+ // note that not all data could have been written as we don't block on
+ // the write end of the pipe
+ const size_t lenChunk = m_out.LastWrite();
+
+ pc += lenChunk;
+ len -= lenChunk;
+
+ DoGet();
+ }
+}
+
+void MyPipeFrame::DoGet()
+{
+ // we don't have any way to be notified when any input appears on the
+ // stream so we have to poll it :-(
+ DoGetFromStream(m_textIn, m_in);
+ DoGetFromStream(m_textErr, m_err);
+}
+
+void MyPipeFrame::DoGetFromStream(wxTextCtrl *text, wxInputStream& in)
+{
+ while ( in.CanRead() )
+ {
+ wxChar buffer[4096];
+ buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = _T('\0');
+
+ text->AppendText(buffer);
+ }
+}
+
+void MyPipeFrame::DoClose()
+{
+ m_process->CloseOutput();
+
+ DisableInput();
+}
+
+void MyPipeFrame::DisableInput()
+{
+ m_textOut->SetEditable(false);
+ FindWindow(Exec_Btn_Send)->Disable();
+ FindWindow(Exec_Btn_SendFile)->Disable();
+ FindWindow(Exec_Btn_Close)->Disable();
+}
+
+void MyPipeFrame::DisableOutput()
+{
+ FindWindow(Exec_Btn_Get)->Disable();
+}
+
+void MyPipeFrame::OnClose(wxCloseEvent& event)
+{
+ if ( m_process )
+ {
+ // we're not interested in getting the process termination notification
+ // if we are closing it ourselves
+ wxProcess *process = m_process;
+ m_process = NULL;
+ process->SetNextHandler(NULL);
+
+ process->CloseOutput();
+ }
+
+ event.Skip();
+}
+
+void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event))
+{
+ DoGet();
+
+ delete m_process;
+ m_process = NULL;
+
+ wxLogWarning(_T("The other process has terminated, closing"));
+
+ DisableInput();
+ DisableOutput();
+}