A few weeks of Unicode fixes (my old win95 laptop compiles sloowly,
[wxWidgets.git] / src / msw / dde.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dde.cpp
3 // Purpose: DDE classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "dde.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #endif
26
27 #if wxUSE_IPC
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/app.h"
32 #endif
33
34 #include "wx/module.h"
35 #include "wx/dde.h"
36
37 #include "wx/msw/private.h"
38 #include <windows.h>
39 #include <ddeml.h>
40
41 #ifndef __TWIN32__
42 #ifdef __GNUWIN32__
43 #include "wx/msw/gnuwin32/extra.h"
44 #endif
45 #endif
46
47 #include <string.h>
48
49 #ifdef __WIN32__
50 #define _EXPORT /**/
51 #else
52 #define _EXPORT _export
53 #endif
54
55 #if !USE_SHARED_LIBRARY
56 IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
57 IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
58 IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase)
59 #endif
60
61 static wxDDEConnection *DDEFindConnection(HCONV hConv);
62 static void DDEDeleteConnection(HCONV hConv);
63 static wxDDEServer *DDEFindServer(const wxString& s);
64
65 extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback(
66 WORD wType,
67 WORD wFmt,
68 HCONV hConv,
69 HSZ hsz1,
70 HSZ hsz2,
71 HDDEDATA hData,
72 DWORD lData1,
73 DWORD lData2);
74
75 // Add topic name to atom table before using in conversations
76 static HSZ DDEAddAtom(const wxString& string);
77 static HSZ DDEGetAtom(const wxString& string);
78 static void DDEPrintError(void);
79
80 static DWORD DDEIdInst = 0L;
81 static wxDDEConnection *DDECurrentlyConnecting = NULL;
82
83 static wxList wxAtomTable(wxKEY_STRING);
84 static wxList wxDDEClientObjects;
85 static wxList wxDDEServerObjects;
86
87 char *DDEDefaultIPCBuffer = NULL;
88 int DDEDefaultIPCBufferSize = 0;
89
90 /*
91 * Initialization
92 *
93 */
94
95 static bool DDEInitialized = FALSE;
96
97 void wxDDEInitialize()
98 {
99 if (DDEInitialized)
100 return;
101 DDEInitialized = TRUE;
102
103 // Should insert filter flags
104 DdeInitialize(&DDEIdInst, (PFNCALLBACK)MakeProcInstance(
105 (FARPROC)_DDECallback, wxGetInstance()),
106 APPCLASS_STANDARD,
107 0L);
108 }
109
110 /*
111 * CleanUp
112 */
113
114 void wxDDECleanUp()
115 {
116 if (DDEIdInst != 0)
117 {
118 DdeUninitialize(DDEIdInst);
119 DDEIdInst = 0;
120 }
121 if (DDEDefaultIPCBuffer)
122 delete [] DDEDefaultIPCBuffer ;
123 }
124
125 // A module to allow DDE initialization/cleanup
126 // without calling these functions from app.cpp or from
127 // the user's application.
128
129 class wxDDEModule: public wxModule
130 {
131 DECLARE_DYNAMIC_CLASS(wxDDEModule)
132 public:
133 wxDDEModule() {}
134 bool OnInit() { wxDDEInitialize(); return TRUE; };
135 void OnExit() { wxDDECleanUp(); };
136 };
137
138 IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
139
140 // Global find connection
141 static wxDDEConnection *DDEFindConnection(HCONV hConv)
142 {
143 wxNode *node = wxDDEServerObjects.First();
144 wxDDEConnection *found = NULL;
145 while (node && !found)
146 {
147 wxDDEServer *object = (wxDDEServer *)node->Data();
148 found = object->FindConnection((WXHCONV) hConv);
149 node = node->Next();
150 }
151 if (found)
152 return found;
153
154 node = wxDDEClientObjects.First();
155 while (node && !found)
156 {
157 wxDDEClient *object = (wxDDEClient *)node->Data();
158 found = object->FindConnection((WXHCONV) hConv);
159 node = node->Next();
160 }
161 return found;
162 }
163
164 // Global delete connection
165 static void DDEDeleteConnection(HCONV hConv)
166 {
167 wxNode *node = wxDDEServerObjects.First();
168 bool found = FALSE;
169 while (node && !found)
170 {
171 wxDDEServer *object = (wxDDEServer *)node->Data();
172 found = object->DeleteConnection((WXHCONV) hConv);
173 node = node->Next();
174 }
175 if (found)
176 return;
177
178 node = wxDDEServerObjects.First();
179 while (node && !found)
180 {
181 wxDDEClient *object = (wxDDEClient *)node->Data();
182 found = object->DeleteConnection((WXHCONV) hConv);
183 node = node->Next();
184 }
185 }
186
187 // Find a server from a service name
188 static wxDDEServer *DDEFindServer(const wxString& s)
189 {
190 wxNode *node = wxDDEServerObjects.First();
191 wxDDEServer *found = NULL;
192 while (node && !found)
193 {
194 wxDDEServer *object = (wxDDEServer *)node->Data();
195
196 if (object->GetServiceName() == s)
197 found = object;
198 else node = node->Next();
199 }
200 return found;
201 }
202
203 /*
204 * Server
205 *
206 */
207
208 wxDDEServer::wxDDEServer(void)
209 {
210 m_serviceName = "";
211 wxDDEServerObjects.Append(this);
212 }
213
214 bool wxDDEServer::Create(const wxString& server_name)
215 {
216 m_serviceName = server_name;
217 HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST server_name, CP_WINANSI);
218
219 if (DdeNameService(DDEIdInst, serviceName, (HSZ) NULL, DNS_REGISTER) == 0)
220 {
221 DDEPrintError();
222 return FALSE;
223 }
224 return TRUE;
225 }
226
227 wxDDEServer::~wxDDEServer(void)
228 {
229 if (m_serviceName != _T(""))
230 {
231 HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST m_serviceName, CP_WINANSI);
232 if (DdeNameService(DDEIdInst, serviceName, NULL, DNS_UNREGISTER) == 0)
233 {
234 DDEPrintError();
235 }
236 }
237 wxDDEServerObjects.DeleteObject(this);
238
239 wxNode *node = m_connections.First();
240 while (node)
241 {
242 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
243 wxNode *next = node->Next();
244 connection->OnDisconnect(); // May delete the node implicitly
245 node = next;
246 }
247
248 // If any left after this, delete them
249 node = m_connections.First();
250 while (node)
251 {
252 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
253 wxNode *next = node->Next();
254 delete connection;
255 node = next;
256 }
257 }
258
259 wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */)
260 {
261 return new wxDDEConnection;
262 }
263
264 wxDDEConnection *wxDDEServer::FindConnection(WXHCONV conv)
265 {
266 wxNode *node = m_connections.First();
267 wxDDEConnection *found = NULL;
268 while (node && !found)
269 {
270 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
271 if (connection->m_hConv == conv)
272 found = connection;
273 else node = node->Next();
274 }
275 return found;
276 }
277
278 // Only delete the entry in the map, not the actual connection
279 bool wxDDEServer::DeleteConnection(WXHCONV conv)
280 {
281 wxNode *node = m_connections.First();
282 bool found = FALSE;
283 while (node && !found)
284 {
285 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
286 if (connection->m_hConv == conv)
287 {
288 found = TRUE;
289 delete node;
290 }
291 else node = node->Next();
292 }
293 return found;
294 }
295
296
297 /*
298 * Client
299 *
300 */
301
302
303 wxDDEClient::wxDDEClient(void)
304 {
305 wxDDEClientObjects.Append(this);
306 }
307
308 wxDDEClient::~wxDDEClient(void)
309 {
310 wxDDEClientObjects.DeleteObject(this);
311 wxNode *node = m_connections.First();
312 while (node)
313 {
314 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
315 delete connection; // Deletes the node implicitly (see ~wxDDEConnection)
316 node = m_connections.First();
317 }
318 }
319
320 bool wxDDEClient::ValidHost(const wxString& /* host */)
321 {
322 return TRUE;
323 }
324
325 wxConnectionBase *wxDDEClient::MakeConnection(const wxString& /* host */, const wxString& server_name, const wxString& topic)
326 {
327 HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST server_name, CP_WINANSI);
328 HSZ topic_atom = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST topic, CP_WINANSI);
329
330 HCONV hConv = DdeConnect(DDEIdInst, serviceName, topic_atom, (PCONVCONTEXT)NULL);
331 if (hConv == (HCONV) NULL)
332 return (wxConnectionBase*) NULL;
333 else
334 {
335 wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection();
336 if (connection)
337 {
338 connection->m_hConv = (WXHCONV) hConv;
339 connection->m_topicName = topic;
340 connection->m_client = this;
341 m_connections.Append(connection);
342 return connection;
343 }
344 else return (wxConnectionBase*) NULL;
345 }
346 }
347
348 wxConnectionBase *wxDDEClient::OnMakeConnection(void)
349 {
350 return new wxDDEConnection;
351 }
352
353 wxDDEConnection *wxDDEClient::FindConnection(WXHCONV conv)
354 {
355 wxNode *node = m_connections.First();
356 wxDDEConnection *found = NULL;
357 while (node && !found)
358 {
359 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
360 if (connection->m_hConv == conv)
361 found = connection;
362 else node = node->Next();
363 }
364 return found;
365 }
366
367 // Only delete the entry in the map, not the actual connection
368 bool wxDDEClient::DeleteConnection(WXHCONV conv)
369 {
370 wxNode *node = m_connections.First();
371 bool found = FALSE;
372 while (node && !found)
373 {
374 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
375 if (connection->m_hConv == conv)
376 {
377 found = TRUE;
378 delete node;
379 }
380 else node = node->Next();
381 }
382 return found;
383 }
384
385 /*
386 * Connection
387 */
388
389 wxDDEConnection::wxDDEConnection(char *buffer, int size)
390 {
391 if (buffer == NULL)
392 {
393 if (DDEDefaultIPCBuffer == NULL)
394 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
395 m_bufPtr = DDEDefaultIPCBuffer;
396 m_bufSize = DDEDefaultIPCBufferSize;
397 }
398 else
399 {
400 m_bufPtr = buffer;
401 m_bufSize = size;
402 }
403
404 m_topicName = "";
405
406 m_client = NULL;
407 m_server = NULL;
408
409 m_hConv = 0;
410 m_sendingData = NULL;
411 }
412
413 wxDDEConnection::wxDDEConnection(void)
414 {
415 m_hConv = 0;
416 m_sendingData = NULL;
417 m_server = NULL;
418 m_client = NULL;
419 if (DDEDefaultIPCBuffer == NULL)
420 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
421
422 m_bufPtr = DDEDefaultIPCBuffer;
423 m_bufSize = DDEDefaultIPCBufferSize;
424 m_topicName = "";
425 }
426
427 wxDDEConnection::~wxDDEConnection(void)
428 {
429 if (m_server)
430 m_server->GetConnections().DeleteObject(this);
431 else
432 m_client->GetConnections().DeleteObject(this);
433 }
434
435 // Calls that CLIENT can make
436 bool wxDDEConnection::Disconnect(void)
437 {
438 DDEDeleteConnection((HCONV) m_hConv);
439 return (DdeDisconnect((HCONV) m_hConv) != 0);
440 }
441
442 bool wxDDEConnection::Execute(wxChar *data, int size, wxIPCFormat format)
443 {
444 DWORD result;
445 if (size < 0)
446 size = wxStrlen(data);
447
448 size ++;
449
450 return (DdeClientTransaction((LPBYTE)data, size, (HCONV) m_hConv,
451 NULL, format, XTYP_EXECUTE, 5000, &result) ? TRUE : FALSE);
452 }
453
454 char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
455 {
456 DWORD result;
457 HSZ atom = DDEGetAtom(item);
458
459 HDDEDATA returned_data = DdeClientTransaction(NULL, 0, (HCONV) m_hConv,
460 atom, format, XTYP_REQUEST, 5000, &result);
461
462 DWORD len = DdeGetData(returned_data, (LPBYTE)(m_bufPtr), m_bufSize, 0);
463
464 DdeFreeDataHandle(returned_data);
465
466 if (size) *size = (int)len;
467 if (len > 0)
468 {
469 return m_bufPtr;
470 }
471 else return NULL;
472 }
473
474 bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
475 {
476 DWORD result;
477 if (size < 0)
478 size = wxStrlen(data);
479
480 size ++;
481
482 HSZ item_atom = DDEGetAtom(item);
483 return (DdeClientTransaction((LPBYTE)data, size, (HCONV) m_hConv,
484 item_atom, format, XTYP_POKE, 5000, &result) ? TRUE : FALSE);
485 }
486
487 bool wxDDEConnection::StartAdvise(const wxString& item)
488 {
489 DWORD result;
490 HSZ atom = DDEGetAtom(item);
491
492 return (DdeClientTransaction(NULL, 0, (HCONV) m_hConv,
493 atom, CF_TEXT, XTYP_ADVSTART, 5000, &result) ? TRUE : FALSE);
494 }
495
496 bool wxDDEConnection::StopAdvise(const wxString& item)
497 {
498 DWORD result;
499 HSZ atom = DDEGetAtom(item);
500
501 return (DdeClientTransaction(NULL, 0, (HCONV) m_hConv,
502 atom, CF_TEXT, XTYP_ADVSTOP, 5000, &result) ? TRUE : FALSE);
503 }
504
505 // Calls that SERVER can make
506 bool wxDDEConnection::Advise(const wxString& item, wxChar *data, int size, wxIPCFormat format)
507 {
508 if (size < 0)
509 size = wxStrlen(data);
510
511 size ++;
512
513 HSZ item_atom = DDEGetAtom(item);
514 HSZ topic_atom = DDEGetAtom(m_topicName);
515 m_sendingData = data;
516 m_dataSize = size;
517 m_dataType = format;
518 return (DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0);
519 }
520
521 bool wxDDEConnection::OnDisconnect(void)
522 {
523 delete this;
524 return TRUE;
525 }
526
527
528 #define DDERETURN HDDEDATA
529
530 HDDEDATA EXPENTRY _EXPORT _DDECallback(
531 WORD wType,
532 WORD wFmt,
533 HCONV hConv,
534 HSZ hsz1,
535 HSZ hsz2,
536 HDDEDATA hData,
537 DWORD /* lData1 */,
538 DWORD /* lData2 */)
539 {
540 switch (wType)
541 {
542 case XTYP_CONNECT:
543 {
544 wxChar topic_buf[100];
545 wxChar server_buf[100];
546 DdeQueryString(DDEIdInst, hsz1, (LPTSTR)topic_buf, WXSIZEOF(topic_buf),
547 CP_WINANSI);
548 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)server_buf, WXSIZEOF(topic_buf),
549 CP_WINANSI);
550 wxDDEServer *server = DDEFindServer(server_buf);
551 if (server)
552 {
553 wxDDEConnection *connection =
554 (wxDDEConnection*) server->OnAcceptConnection(wxString(topic_buf));
555 if (connection)
556 {
557 connection->m_server = server;
558 server->GetConnections().Append(connection);
559 connection->m_hConv = 0;
560 connection->m_topicName = topic_buf;
561 DDECurrentlyConnecting = connection;
562 return (DDERETURN)TRUE;
563 }
564 }
565 else return (DDERETURN)0;
566 break;
567 }
568
569 case XTYP_CONNECT_CONFIRM:
570 {
571 if (DDECurrentlyConnecting)
572 {
573 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
574 DDECurrentlyConnecting = NULL;
575 return (DDERETURN)TRUE;
576 }
577 else return 0;
578 break;
579 }
580
581 case XTYP_DISCONNECT:
582 {
583 wxDDEConnection *connection = DDEFindConnection(hConv);
584 if (connection && connection->OnDisconnect())
585 {
586 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
587 return (DDERETURN)TRUE;
588 }
589 else return (DDERETURN)0;
590 break;
591 }
592
593 case XTYP_EXECUTE:
594 {
595 wxDDEConnection *connection = DDEFindConnection(hConv);
596
597 if (connection)
598 {
599 DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0);
600 DdeFreeDataHandle(hData);
601 if (connection->OnExecute(connection->m_topicName, connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt))
602 return (DDERETURN)DDE_FACK;
603 else
604 return (DDERETURN)DDE_FNOTPROCESSED;
605 } else return (DDERETURN)DDE_FNOTPROCESSED;
606 break;
607 }
608
609 case XTYP_REQUEST:
610 {
611 wxDDEConnection *connection = DDEFindConnection(hConv);
612
613 if (connection)
614 {
615 wxChar item_name[200];
616 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name),
617 CP_WINANSI);
618
619 int user_size = -1;
620 char *data = connection->OnRequest(connection->m_topicName, wxString(item_name), &user_size, (wxIPCFormat) wFmt);
621 if (data)
622 {
623 if (user_size < 0) user_size = strlen(data);
624
625 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
626 (LPBYTE)data, user_size + 1, 0, hsz2, wFmt, 0);
627 return (DDERETURN)handle;
628 } else return (DDERETURN)0;
629 } else return (DDERETURN)0;
630 break;
631 }
632
633 case XTYP_POKE:
634 {
635 wxDDEConnection *connection = DDEFindConnection(hConv);
636
637 if (connection)
638 {
639 wxChar item_name[200];
640 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name),
641 CP_WINANSI);
642 DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0);
643 DdeFreeDataHandle(hData);
644 connection->OnPoke(connection->m_topicName, wxString(item_name), connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt);
645 return (DDERETURN)DDE_FACK;
646 } else return (DDERETURN)DDE_FNOTPROCESSED;
647 break;
648 }
649
650 case XTYP_ADVSTART:
651 {
652 wxDDEConnection *connection = DDEFindConnection(hConv);
653
654 if (connection)
655 {
656 wxChar item_name[200];
657 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name),
658 CP_WINANSI);
659
660 return (DDERETURN)connection->OnStartAdvise(connection->m_topicName, wxString(item_name));
661 } else return (DDERETURN)0;
662 break;
663 }
664
665 case XTYP_ADVSTOP:
666 {
667 wxDDEConnection *connection = DDEFindConnection(hConv);
668
669 if (connection)
670 {
671 wxChar item_name[200];
672 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name),
673 CP_WINANSI);
674 return (DDERETURN)connection->OnStopAdvise(connection->m_topicName, wxString(item_name));
675 } else return (DDERETURN)0;
676 break;
677 }
678
679 case XTYP_ADVREQ:
680 {
681 wxDDEConnection *connection = DDEFindConnection(hConv);
682
683 if (connection && connection->m_sendingData)
684 {
685 HDDEDATA data = DdeCreateDataHandle(DDEIdInst,
686 (LPBYTE)connection->m_sendingData,
687 connection->m_dataSize, 0, hsz2, connection->m_dataType, 0);
688 connection->m_sendingData = NULL;
689 return (DDERETURN)data;
690 } else return (DDERETURN)NULL;
691 break;
692 }
693
694 case XTYP_ADVDATA:
695 {
696 wxDDEConnection *connection = DDEFindConnection(hConv);
697
698 if (connection)
699 {
700 wxChar item_name[200];
701 DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name),
702 CP_WINANSI);
703
704 DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0);
705 DdeFreeDataHandle(hData);
706 if (connection->OnAdvise(connection->m_topicName, wxString(item_name), connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt))
707 return (DDERETURN)DDE_FACK;
708 else
709 return (DDERETURN)DDE_FNOTPROCESSED;
710 } else return (DDERETURN)DDE_FNOTPROCESSED;
711 break;
712 }
713 }
714 return 0;
715 }
716
717 // Atom table stuff
718 static HSZ DDEAddAtom(const wxString& string)
719 {
720 HSZ atom = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST string, CP_WINANSI);
721 wxAtomTable.Append(string, (wxObject *)atom);
722 return atom;
723 }
724
725 static HSZ DDEGetAtom(const wxString& string)
726 {
727 wxNode *node = wxAtomTable.Find(string);
728 if (node)
729 return (HSZ)node->Data();
730 else
731 {
732 DDEAddAtom(string);
733 return (HSZ)(wxAtomTable.Find(string)->Data());
734 }
735 }
736
737 void DDEPrintError(void)
738 {
739 wxChar *err = NULL;
740 switch (DdeGetLastError(DDEIdInst))
741 {
742 case DMLERR_ADVACKTIMEOUT:
743 err = _T("A request for a synchronous advise transaction has timed out.");
744 break;
745 case DMLERR_BUSY:
746 err = _T("The response to the transaction caused the DDE_FBUSY bit to be set.");
747 break;
748 case DMLERR_DATAACKTIMEOUT:
749 err = _T("A request for a synchronous data transaction has timed out.");
750 break;
751 case DMLERR_DLL_NOT_INITIALIZED:
752 err = _T("A DDEML function was called without first calling the DdeInitialize function,\n\ror an invalid instance identifier\n\rwas passed to a DDEML function.");
753 break;
754 case DMLERR_DLL_USAGE:
755 err = _T("An application initialized as APPCLASS_MONITOR has\n\rattempted to perform a DDE transaction,\n\ror an application initialized as APPCMD_CLIENTONLY has \n\rattempted to perform server transactions.");
756 break;
757 case DMLERR_EXECACKTIMEOUT:
758 err = _T("A request for a synchronous execute transaction has timed out.");
759 break;
760 case DMLERR_INVALIDPARAMETER:
761 err = _T("A parameter failed to be validated by the DDEML.");
762 break;
763 case DMLERR_LOW_MEMORY:
764 err = _T("A DDEML application has created a prolonged race condition.");
765 break;
766 case DMLERR_MEMORY_ERROR:
767 err = _T("A memory allocation failed.");
768 break;
769 case DMLERR_NO_CONV_ESTABLISHED:
770 err = _T("A client's attempt to establish a conversation has failed.");
771 break;
772 case DMLERR_NOTPROCESSED:
773 err = _T("A transaction failed.");
774 break;
775 case DMLERR_POKEACKTIMEOUT:
776 err = _T("A request for a synchronous poke transaction has timed out.");
777 break;
778 case DMLERR_POSTMSG_FAILED:
779 err = _T("An internal call to the PostMessage function has failed. ");
780 break;
781 case DMLERR_REENTRANCY:
782 err = _T("Reentrancy problem.");
783 break;
784 case DMLERR_SERVER_DIED:
785 err = _T("A server-side transaction was attempted on a conversation\n\rthat was terminated by the client, or the server\n\rterminated before completing a transaction.");
786 break;
787 case DMLERR_SYS_ERROR:
788 err = _T("An internal error has occurred in the DDEML.");
789 break;
790 case DMLERR_UNADVACKTIMEOUT:
791 err = _T("A request to end an advise transaction has timed out.");
792 break;
793 case DMLERR_UNFOUND_QUEUE_ID:
794 err = _T("An invalid transaction identifier was passed to a DDEML function.\n\rOnce the application has returned from an XTYP_XACT_COMPLETE callback,\n\rthe transaction identifier for that callback is no longer valid.");
795 break;
796 default:
797 err = _T("Unrecognised error type.");
798 break;
799 }
800 MessageBox((HWND) NULL, (LPCTSTR)err, _T("DDE Error"), MB_OK | MB_ICONINFORMATION);
801 }
802
803 #endif
804 // wxUSE_IPC