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