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