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