+ m_hInput = hInput;
+}
+
+wxPipeInputStream::~wxPipeInputStream()
+{
+ if ( m_hInput != INVALID_HANDLE_VALUE )
+ ::CloseHandle(m_hInput);
+}
+
+bool wxPipeInputStream::CanRead() const
+{
+ // we can read if there's something in the put back buffer
+ // even pipe is closed
+ if ( m_wbacksize > m_wbackcur )
+ return true;
+
+ wxPipeInputStream * const self = wxConstCast(this, wxPipeInputStream);
+
+ if ( !IsOpened() )
+ {
+ // set back to mark Eof as it may have been unset by Ungetch()
+ self->m_lasterror = wxSTREAM_EOF;
+ return false;
+ }
+
+ DWORD nAvailable;
+
+ // function name is misleading, it works with anon pipes as well
+ DWORD rc = ::PeekNamedPipe
+ (
+ m_hInput, // handle
+ NULL, 0, // ptr to buffer and its size
+ NULL, // [out] bytes read
+ &nAvailable, // [out] bytes available
+ NULL // [out] bytes left
+ );
+
+ if ( !rc )
+ {
+ if ( ::GetLastError() != ERROR_BROKEN_PIPE )
+ {
+ // unexpected error
+ wxLogLastError(wxT("PeekNamedPipe"));
+ }
+
+ // don't try to continue reading from a pipe if an error occurred or if
+ // it had been closed
+ ::CloseHandle(m_hInput);
+
+ self->m_hInput = INVALID_HANDLE_VALUE;
+ self->m_lasterror = wxSTREAM_EOF;
+
+ nAvailable = 0;
+ }
+
+ return nAvailable != 0;
+}
+
+size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
+{
+ if ( !IsOpened() )
+ {
+ m_lasterror = wxSTREAM_EOF;
+
+ return 0;
+ }
+
+ DWORD bytesRead;
+ if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
+ {
+ m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
+ ? wxSTREAM_EOF
+ : wxSTREAM_READ_ERROR;
+ }
+
+ // bytesRead is set to 0, as desired, if an error occurred
+ return bytesRead;
+}
+
+// ----------------------------------------------------------------------------
+// wxPipeOutputStream
+// ----------------------------------------------------------------------------
+
+wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
+{
+ m_hOutput = hOutput;
+
+ // unblock the pipe to prevent deadlocks when we're writing to the pipe
+ // from which the child process can't read because it is writing in its own
+ // end of it
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
+ if ( !::SetNamedPipeHandleState
+ (
+ m_hOutput,
+ &mode,
+ NULL, // collection count (we don't set it)
+ NULL // timeout (we don't set it neither)
+ ) )
+ {
+ wxLogLastError(wxT("SetNamedPipeHandleState(PIPE_NOWAIT)"));
+ }
+}
+
+bool wxPipeOutputStream::Close()
+{
+ return ::CloseHandle(m_hOutput) != 0;
+}
+
+
+size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
+{
+ m_lasterror = wxSTREAM_NO_ERROR;
+
+ DWORD totalWritten = 0;
+ while ( len > 0 )
+ {
+ DWORD chunkWritten;
+ if ( !::WriteFile(m_hOutput, buffer, len, &chunkWritten, NULL) )
+ {
+ m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
+ ? wxSTREAM_EOF
+ : wxSTREAM_WRITE_ERROR;
+ break;
+ }
+
+ if ( !chunkWritten )
+ break;
+
+ buffer = (char *)buffer + chunkWritten;
+ totalWritten += chunkWritten;
+ len -= chunkWritten;
+ }
+
+ return totalWritten;
+}
+
+#endif // wxUSE_STREAMS
+
+// ============================================================================
+// wxExecute functions family
+// ============================================================================
+
+#if wxUSE_IPC
+
+// connect to the given server via DDE and ask it to execute the command
+bool
+wxExecuteDDE(const wxString& ddeServer,
+ const wxString& ddeTopic,
+ const wxString& ddeCommand)
+{
+ bool ok wxDUMMY_INITIALIZE(false);
+
+ wxDDEClient client;
+ wxConnectionBase *
+ conn = client.MakeConnection(wxEmptyString, ddeServer, ddeTopic);
+ if ( !conn )
+ {
+ ok = false;
+ }
+ else // connected to DDE server
+ {
+ // the added complication here is that although most programs use
+ // XTYP_EXECUTE for their DDE API, some important ones -- like Word
+ // and other MS stuff - use XTYP_REQUEST!
+ //
+ // moreover, anotheri mportant program (IE) understands both but
+ // returns an error from Execute() so we must try Request() first
+ // to avoid doing it twice
+ {
+ // we're prepared for this one to fail, so don't show errors
+ wxLogNull noErrors;
+
+ ok = conn->Request(ddeCommand) != NULL;
+ }
+
+ if ( !ok )
+ {
+ // now try execute -- but show the errors
+ ok = conn->Execute(ddeCommand);
+ }
+ }
+
+ return ok;
+}
+
+#endif // wxUSE_IPC
+
+long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
+{
+ wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
+
+#if wxUSE_THREADS
+ // for many reasons, the code below breaks down if it's called from another
+ // thread -- this could be fixed, but as Unix versions don't support this
+ // neither I don't want to waste time on this now
+ wxASSERT_MSG( wxThread::IsMain(),
+ wxT("wxExecute() can be called only from the main thread") );
+#endif // wxUSE_THREADS