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