]> git.saurik.com Git - wxWidgets.git/blob - samples/ipc/baseclient.cpp
Make storing non-trivial data in wxThreadSpecificInfo possible.
[wxWidgets.git] / samples / ipc / baseclient.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: samples/ipc/baseclient.cpp
3 // Purpose: IPC sample: console client
4 // Author: Anders Larsen
5 // Most of the code was stolen from: samples/ipc/client.cpp
6 // (c) Julian Smart, Jurgen Doornik
7 // Created: 2007-11-08
8 // Copyright: (c) 2007 Anders Larsen
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/wx.h"
29 #endif
30
31 // Settings common to both executables: determines whether
32 // we're using TCP/IP or real DDE.
33 #include "ipcsetup.h"
34
35 #include "connection.h"
36
37 #include "wx/timer.h"
38 #include "wx/datetime.h"
39 #include "wx/vector.h"
40
41 class MyClient;
42
43 // ----------------------------------------------------------------------------
44 // classes
45 // ----------------------------------------------------------------------------
46
47 class MyApp : public wxApp
48 {
49 public:
50 MyApp() { Connect(wxEVT_IDLE, wxIdleEventHandler(MyApp::OnIdle)); }
51
52 virtual bool OnInit();
53 virtual int OnExit();
54
55 private:
56 void OnIdle(wxIdleEvent& event);
57
58 MyClient *m_client;
59 };
60
61 class MyConnection : public MyConnectionBase
62 {
63 public:
64 virtual bool DoExecute(const void *data, size_t size, wxIPCFormat format);
65 virtual const void *Request(const wxString& item, size_t *size = NULL, wxIPCFormat format = wxIPC_TEXT);
66 virtual bool DoPoke(const wxString& item, const void* data, size_t size, wxIPCFormat format);
67 virtual bool OnAdvise(const wxString& topic, const wxString& item, const void *data, size_t size, wxIPCFormat format);
68 virtual bool OnDisconnect();
69 };
70
71 class MyClient : public wxClient,
72 private wxTimer
73 {
74 public:
75 MyClient();
76 virtual ~MyClient();
77
78 bool Connect(const wxString& sHost, const wxString& sService, const wxString& sTopic);
79 void Disconnect();
80 wxConnectionBase *OnMakeConnection();
81 bool IsConnected() { return m_connection != NULL; };
82
83 virtual void Notify();
84
85 void StartNextTestIfNecessary();
86
87 private:
88 void TestRequest();
89 void TestPoke();
90 void TestExecute();
91 void TestStartAdvise();
92 void TestStopAdvise();
93 void TestDisconnect();
94
95
96 MyConnection *m_connection;
97
98 // the test functions to be executed by StartNextTestIfNecessary()
99 typedef void (MyClient::*MyClientTestFunc)();
100 wxVector<MyClientTestFunc> m_tests;
101
102 // number of seconds since the start of the test
103 int m_step;
104 };
105
106 // ============================================================================
107 // implementation
108 // ============================================================================
109
110 IMPLEMENT_APP_CONSOLE(MyApp)
111
112 // ----------------------------------------------------------------------------
113 // MyApp
114 // ----------------------------------------------------------------------------
115
116 // The `main program' equivalent, creating the windows and returning the
117 // main frame
118 bool MyApp::OnInit()
119 {
120 if ( !wxApp::OnInit() )
121 return false;
122
123 // Create a new client
124 m_client = new MyClient;
125 bool retval = m_client->Connect("localhost", "4242", "IPC TEST");
126
127 wxLogMessage("Client host=\"localhost\" port=\"4242\" topic=\"IPC TEST\" %s",
128 retval ? "connected" : "failed to connect");
129
130 return retval;
131 }
132
133 int MyApp::OnExit()
134 {
135 delete m_client;
136
137 return 0;
138 }
139
140 void MyApp::OnIdle(wxIdleEvent& event)
141 {
142 if ( m_client )
143 m_client->StartNextTestIfNecessary();
144
145 event.Skip();
146 }
147
148 // ----------------------------------------------------------------------------
149 // MyClient
150 // ----------------------------------------------------------------------------
151
152 MyClient::MyClient()
153 : wxClient()
154 {
155 m_connection = NULL;
156 m_step = 0;
157 }
158
159 bool
160 MyClient::Connect(const wxString& sHost,
161 const wxString& sService,
162 const wxString& sTopic)
163 {
164 // suppress the log messages from MakeConnection()
165 wxLogNull nolog;
166
167 m_connection = (MyConnection *)MakeConnection(sHost, sService, sTopic);
168 if ( !m_connection )
169 return false;
170
171 Start(1000);
172
173 return true;
174 }
175
176 wxConnectionBase *MyClient::OnMakeConnection()
177 {
178 return new MyConnection;
179 }
180
181 void MyClient::Disconnect()
182 {
183 if (m_connection)
184 {
185 m_connection->Disconnect();
186 wxDELETE(m_connection);
187 wxLogMessage("Client disconnected from server");
188 }
189 wxGetApp().ExitMainLoop();
190 }
191
192 MyClient::~MyClient()
193 {
194 Disconnect();
195 }
196
197 void MyClient::Notify()
198 {
199 // we shouldn't call wxIPC methods from here directly as we may be called
200 // from inside an IPC call when using TCP/IP as the sockets are used in
201 // non-blocking code and so can dispatch events, including the timer ones,
202 // while waiting for IO and so starting another IPC call would result in
203 // fatal reentrancies -- instead, just set a flag and perform the test
204 // indicated by it later from our idle event handler
205 MyClientTestFunc testfunc = NULL;
206 switch ( m_step++ )
207 {
208 case 0:
209 testfunc = &MyClient::TestRequest;
210 break;
211
212 case 1:
213 testfunc = &MyClient::TestPoke;
214 break;
215
216 case 2:
217 testfunc = &MyClient::TestExecute;
218 break;
219
220 case 3:
221 testfunc = &MyClient::TestStartAdvise;
222 break;
223
224 case 10:
225 testfunc = &MyClient::TestStopAdvise;
226 break;
227
228 case 15:
229 testfunc = &MyClient::TestDisconnect;
230 // We don't need the timer any more, we're going to exit soon.
231 Stop();
232 break;
233
234 default:
235 // No need to wake up idle handling.
236 return;
237 }
238
239 m_tests.push_back(testfunc);
240
241 wxWakeUpIdle();
242 }
243
244 void MyClient::StartNextTestIfNecessary()
245 {
246 while ( !m_tests.empty() )
247 {
248 MyClientTestFunc testfunc = m_tests.front();
249 m_tests.erase(m_tests.begin());
250 (this->*testfunc)();
251 }
252 }
253
254 void MyClient::TestRequest()
255 {
256 size_t size;
257 m_connection->Request("Date");
258 m_connection->Request("Date+len", &size);
259 m_connection->Request("bytes[3]", &size, wxIPC_PRIVATE);
260 }
261
262 void MyClient::TestPoke()
263 {
264 wxString s = wxDateTime::Now().Format();
265 m_connection->Poke("Date", s);
266 s = wxDateTime::Now().FormatTime() + " " + wxDateTime::Now().FormatDate();
267 m_connection->Poke("Date", (const char *)s.c_str(), s.length() + 1);
268 char bytes[3];
269 bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3';
270 m_connection->Poke("bytes[3]", bytes, 3, wxIPC_PRIVATE);
271 }
272
273 void MyClient::TestExecute()
274 {
275 wxString s = "Date";
276 m_connection->Execute(s);
277 m_connection->Execute((const char *)s.c_str(), s.length() + 1);
278 char bytes[3];
279 bytes[0] = '1';
280 bytes[1] = '2';
281 bytes[2] = '3';
282 m_connection->Execute(bytes, WXSIZEOF(bytes));
283 }
284
285 void MyClient::TestStartAdvise()
286 {
287 wxLogMessage("StartAdvise(\"something\")");
288 m_connection->StartAdvise("something");
289 }
290
291 void MyClient::TestStopAdvise()
292 {
293 wxLogMessage("StopAdvise(\"something\")");
294 m_connection->StopAdvise("something");
295 }
296
297 void MyClient::TestDisconnect()
298 {
299 Disconnect();
300 }
301
302 // ----------------------------------------------------------------------------
303 // MyConnection
304 // ----------------------------------------------------------------------------
305
306 bool MyConnection::OnAdvise(const wxString& topic, const wxString& item, const void *data,
307 size_t size, wxIPCFormat format)
308 {
309 Log("OnAdvise", topic, item, data, size, format);
310 return true;
311 }
312
313 bool MyConnection::OnDisconnect()
314 {
315 wxLogMessage("OnDisconnect()");
316 wxGetApp().ExitMainLoop();
317 return true;
318 }
319
320 bool MyConnection::DoExecute(const void *data, size_t size, wxIPCFormat format)
321 {
322 Log("Execute", wxEmptyString, wxEmptyString, data, size, format);
323 bool retval = wxConnection::DoExecute(data, size, format);
324 if (!retval)
325 {
326 wxLogMessage("Execute failed!");
327 }
328 return retval;
329 }
330
331 const void *MyConnection::Request(const wxString& item, size_t *size, wxIPCFormat format)
332 {
333 const void *data = wxConnection::Request(item, size, format);
334 Log("Request", wxEmptyString, item, data, size ? *size : wxNO_LEN, format);
335 return data;
336 }
337
338 bool MyConnection::DoPoke(const wxString& item, const void *data, size_t size, wxIPCFormat format)
339 {
340 Log("Poke", wxEmptyString, item, data, size, format);
341 return wxConnection::DoPoke(item, data, size, format);
342 }