Hi CBers. I want to use the PipedProcess class (defined in the SDK) to execute some console commands and capture the input/output in the Interpreted Languages plugin that I've been working on. I can't figure out what I'm supposed to pass to as the first argument to the constructor. From the SDK:
PipedProcess::PipedProcess(void** pvThis, wxEvtHandler* parent, int id, bool pipe, const wxString& dir)
: wxProcess(parent, id),
m_Parent(parent),
m_Id(id),
m_Pid(0),
m_pvThis(pvThis)
{
wxSetWorkingDirectory(UnixFilename(dir));
if (pipe)
Redirect();
}
so what should I be passing as pvThis? Just an uninitialized pointer?
I can't figure out what I'm supposed to pass to as the first argument to the constructor.
The first parameter takes a pointer to the PipedProcess* variable you are just creating. You can pass NULL if you want, but I wouldn't advise it. The reason it's there is because when the piped process closes its handles, your variable (in your code) gets NULLed automatically. Perhaps some pseudocode will help explain better:
wxProcess* myProcess = 0;
myProcess = new PipedProcess(&myProcess, blah, blah);
...
(process executes, you get data, etc)
...
(now you want to send a command through the process)
if (myProcess)
myProcess->SendString(_T("break main.cpp:8"));
...
(if the process had died, myProcess would have been nulled automatically)
(else the call proceeds)
As for it being void**, well, that's because you could actually put any pointer there you would like nulled when the process dies. You might put there a pointer to char* if you like: PipedProcess doesn't care. It will still null it.
thanks for the responses from all of you. I now have a slightly better understanding.
My next stumbling block: It doesn't look like EVT_PIPEDPROCESS_STDOUT messages get passed to standard CB plugins? (unless i've done something silly - quite likely)
Code snipped:
BEGIN_EVENT_TABLE(InterpretedLangs, cbPlugin)
EVT_MENU(ID_LangMenu_RunPiped,InterpretedLangs::OnRunPiped)
EVT_PIPEDPROCESS_STDOUT(ID_PipedProcess, InterpretedLangs::OnPipedOutput)
END_EVENT_TABLE()
void InterpretedLangs::OnPipedOutput(wxCommandEvent& event)
{
wxMessageBox(_T("Piped output"));
wxString msg = event.GetString();
if (!msg.IsEmpty())
{
wxMessageBox(msg);
}
}
void InterpretedLangs::OnRunPiped(wxCommandEvent &event)
{
m_pp=new PipedProcess((void **)&m_pp,this,ID_PipedProcess);
m_pp->Launch(_T("C:/Python25/python.exe"),100);
}
As you can see, I have a menu item that calls OnRunPiped, which opens the piped process with unique identifier ID_PipedProcess. This works, but I don't seem to receive any EVT_PIPEDPROCESS_STDOUT messages. On the other hand, if I just call m_pp->Read(...) (not shown) there is stuff coming in through standard out.
Unrelated Question: Why is wxString manipulation so poor? It doesn't seem to be able convert char *, int, double etc to wxStrings (or back). Is this just incompleteness of unicode wxWidgets?
so what is the standard way of converting int/float/double to a unicode wxString and back? operator<<, operator>> and the relevant constructor appear to simply fail without warning.
"...simply fail without warning." So true! Unicode string streaming is terrible.
The following code snippets from others may be of interest to you.
#include <sstream>
// Read in and set window position --------------------------------
wxFileConfig cfgFile(wxTheApp->GetAppName(), // appname
wxEmptyString, // vendor
wxEmptyString, // local filename
wxEmptyString, // global file
wxCONFIG_USE_LOCAL_FILE);
wxString winPos;
cfgFile.Read(_T("WindowPosition"), &winPos) ;
if ( not winPos.IsEmpty() )
{ long windowXpos, windowYpos, windowWidth, windowHeight;
wxWX2MBbuf buf = cbU2C(winPos);
std::string cstring( buf );
std::stringstream istream(cstring);
istream >> windowXpos ;
istream >> windowYpos ;
istream >> windowWidth ;
istream >> windowHeight ;
this->SetSize(windowXpos, windowYpos, windowWidth, windowHeight);
}
// Record position ------------------------------------------------------
wxFileConfig cfgFile(g_AppName, // appname
wxEmptyString, // vendor
wxEmptyString, // local filename
wxEmptyString, // global file
wxCONFIG_USE_LOCAL_FILE);
wxWindow* pwin = wxTheApp->GetTopWindow();
int winXposn, winYposn, winWidth, winHeight;
pwin->GetPosition( &winXposn, &winYposn );
pwin->GetSize( &winWidth, &winHeight );
// Using std::stringstream; wxStringStream dont work in unicode
std::string cwinPos;
std::ostringstream ostream;
ostream << winXposn <<" " << winYposn <<" " << winWidth <<" " <<winHeight;
cwinPos = ostream.str();
wxString winPos = cbC2U( cwinPos.c_str());
cfgFile.Write(_T("WindowPosition"), winPos) ;
// This could also be done as:
winPos = winPos.Format(wxT("%d %d %d %d"),
winXposn, winYposn, winWidth, winHeight);
Conversions:
#include <wx/string.h>
// Return @c str as a proper unicode-compatible string
wxString cbC2U(const char* str)
{
#if wxUSE_UNICODE
return wxString(str, wxConvUTF8);
#else
return wxString(str);
#endif
}
// Return multibyte (C string) representation of the string
wxWX2MBbuf cbU2C(const wxString& str)
{
#if wxUSE_UNICODE
return str.mb_str(wxConvUTF8);
#else
return (wxChar*)str.mb_str();
#endif
}
No, no...
EVT_PIPEDPROCESS_STDOUT works fine (proven).
PipedProcess::Launch() doesn't work and it's not used.
whoops. anyway, I went back to basics and did some exploration with wxProcess to pipe a simple python debug session and send something down the output stream and retrieve from the input stream - this works - see code snippet below. Perhaps someone can tell me how it could be done more efficiently with a PipedProcess and the role of the Idle message handler (I tried to implement the latter but it just crashed C::B). I'm still confused by PipedProcess - do i need to setup a wxTimer to poll stdout buffer, or does processing EVT_PIPEDPROCESS_STDOUT handle all this for me. The latter doesn't seem to be the case, and if not how do I tell EVT_PIPEDPROCESS_STDOUT to hijack the timer that I create?? Sacrificing a goat to Bjarne + going through the source code, macro definitions, wxWidgets docs and C::B wikis trying to figure this out is killing me - I had a hard enough time with the python interpreter until i realized it doesn't update stdin and stdout if you don't specify the right set of options
BEGIN_EVENT_TABLE(InterpretedLangs, cbPlugin)
EVT_MENU(ID_LangMenu_RunPiped,InterpretedLangs::OnRunPiped)
EVT_TIMER(ID_TimerPollDebugger, InterpretedLangs::OnTimer)
...
END_EVENT_TABLE()
void InterpretedLangs::OnTimer(wxTimerEvent& event)
{
if (m_pp && m_pp->IsInputAvailable())
{
char buf0[1001]; //Sloppy i know - was in a hurry
for(int i=0;i<1001;++i)
buf0[i]=0;
m_istream->Read(buf0,1000);
wxString sbuf=wxString::FromAscii(buf0);
wxMessageBox(sbuf);
}
}
void InterpretedLangs::OnRunPiped(wxCommandEvent &event)
{
m_TimerPollDebugger=new wxTimer(this, ID_TimerPollDebugger);
m_TimerPollDebugger->Start(100);
m_pp=new wxProcess(this,ID_PipedProcess);
m_pp->Redirect();
wxExecute(_T("c:/python25/python.exe -u -m pdb c:/python25/test.py"),wxEXEC_ASYNC,m_pp);
m_ostream=m_pp->GetOutputStream();
m_ostream->Write("w\n",2);
m_istream=m_pp->GetInputStream();
}
wxString::Format(_T("%d, %5.2f"), i, f);
color me pleasantly surprised. I gave up on the wxstring stream style commands after wxstring::printf didn't work.