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