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