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