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