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