X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ebe887ed03623b97508eb5a6959ba043fd2faa19..7f6cf37004ce42bba674e577b8a39b853aa08254:/samples/ipc/baseclient.cpp diff --git a/samples/ipc/baseclient.cpp b/samples/ipc/baseclient.cpp index 91c887b709..4543148f41 100644 --- a/samples/ipc/baseclient.cpp +++ b/samples/ipc/baseclient.cpp @@ -7,7 +7,7 @@ // Created: 2007-11-08 // RCS-ID: $Id$ // Copyright: (c) 2007 Anders Larsen -// License: wxWindows licence +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -33,65 +33,82 @@ // we're using TCP/IP or real DDE. #include "ipcsetup.h" +#include "connection.h" + #include "wx/timer.h" #include "wx/datetime.h" +#include "wx/vector.h" + +class MyClient; // ---------------------------------------------------------------------------- -// wxWin macros +// classes // ---------------------------------------------------------------------------- - -// Define a new application -class MyClient; -class MyConnection; - -class MyApp: public wxApp +class MyApp : public wxApp { public: + MyApp() { Connect(wxEVT_IDLE, wxIdleEventHandler(MyApp::OnIdle)); } + virtual bool OnInit(); virtual int OnExit(); -protected: - MyClient *m_client; +private: + void OnIdle(wxIdleEvent& event); + + MyClient *m_client; }; -class MyConnection: public wxConnection +class MyConnection : public MyConnectionBase { public: - MyConnection(); - virtual ~MyConnection(); virtual bool DoExecute(const void *data, size_t size, wxIPCFormat format); virtual const void *Request(const wxString& item, size_t *size = NULL, wxIPCFormat format = wxIPC_TEXT); virtual bool DoPoke(const wxString& item, const void* data, size_t size, wxIPCFormat format); virtual bool OnAdvise(const wxString& topic, const wxString& item, const void *data, size_t size, wxIPCFormat format); virtual bool OnDisconnect(); - -protected: - void Log(const wxString& command, const wxString& topic, - const wxString& item, const void *data, size_t size, wxIPCFormat format); }; -class MyClient: public wxClient, public wxTimer +class MyClient : public wxClient, + private wxTimer { public: MyClient(); virtual ~MyClient(); + bool Connect(const wxString& sHost, const wxString& sService, const wxString& sTopic); void Disconnect(); wxConnectionBase *OnMakeConnection(); bool IsConnected() { return m_connection != NULL; }; + virtual void Notify(); -protected: - MyConnection *m_connection; - int m_step; + void StartNextTestIfNecessary(); + +private: + void TestRequest(); + void TestPoke(); + void TestExecute(); + void TestStartAdvise(); + void TestStopAdvise(); + void TestDisconnect(); + + + MyConnection *m_connection; + + // the test functions to be executed by StartNextTestIfNecessary() + typedef void (MyClient::*MyClientTestFunc)(); + wxVector m_tests; + + // number of seconds since the start of the test + int m_step; }; // ============================================================================ // implementation // ============================================================================ -IMPLEMENT_APP(MyApp) +IMPLEMENT_APP_CONSOLE(MyApp) // ---------------------------------------------------------------------------- // MyApp @@ -104,14 +121,12 @@ bool MyApp::OnInit() if ( !wxApp::OnInit() ) return false; - delete wxLog::SetActiveTarget(new wxLogStderr); - // Create a new client m_client = new MyClient; bool retval = m_client->Connect("localhost", "4242", "IPC TEST"); - wxLogMessage(_T("Client host=\"localhost\" port=\"4242\" topic=\"IPC TEST\" %s"), - retval ? _T("connected") : _T("failed to connect")); + wxLogMessage("Client host=\"localhost\" port=\"4242\" topic=\"IPC TEST\" %s", + retval ? "connected" : "failed to connect"); return retval; } @@ -123,25 +138,40 @@ int MyApp::OnExit() return 0; } +void MyApp::OnIdle(wxIdleEvent& event) +{ + if ( m_client ) + m_client->StartNextTestIfNecessary(); + + event.Skip(); +} + // ---------------------------------------------------------------------------- // MyClient // ---------------------------------------------------------------------------- -MyClient::MyClient() : wxClient() +MyClient::MyClient() + : wxClient() { m_connection = NULL; m_step = 0; } -bool MyClient::Connect(const wxString& sHost, const wxString& sService, const wxString& sTopic) +bool +MyClient::Connect(const wxString& sHost, + const wxString& sService, + const wxString& sTopic) { // suppress the log messages from MakeConnection() wxLogNull nolog; m_connection = (MyConnection *)MakeConnection(sHost, sService, sTopic); - if (m_connection) - Start(1000, false); - return m_connection != NULL; + if ( !m_connection ) + return false; + + Start(1000); + + return true; } wxConnectionBase *MyClient::OnMakeConnection() @@ -154,9 +184,8 @@ void MyClient::Disconnect() if (m_connection) { m_connection->Disconnect(); - delete m_connection; - m_connection = NULL; - wxLogMessage(_T("Client disconnected from server")); + wxDELETE(m_connection); + wxLogMessage("Client disconnected from server"); } wxGetApp().ExitMainLoop(); } @@ -168,139 +197,147 @@ MyClient::~MyClient() void MyClient::Notify() { - switch (m_step++) + // we shouldn't call wxIPC methods from here directly as we may be called + // from inside an IPC call when using TCP/IP as the sockets are used in + // non-blocking code and so can dispatch events, including the timer ones, + // while waiting for IO and so starting another IPC call would result in + // fatal reentrancies -- instead, just set a flag and perform the test + // indicated by it later from our idle event handler + MyClientTestFunc testfunc = NULL; + switch ( m_step++ ) { case 0: - { - size_t size; - m_connection->Request(_T("Date")); - m_connection->Request(_T("Date+len"), &size); - m_connection->Request(_T("bytes[3]"), &size, wxIPC_PRIVATE); + testfunc = &MyClient::TestRequest; break; - } + case 1: - { - wxString s = wxDateTime::Now().Format(); - m_connection->Poke(_T("Date"), s); - s = wxDateTime::Now().FormatTime() + _T(" ") + wxDateTime::Now().FormatDate(); - m_connection->Poke(_T("Date"), (const char *)s.c_str(), s.length() + 1); - char bytes[3]; - bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3'; - m_connection->Poke(_T("bytes[3]"), bytes, 3, wxIPC_PRIVATE); + testfunc = &MyClient::TestPoke; break; - } + case 2: - { - wxString s = _T("Date"); - m_connection->Execute(s); - m_connection->Execute((const char *)s.c_str(), s.length() + 1); -#if wxUSE_DDE_FOR_IPC - wxLogMessage(_T("DDE Execute can only be used to send text strings, not arbitrary data.\nThe type argument will be ignored, text truncated, converted to Unicode and null terminated.")); -#endif - char bytes[3]; - bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3'; - m_connection->Execute(bytes, 3, wxIPC_PRIVATE); + testfunc = &MyClient::TestExecute; break; - } + case 3: - wxLogMessage(_T("StartAdvise(\"something\")")); - m_connection->StartAdvise(_T("something")); + testfunc = &MyClient::TestStartAdvise; break; + case 10: - wxLogMessage(_T("StopAdvise(\"something\")")); - m_connection->StopAdvise(_T("something")); + testfunc = &MyClient::TestStopAdvise; break; + case 15: - Disconnect(); + testfunc = &MyClient::TestDisconnect; + // We don't need the timer any more, we're going to exit soon. + Stop(); break; + + default: + // No need to wake up idle handling. + return; } + + m_tests.push_back(testfunc); + + wxWakeUpIdle(); } -// ---------------------------------------------------------------------------- -// MyConnection -// ---------------------------------------------------------------------------- +void MyClient::StartNextTestIfNecessary() +{ + while ( !m_tests.empty() ) + { + MyClientTestFunc testfunc = m_tests.front(); + m_tests.erase(m_tests.begin()); + (this->*testfunc)(); + } +} -MyConnection::MyConnection() +void MyClient::TestRequest() { + size_t size; + m_connection->Request("Date"); + m_connection->Request("Date+len", &size); + m_connection->Request("bytes[3]", &size, wxIPC_PRIVATE); } -MyConnection::~MyConnection() +void MyClient::TestPoke() { + wxString s = wxDateTime::Now().Format(); + m_connection->Poke("Date", s); + s = wxDateTime::Now().FormatTime() + " " + wxDateTime::Now().FormatDate(); + m_connection->Poke("Date", (const char *)s.c_str(), s.length() + 1); + char bytes[3]; + bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3'; + m_connection->Poke("bytes[3]", bytes, 3, wxIPC_PRIVATE); } -void MyConnection::Log(const wxString& command, const wxString& topic, - const wxString& item, const void *data, size_t size, wxIPCFormat format) +void MyClient::TestExecute() { - wxString s; - if (topic.IsEmpty() && item.IsEmpty()) - s.Printf(_T("%s("), command.c_str()); - else if (topic.IsEmpty()) - s.Printf(_T("%s(item=\"%s\","), command.c_str(), item.c_str()); - else if (item.IsEmpty()) - s.Printf(_T("%s(topic=\"%s\","), command.c_str(), topic.c_str()); - else - s.Printf(_T("%s(topic=\"%s\",item=\"%s\","), command.c_str(), topic.c_str(), item.c_str()); - - switch (format) - { - case wxIPC_TEXT: - case wxIPC_UTF8TEXT: -#if !wxUSE_UNICODE || wxUSE_UNICODE_UTF8 - wxLogMessage(_T("%s\"%s\",%d)"), s.c_str(), data, size); -#else - wxLogMessage(_T("%s\"%s\",%d)"), s.c_str(), wxConvUTF8.cMB2WC((const char*)data), size); -#endif - break; - case wxIPC_PRIVATE: - if (size == 3) - { - char *bytes = (char *)data; - wxLogMessage(_T("%s'%c%c%c',%d)"), s.c_str(), bytes[0], bytes[1], bytes[2], size); - } - else - wxLogMessage(_T("%s...,%d)"), s.c_str(), size); - break; - case wxIPC_INVALID: - wxLogMessage(_T("%s[invalid data],%d)"), s.c_str(), size); - break; - default: - wxLogMessage(_T("%s[unknown data],%d)"), s.c_str(), size); - break; - } + wxString s = "Date"; + m_connection->Execute(s); + m_connection->Execute((const char *)s.c_str(), s.length() + 1); + char bytes[3]; + bytes[0] = '1'; + bytes[1] = '2'; + bytes[2] = '3'; + m_connection->Execute(bytes, WXSIZEOF(bytes)); +} + +void MyClient::TestStartAdvise() +{ + wxLogMessage("StartAdvise(\"something\")"); + m_connection->StartAdvise("something"); +} + +void MyClient::TestStopAdvise() +{ + wxLogMessage("StopAdvise(\"something\")"); + m_connection->StopAdvise("something"); } +void MyClient::TestDisconnect() +{ + Disconnect(); +} + +// ---------------------------------------------------------------------------- +// MyConnection +// ---------------------------------------------------------------------------- + bool MyConnection::OnAdvise(const wxString& topic, const wxString& item, const void *data, size_t size, wxIPCFormat format) { - Log(_T("OnAdvise"), topic, item, data, size, format); + Log("OnAdvise", topic, item, data, size, format); return true; } bool MyConnection::OnDisconnect() { - wxLogMessage(_T("OnDisconnect()")); + wxLogMessage("OnDisconnect()"); wxGetApp().ExitMainLoop(); return true; } bool MyConnection::DoExecute(const void *data, size_t size, wxIPCFormat format) { - Log(_T("Execute"), wxEmptyString, wxEmptyString, data, size, format); + Log("Execute", wxEmptyString, wxEmptyString, data, size, format); bool retval = wxConnection::DoExecute(data, size, format); if (!retval) - wxLogMessage(_T("Execute failed!")); + { + wxLogMessage("Execute failed!"); + } return retval; } const void *MyConnection::Request(const wxString& item, size_t *size, wxIPCFormat format) { const void *data = wxConnection::Request(item, size, format); - Log(_T("Request"), wxEmptyString, item, data, size ? *size : wxNO_LEN, format); + Log("Request", wxEmptyString, item, data, size ? *size : wxNO_LEN, format); return data; } bool MyConnection::DoPoke(const wxString& item, const void *data, size_t size, wxIPCFormat format) { - Log(_T("Poke"), wxEmptyString, item, data, size, format); + Log("Poke", wxEmptyString, item, data, size, format); return wxConnection::DoPoke(item, data, size, format); }