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