]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dde.cpp
value of wxTE_PASSWORD changed to be different from wxCANCEL
[wxWidgets.git] / src / msw / dde.cpp
... / ...
CommitLineData
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
78static wxDDEConnection *DDEFindConnection(HCONV hConv);
79static void DDEDeleteConnection(HCONV hConv);
80static wxDDEServer *DDEFindServer(const wxString& s);
81
82extern "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
92static HSZ DDEAddAtom(const wxString& string);
93static HSZ DDEGetAtom(const wxString& string);
94
95// string handles
96static HSZ DDEAtomFromString(const wxString& s);
97static wxString DDEStringFromAtom(HSZ hsz);
98
99// error handling
100static wxString DDEGetErrorMsg(UINT error);
101static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR);
102
103// ----------------------------------------------------------------------------
104// global variables
105// ----------------------------------------------------------------------------
106
107static DWORD DDEIdInst = 0L;
108static wxDDEConnection *DDECurrentlyConnecting = NULL;
109
110static wxList wxAtomTable(wxKEY_STRING);
111static wxList wxDDEClientObjects;
112static wxList wxDDEServerObjects;
113
114char *DDEDefaultIPCBuffer = NULL;
115int DDEDefaultIPCBufferSize = 0;
116static 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
125class wxDDEModule : public wxModule
126{
127public:
128 wxDDEModule() {}
129 bool OnInit() { return TRUE; }
130 void OnExit() { wxDDECleanUp(); }
131
132private:
133 DECLARE_DYNAMIC_CLASS(wxDDEModule)
134};
135
136// ----------------------------------------------------------------------------
137// wxWin macros
138// ----------------------------------------------------------------------------
139
140IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
141IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
142IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase)
143IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
144
145// ============================================================================
146// implementation
147// ============================================================================
148
149// ----------------------------------------------------------------------------
150// initialization and cleanup
151// ----------------------------------------------------------------------------
152
153extern 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
172void 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
188static 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
212static 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
235static 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
254wxDDEServer::wxDDEServer()
255{
256 wxDDEInitialize();
257
258 wxDDEServerObjects.Append(this);
259}
260
261bool 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
276wxDDEServer::~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
310wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */)
311{
312 return new wxDDEConnection;
313}
314
315wxDDEConnection *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
330bool 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
351wxDDEClient::wxDDEClient()
352{
353 wxDDEInitialize();
354
355 wxDDEClientObjects.Append(this);
356}
357
358wxDDEClient::~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
370bool wxDDEClient::ValidHost(const wxString& /* host */)
371{
372 return TRUE;
373}
374
375wxConnectionBase *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
403wxConnectionBase *wxDDEClient::OnMakeConnection()
404{
405 return new wxDDEConnection;
406}
407
408wxDDEConnection *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
423bool 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
444wxDDEConnection::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
466wxDDEConnection::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
479wxDDEConnection::~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
488bool 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
501bool 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
524char *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
552bool 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
575bool 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
594bool 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
614bool 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
639bool wxDDEConnection::OnDisconnect()
640{
641 delete this;
642 return TRUE;
643}
644
645// ----------------------------------------------------------------------------
646// _DDECallback
647// ----------------------------------------------------------------------------
648
649#define DDERETURN HDDEDATA
650
651HDDEDATA 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
879static HSZ DDEAddAtom(const wxString& string)
880{
881 HSZ atom = DDEAtomFromString(string);
882 wxAtomTable.Append(string, (wxObject *)atom);
883 return atom;
884}
885
886static 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
899static 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
912static 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
928static 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
938static 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