adding intl.h and wxString -> char* conversion in DDEAtomFromString
[wxWidgets.git] / src / msw / dde.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/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 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dde.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_IPC
32
33 #ifndef WX_PRECOMP
34 #include "wx/utils.h"
35 #include "wx/app.h"
36 #endif
37
38 #include "wx/module.h"
39 #include "wx/dde.h"
40 #include "wx/intl.h"
41
42
43 #include "wx/msw/private.h"
44
45 #include <string.h>
46 #include <windows.h>
47 #include <ddeml.h>
48
49 #if defined(__TWIN32__) || defined(__GNUWIN32_OLD__)
50 #include "wx/msw/gnuwin32/extra.h"
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // macros and constants
55 // ----------------------------------------------------------------------------
56
57 #ifdef __WIN32__
58 #define _EXPORT
59 #else
60 #define _EXPORT _export
61 #endif
62
63 #if wxUSE_UNICODE
64 #define DDE_CP CP_WINUNICODE
65 #else
66 #define DDE_CP CP_WINANSI
67 #endif
68
69 #define GetHConv() ((HCONV)m_hConv)
70
71 // default timeout for DDE operations (5sec)
72 #define DDE_TIMEOUT 5000
73
74 // ----------------------------------------------------------------------------
75 // private functions
76 // ----------------------------------------------------------------------------
77
78 static wxDDEConnection *DDEFindConnection(HCONV hConv);
79 static void DDEDeleteConnection(HCONV hConv);
80 static wxDDEServer *DDEFindServer(const wxString& s);
81
82 extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback(WORD wType,
83 WORD wFmt,
84 HCONV hConv,
85 HSZ hsz1,
86 HSZ hsz2,
87 HDDEDATA hData,
88 DWORD lData1,
89 DWORD lData2);
90
91 // Add topic name to atom table before using in conversations
92 static HSZ DDEAddAtom(const wxString& string);
93 static HSZ DDEGetAtom(const wxString& string);
94
95 // string handles
96 static HSZ DDEAtomFromString(const wxString& s);
97 static wxString DDEStringFromAtom(HSZ hsz);
98
99 // error handling
100 static wxString DDEGetErrorMsg(UINT error);
101 static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR);
102
103 // ----------------------------------------------------------------------------
104 // global variables
105 // ----------------------------------------------------------------------------
106
107 static DWORD DDEIdInst = 0L;
108 static wxDDEConnection *DDECurrentlyConnecting = NULL;
109
110 static wxList wxAtomTable(wxKEY_STRING);
111 static wxList wxDDEClientObjects;
112 static wxList wxDDEServerObjects;
113
114 char *DDEDefaultIPCBuffer = NULL;
115 int DDEDefaultIPCBufferSize = 0;
116 static bool DDEInitialized = FALSE;
117
118 // ----------------------------------------------------------------------------
119 // private classes
120 // ----------------------------------------------------------------------------
121
122 // A module to allow DDE cleanup without calling these functions
123 // from app.cpp or from the user's application.
124
125 class wxDDEModule : public wxModule
126 {
127 public:
128 wxDDEModule() {}
129 bool OnInit() { return TRUE; }
130 void OnExit() { wxDDECleanUp(); }
131
132 private:
133 DECLARE_DYNAMIC_CLASS(wxDDEModule)
134 };
135
136 // ----------------------------------------------------------------------------
137 // wxWin macros
138 // ----------------------------------------------------------------------------
139
140 IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
141 IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
142 IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase)
143 IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
144
145 // ============================================================================
146 // implementation
147 // ============================================================================
148
149 // ----------------------------------------------------------------------------
150 // initialization and cleanup
151 // ----------------------------------------------------------------------------
152
153 extern void wxDDEInitialize()
154 {
155 if ( !DDEInitialized )
156 {
157 // Should insert filter flags
158 PFNCALLBACK callback = (PFNCALLBACK)
159 MakeProcInstance((FARPROC)_DDECallback, wxGetInstance());
160 UINT rc = DdeInitialize(&DDEIdInst, callback, APPCLASS_STANDARD, 0L);
161 if ( rc != DMLERR_NO_ERROR )
162 {
163 DDELogError(_T("Failed to initialize DDE"), rc);
164 }
165 else
166 {
167 DDEInitialized = TRUE;
168 }
169 }
170 }
171
172 void wxDDECleanUp()
173 {
174 if ( DDEIdInst != 0 )
175 {
176 DdeUninitialize(DDEIdInst);
177 DDEIdInst = 0;
178 }
179
180 delete [] DDEDefaultIPCBuffer;
181 }
182
183 // ----------------------------------------------------------------------------
184 // functions working with the global connection list(s)
185 // ----------------------------------------------------------------------------
186
187 // Global find connection
188 static wxDDEConnection *DDEFindConnection(HCONV hConv)
189 {
190 wxNode *node = wxDDEServerObjects.First();
191 wxDDEConnection *found = NULL;
192 while (node && !found)
193 {
194 wxDDEServer *object = (wxDDEServer *)node->Data();
195 found = object->FindConnection((WXHCONV) hConv);
196 node = node->Next();
197 }
198 if (found)
199 return found;
200
201 node = wxDDEClientObjects.First();
202 while (node && !found)
203 {
204 wxDDEClient *object = (wxDDEClient *)node->Data();
205 found = object->FindConnection((WXHCONV) hConv);
206 node = node->Next();
207 }
208 return found;
209 }
210
211 // Global delete connection
212 static void DDEDeleteConnection(HCONV hConv)
213 {
214 wxNode *node = wxDDEServerObjects.First();
215 bool found = FALSE;
216 while (node && !found)
217 {
218 wxDDEServer *object = (wxDDEServer *)node->Data();
219 found = object->DeleteConnection((WXHCONV) hConv);
220 node = node->Next();
221 }
222 if (found)
223 return;
224
225 node = wxDDEClientObjects.First();
226 while (node && !found)
227 {
228 wxDDEClient *object = (wxDDEClient *)node->Data();
229 found = object->DeleteConnection((WXHCONV) hConv);
230 node = node->Next();
231 }
232 }
233
234 // Find a server from a service name
235 static wxDDEServer *DDEFindServer(const wxString& s)
236 {
237 wxNode *node = wxDDEServerObjects.First();
238 wxDDEServer *found = NULL;
239 while (node && !found)
240 {
241 wxDDEServer *object = (wxDDEServer *)node->Data();
242
243 if (object->GetServiceName() == s)
244 found = object;
245 else node = node->Next();
246 }
247 return found;
248 }
249
250 // ----------------------------------------------------------------------------
251 // wxDDEServer
252 // ----------------------------------------------------------------------------
253
254 wxDDEServer::wxDDEServer()
255 {
256 wxDDEInitialize();
257
258 wxDDEServerObjects.Append(this);
259 }
260
261 bool wxDDEServer::Create(const wxString& server)
262 {
263 m_serviceName = server;
264
265 if ( !DdeNameService(DDEIdInst, DDEAtomFromString(server), (HSZ)NULL, DNS_REGISTER) )
266 {
267 DDELogError(wxString::Format(_("Failed to register DDE server '%s'"),
268 server.c_str()));
269
270 return FALSE;
271 }
272
273 return TRUE;
274 }
275
276 wxDDEServer::~wxDDEServer()
277 {
278 if ( !!m_serviceName )
279 {
280 if ( !DdeNameService(DDEIdInst, DDEAtomFromString(m_serviceName),
281 (HSZ)NULL, DNS_UNREGISTER) )
282 {
283 DDELogError(wxString::Format(_("Failed to unregister DDE server '%s'"),
284 m_serviceName.c_str()));
285 }
286 }
287
288 wxDDEServerObjects.DeleteObject(this);
289
290 wxNode *node = m_connections.First();
291 while (node)
292 {
293 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
294 wxNode *next = node->Next();
295 connection->OnDisconnect(); // May delete the node implicitly
296 node = next;
297 }
298
299 // If any left after this, delete them
300 node = m_connections.First();
301 while (node)
302 {
303 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
304 wxNode *next = node->Next();
305 delete connection;
306 node = next;
307 }
308 }
309
310 wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */)
311 {
312 return new wxDDEConnection;
313 }
314
315 wxDDEConnection *wxDDEServer::FindConnection(WXHCONV conv)
316 {
317 wxNode *node = m_connections.First();
318 wxDDEConnection *found = NULL;
319 while (node && !found)
320 {
321 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
322 if (connection->m_hConv == conv)
323 found = connection;
324 else node = node->Next();
325 }
326 return found;
327 }
328
329 // Only delete the entry in the map, not the actual connection
330 bool wxDDEServer::DeleteConnection(WXHCONV conv)
331 {
332 wxNode *node = m_connections.First();
333 bool found = FALSE;
334 while (node && !found)
335 {
336 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
337 if (connection->m_hConv == conv)
338 {
339 found = TRUE;
340 delete node;
341 }
342 else node = node->Next();
343 }
344 return found;
345 }
346
347 // ----------------------------------------------------------------------------
348 // wxDDEClient
349 // ----------------------------------------------------------------------------
350
351 wxDDEClient::wxDDEClient()
352 {
353 wxDDEInitialize();
354
355 wxDDEClientObjects.Append(this);
356 }
357
358 wxDDEClient::~wxDDEClient()
359 {
360 wxDDEClientObjects.DeleteObject(this);
361 wxNode *node = m_connections.First();
362 while (node)
363 {
364 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
365 delete connection; // Deletes the node implicitly (see ~wxDDEConnection)
366 node = m_connections.First();
367 }
368 }
369
370 bool wxDDEClient::ValidHost(const wxString& /* host */)
371 {
372 return TRUE;
373 }
374
375 wxConnectionBase *wxDDEClient::MakeConnection(const wxString& WXUNUSED(host),
376 const wxString& server,
377 const wxString& topic)
378 {
379 HCONV hConv = DdeConnect(DDEIdInst, DDEAtomFromString(server), DDEAtomFromString(topic),
380 (PCONVCONTEXT)NULL);
381 if ( !hConv )
382 {
383 DDELogError(wxString::Format(_("Failed to create connection to "
384 "server '%s' on topic '%s'"),
385 server.c_str(), topic.c_str()));
386 }
387 else
388 {
389 wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection();
390 if (connection)
391 {
392 connection->m_hConv = (WXHCONV) hConv;
393 connection->m_topicName = topic;
394 connection->m_client = this;
395 m_connections.Append(connection);
396 return connection;
397 }
398 }
399
400 return (wxConnectionBase*) NULL;
401 }
402
403 wxConnectionBase *wxDDEClient::OnMakeConnection()
404 {
405 return new wxDDEConnection;
406 }
407
408 wxDDEConnection *wxDDEClient::FindConnection(WXHCONV conv)
409 {
410 wxNode *node = m_connections.First();
411 wxDDEConnection *found = NULL;
412 while (node && !found)
413 {
414 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
415 if (connection->m_hConv == conv)
416 found = connection;
417 else node = node->Next();
418 }
419 return found;
420 }
421
422 // Only delete the entry in the map, not the actual connection
423 bool wxDDEClient::DeleteConnection(WXHCONV conv)
424 {
425 wxNode *node = m_connections.First();
426 bool found = FALSE;
427 while (node && !found)
428 {
429 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
430 if (connection->m_hConv == conv)
431 {
432 found = TRUE;
433 delete node;
434 }
435 else node = node->Next();
436 }
437 return found;
438 }
439
440 // ----------------------------------------------------------------------------
441 // wxDDEConnection
442 // ----------------------------------------------------------------------------
443
444 wxDDEConnection::wxDDEConnection(char *buffer, int size)
445 {
446 if (buffer == NULL)
447 {
448 if (DDEDefaultIPCBuffer == NULL)
449 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
450 m_bufPtr = DDEDefaultIPCBuffer;
451 m_bufSize = DDEDefaultIPCBufferSize;
452 }
453 else
454 {
455 m_bufPtr = buffer;
456 m_bufSize = size;
457 }
458
459 m_client = NULL;
460 m_server = NULL;
461
462 m_hConv = 0;
463 m_sendingData = NULL;
464 }
465
466 wxDDEConnection::wxDDEConnection()
467 {
468 m_hConv = 0;
469 m_sendingData = NULL;
470 m_server = NULL;
471 m_client = NULL;
472 if (DDEDefaultIPCBuffer == NULL)
473 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
474
475 m_bufPtr = DDEDefaultIPCBuffer;
476 m_bufSize = DDEDefaultIPCBufferSize;
477 }
478
479 wxDDEConnection::~wxDDEConnection()
480 {
481 if (m_server)
482 m_server->GetConnections().DeleteObject(this);
483 else
484 m_client->GetConnections().DeleteObject(this);
485 }
486
487 // Calls that CLIENT can make
488 bool wxDDEConnection::Disconnect()
489 {
490 DDEDeleteConnection(GetHConv());
491
492 bool ok = DdeDisconnect(GetHConv()) != 0;
493 if ( !ok )
494 {
495 DDELogError(_T("Failed to disconnect from DDE server gracefully"));
496 }
497
498 return ok;
499 }
500
501 bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
502 {
503 DWORD result;
504 if (size < 0)
505 {
506 size = wxStrlen(data) + 1;
507 }
508
509 bool ok = DdeClientTransaction((LPBYTE)data, size,
510 GetHConv(),
511 NULL,
512 format,
513 XTYP_EXECUTE,
514 DDE_TIMEOUT,
515 &result) != 0;
516 if ( !ok )
517 {
518 DDELogError(_T("DDE execute request failed"));
519 }
520
521 return ok;
522 }
523
524 char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
525 {
526 DWORD result;
527 HSZ atom = DDEGetAtom(item);
528
529 HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
530 GetHConv(),
531 atom, format,
532 XTYP_REQUEST,
533 DDE_TIMEOUT,
534 &result);
535 if ( !returned_data )
536 {
537 DDELogError(_T("DDE data request failed"));
538
539 return NULL;
540 }
541
542 DWORD len = DdeGetData(returned_data, (LPBYTE)m_bufPtr, m_bufSize, 0);
543
544 DdeFreeDataHandle(returned_data);
545
546 if (size)
547 *size = (int)len;
548
549 return m_bufPtr;
550 }
551
552 bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
553 {
554 DWORD result;
555 if (size < 0)
556 {
557 size = wxStrlen(data) + 1;
558 }
559
560 HSZ item_atom = DDEGetAtom(item);
561 bool ok = DdeClientTransaction((LPBYTE)data, size,
562 GetHConv(),
563 item_atom, format,
564 XTYP_POKE,
565 DDE_TIMEOUT,
566 &result) != 0;
567 if ( !ok )
568 {
569 DDELogError(_("DDE poke request failed"));
570 }
571
572 return ok;
573 }
574
575 bool wxDDEConnection::StartAdvise(const wxString& item)
576 {
577 DWORD result;
578 HSZ atom = DDEGetAtom(item);
579
580 bool ok = DdeClientTransaction(NULL, 0,
581 GetHConv(),
582 atom, CF_TEXT,
583 XTYP_ADVSTART,
584 DDE_TIMEOUT,
585 &result) != 0;
586 if ( !ok )
587 {
588 DDELogError(_("Failed to establish an advise loop with DDE server"));
589 }
590
591 return ok;
592 }
593
594 bool wxDDEConnection::StopAdvise(const wxString& item)
595 {
596 DWORD result;
597 HSZ atom = DDEGetAtom(item);
598
599 bool ok = DdeClientTransaction(NULL, 0,
600 GetHConv(),
601 atom, CF_TEXT,
602 XTYP_ADVSTOP,
603 DDE_TIMEOUT,
604 &result) != 0;
605 if ( !ok )
606 {
607 DDELogError(_("Failed to terminate the advise loop with DDE server"));
608 }
609
610 return ok;
611 }
612
613 // Calls that SERVER can make
614 bool wxDDEConnection::Advise(const wxString& item,
615 wxChar *data,
616 int size,
617 wxIPCFormat format)
618 {
619 if (size < 0)
620 {
621 size = wxStrlen(data) + 1;
622 }
623
624 HSZ item_atom = DDEGetAtom(item);
625 HSZ topic_atom = DDEGetAtom(m_topicName);
626 m_sendingData = data;
627 m_dataSize = size;
628 m_dataType = format;
629
630 bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
631 if ( !ok )
632 {
633 DDELogError(_("Failed to send DDE advise notification"));
634 }
635
636 return ok;
637 }
638
639 bool wxDDEConnection::OnDisconnect()
640 {
641 delete this;
642 return TRUE;
643 }
644
645 // ----------------------------------------------------------------------------
646 // _DDECallback
647 // ----------------------------------------------------------------------------
648
649 #define DDERETURN HDDEDATA
650
651 HDDEDATA EXPENTRY _EXPORT
652 _DDECallback(WORD wType,
653 WORD wFmt,
654 HCONV hConv,
655 HSZ hsz1,
656 HSZ hsz2,
657 HDDEDATA hData,
658 DWORD WXUNUSED(lData1),
659 DWORD WXUNUSED(lData2))
660 {
661 switch (wType)
662 {
663 case XTYP_CONNECT:
664 {
665 wxString topic = DDEStringFromAtom(hsz1),
666 srv = DDEStringFromAtom(hsz2);
667 wxDDEServer *server = DDEFindServer(srv);
668 if (server)
669 {
670 wxDDEConnection *connection =
671 (wxDDEConnection*) server->OnAcceptConnection(topic);
672 if (connection)
673 {
674 connection->m_server = server;
675 server->GetConnections().Append(connection);
676 connection->m_hConv = 0;
677 connection->m_topicName = topic;
678 DDECurrentlyConnecting = connection;
679 return (DDERETURN)(DWORD)TRUE;
680 }
681 }
682 break;
683 }
684
685 case XTYP_CONNECT_CONFIRM:
686 {
687 if (DDECurrentlyConnecting)
688 {
689 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
690 DDECurrentlyConnecting = NULL;
691 return (DDERETURN)(DWORD)TRUE;
692 }
693 break;
694 }
695
696 case XTYP_DISCONNECT:
697 {
698 wxDDEConnection *connection = DDEFindConnection(hConv);
699 if (connection && connection->OnDisconnect())
700 {
701 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
702 return (DDERETURN)(DWORD)TRUE;
703 }
704 break;
705 }
706
707 case XTYP_EXECUTE:
708 {
709 wxDDEConnection *connection = DDEFindConnection(hConv);
710
711 if (connection)
712 {
713 DWORD len = DdeGetData(hData,
714 (LPBYTE)connection->m_bufPtr,
715 connection->m_bufSize,
716 0);
717 DdeFreeDataHandle(hData);
718 if ( connection->OnExecute(connection->m_topicName,
719 connection->m_bufPtr,
720 (int)len,
721 (wxIPCFormat) wFmt) )
722 {
723 return (DDERETURN)(DWORD)DDE_FACK;
724 }
725 }
726
727 return (DDERETURN)DDE_FNOTPROCESSED;
728 }
729
730 case XTYP_REQUEST:
731 {
732 wxDDEConnection *connection = DDEFindConnection(hConv);
733
734 if (connection)
735 {
736 wxString item_name = DDEStringFromAtom(hsz2);
737
738 int user_size = -1;
739 char *data = connection->OnRequest(connection->m_topicName,
740 item_name,
741 &user_size,
742 (wxIPCFormat) wFmt);
743 if (data)
744 {
745 if (user_size < 0)
746 user_size = wxStrlen(data) + 1;
747
748 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
749 (LPBYTE)data,
750 user_size,
751 0,
752 hsz2,
753 wFmt,
754 0);
755 return (DDERETURN)handle;
756 }
757 }
758 break;
759 }
760
761 case XTYP_POKE:
762 {
763 wxDDEConnection *connection = DDEFindConnection(hConv);
764
765 if (connection)
766 {
767 wxString item_name = DDEStringFromAtom(hsz2);
768
769 DWORD len = DdeGetData(hData,
770 (LPBYTE)connection->m_bufPtr,
771 connection->m_bufSize,
772 0);
773 DdeFreeDataHandle(hData);
774
775 connection->OnPoke(connection->m_topicName,
776 item_name,
777 connection->m_bufPtr,
778 (int)len,
779 (wxIPCFormat) wFmt);
780
781 return (DDERETURN)DDE_FACK;
782 }
783 else
784 {
785 return (DDERETURN)DDE_FNOTPROCESSED;
786 }
787 }
788
789 case XTYP_ADVSTART:
790 {
791 wxDDEConnection *connection = DDEFindConnection(hConv);
792
793 if (connection)
794 {
795 wxString item_name = DDEStringFromAtom(hsz2);
796
797 return (DDERETURN)connection->
798 OnStartAdvise(connection->m_topicName, item_name);
799 }
800
801 break;
802 }
803
804 case XTYP_ADVSTOP:
805 {
806 wxDDEConnection *connection = DDEFindConnection(hConv);
807
808 if (connection)
809 {
810 wxString item_name = DDEStringFromAtom(hsz2);
811
812 return (DDERETURN)connection->
813 OnStopAdvise(connection->m_topicName, item_name);
814 }
815
816 break;
817 }
818
819 case XTYP_ADVREQ:
820 {
821 wxDDEConnection *connection = DDEFindConnection(hConv);
822
823 if (connection && connection->m_sendingData)
824 {
825 HDDEDATA data = DdeCreateDataHandle
826 (
827 DDEIdInst,
828 (LPBYTE)connection->m_sendingData,
829 connection->m_dataSize,
830 0,
831 hsz2,
832 connection->m_dataType,
833 0
834 );
835
836 connection->m_sendingData = NULL;
837
838 return (DDERETURN)data;
839 }
840
841 break;
842 }
843
844 case XTYP_ADVDATA:
845 {
846 wxDDEConnection *connection = DDEFindConnection(hConv);
847
848 if (connection)
849 {
850 wxString item_name = DDEStringFromAtom(hsz2);
851
852 DWORD len = DdeGetData(hData,
853 (LPBYTE)connection->m_bufPtr,
854 connection->m_bufSize,
855 0);
856 DdeFreeDataHandle(hData);
857 if ( connection->OnAdvise(connection->m_topicName,
858 item_name,
859 connection->m_bufPtr,
860 (int)len,
861 (wxIPCFormat) wFmt) )
862 {
863 return (DDERETURN)(DWORD)DDE_FACK;
864 }
865 }
866
867 return (DDERETURN)DDE_FNOTPROCESSED;
868 }
869 }
870
871 return (DDERETURN)0;
872 }
873
874 // ----------------------------------------------------------------------------
875 // DDE strings and atoms
876 // ----------------------------------------------------------------------------
877
878 // Atom table stuff
879 static HSZ DDEAddAtom(const wxString& string)
880 {
881 HSZ atom = DDEAtomFromString(string);
882 wxAtomTable.Append(string, (wxObject *)atom);
883 return atom;
884 }
885
886 static HSZ DDEGetAtom(const wxString& string)
887 {
888 wxNode *node = wxAtomTable.Find(string);
889 if (node)
890 return (HSZ)node->Data();
891 else
892 {
893 DDEAddAtom(string);
894 return (HSZ)(wxAtomTable.Find(string)->Data());
895 }
896 }
897
898 // atom <-> strings
899 static HSZ DDEAtomFromString(const wxString& s)
900 {
901 wxASSERT_MSG( DDEIdInst, _T("DDE not initialized") );
902
903 HSZ hsz = DdeCreateStringHandle(DDEIdInst, (char*) s.c_str(), DDE_CP);
904 if ( !hsz )
905 {
906 DDELogError(_("Failed to create DDE string"));
907 }
908
909 return hsz;
910 }
911
912 static wxString DDEStringFromAtom(HSZ hsz)
913 {
914 // all DDE strings are normally limited to 255 bytes
915 static const size_t len = 256;
916
917 wxString s;
918 (void)DdeQueryString(DDEIdInst, hsz, s.GetWriteBuf(len), len, DDE_CP);
919 s.UngetWriteBuf();
920
921 return s;
922 }
923
924 // ----------------------------------------------------------------------------
925 // error handling
926 // ----------------------------------------------------------------------------
927
928 static void DDELogError(const wxString& s, UINT error)
929 {
930 if ( !error )
931 {
932 error = DdeGetLastError(DDEIdInst);
933 }
934
935 wxLogError(s + _T(": ") + DDEGetErrorMsg(error));
936 }
937
938 static wxString DDEGetErrorMsg(UINT error)
939 {
940 wxString err;
941 switch ( error )
942 {
943 case DMLERR_NO_ERROR:
944 err = _("no DDE error.");
945 break;
946
947 case DMLERR_ADVACKTIMEOUT:
948 err = _("a request for a synchronous advise transaction has timed out.");
949 break;
950 case DMLERR_BUSY:
951 err = _("the response to the transaction caused the DDE_FBUSY bit to be set.");
952 break;
953 case DMLERR_DATAACKTIMEOUT:
954 err = _("a request for a synchronous data transaction has timed out.");
955 break;
956 case DMLERR_DLL_NOT_INITIALIZED:
957 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.");
958 break;
959 case DMLERR_DLL_USAGE:
960 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.");
961 break;
962 case DMLERR_EXECACKTIMEOUT:
963 err = _("a request for a synchronous execute transaction has timed out.");
964 break;
965 case DMLERR_INVALIDPARAMETER:
966 err = _("a parameter failed to be validated by the DDEML.");
967 break;
968 case DMLERR_LOW_MEMORY:
969 err = _("a DDEML application has created a prolonged race condition.");
970 break;
971 case DMLERR_MEMORY_ERROR:
972 err = _("a memory allocation failed.");
973 break;
974 case DMLERR_NO_CONV_ESTABLISHED:
975 err = _("a client's attempt to establish a conversation has failed.");
976 break;
977 case DMLERR_NOTPROCESSED:
978 err = _("a transaction failed.");
979 break;
980 case DMLERR_POKEACKTIMEOUT:
981 err = _("a request for a synchronous poke transaction has timed out.");
982 break;
983 case DMLERR_POSTMSG_FAILED:
984 err = _("an internal call to the PostMessage function has failed. ");
985 break;
986 case DMLERR_REENTRANCY:
987 err = _("reentrancy problem.");
988 break;
989 case DMLERR_SERVER_DIED:
990 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.");
991 break;
992 case DMLERR_SYS_ERROR:
993 err = _("an internal error has occurred in the DDEML.");
994 break;
995 case DMLERR_UNADVACKTIMEOUT:
996 err = _("a request to end an advise transaction has timed out.");
997 break;
998 case DMLERR_UNFOUND_QUEUE_ID:
999 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.");
1000 break;
1001 default:
1002 err.Printf(_("Unknown DDE error %08x"), error);
1003 }
1004
1005 return err;
1006 }
1007
1008 #endif
1009 // wxUSE_IPC