]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dde.cpp
Have wxDCImpl::GetHandle return NULL by default instead of being pure virtual.
[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 // 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
71 static wxDDEConnection *DDEFindConnection(HCONV hConv);
72 static void DDEDeleteConnection(HCONV hConv);
73 static wxDDEServer *DDEFindServer(const wxString& s);
74
75 extern "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
85 static HSZ DDEAddAtom(const wxString& string);
86 static HSZ DDEGetAtom(const wxString& string);
87
88 // string handles
89 static HSZ DDEAtomFromString(const wxString& s);
90 static wxString DDEStringFromAtom(HSZ hsz);
91 static void DDEFreeString(HSZ hsz);
92
93 // error handling
94 static wxString DDEGetErrorMsg(UINT error);
95 static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR);
96
97 // ----------------------------------------------------------------------------
98 // global variables
99 // ----------------------------------------------------------------------------
100
101 WX_DECLARE_STRING_HASH_MAP( HSZ, wxAtomMap );
102
103 static DWORD DDEIdInst = 0L;
104 static wxDDEConnection *DDECurrentlyConnecting = NULL;
105 static wxAtomMap wxAtomTable;
106
107 #include "wx/listimpl.cpp"
108
109 WX_DEFINE_LIST(wxDDEClientList)
110 WX_DEFINE_LIST(wxDDEServerList)
111 WX_DEFINE_LIST(wxDDEConnectionList)
112
113 static wxDDEClientList wxDDEClientObjects;
114 static wxDDEServerList wxDDEServerObjects;
115
116 static 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
125 class wxDDEModule : public wxModule
126 {
127 public:
128 wxDDEModule() {}
129 bool OnInit() { return true; }
130 void OnExit() { wxDDECleanUp(); }
131
132 private:
133 DECLARE_DYNAMIC_CLASS(wxDDEModule)
134 };
135
136 // ----------------------------------------------------------------------------
137 // wxWin macros
138 // ----------------------------------------------------------------------------
139
140 IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
141 IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
142 IMPLEMENT_DYNAMIC_CLASS(wxDDEConnection, wxConnectionBase)
143 IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
144
145 // ============================================================================
146 // implementation
147 // ============================================================================
148
149 // ----------------------------------------------------------------------------
150 // initialization and cleanup
151 // ----------------------------------------------------------------------------
152
153 extern 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
172 void 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
193 static 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
220 static 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
245 static 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
270 wxDDEServer::wxDDEServer()
271 {
272 wxDDEInitialize();
273
274 wxDDEServerObjects.Append(this);
275 }
276
277 bool 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
303 wxDDEServer::~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
345 wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */)
346 {
347 return new wxDDEConnection;
348 }
349
350 wxDDEConnection *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
365 bool 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
388 wxDDEClient::wxDDEClient()
389 {
390 wxDDEInitialize();
391
392 wxDDEClientObjects.Append(this);
393 }
394
395 wxDDEClient::~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
407 bool wxDDEClient::ValidHost(const wxString& /* host */)
408 {
409 return true;
410 }
411
412 wxConnectionBase *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
462 wxConnectionBase *wxDDEClient::OnMakeConnection()
463 {
464 return new wxDDEConnection;
465 }
466
467 wxDDEConnection *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
482 bool 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
502 wxDDEConnection::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
512 wxDDEConnection::wxDDEConnection()
513 : wxConnectionBase()
514 {
515 m_hConv = 0;
516 m_sendingData = NULL;
517 m_server = NULL;
518 m_client = NULL;
519 }
520
521 wxDDEConnection::~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
531 bool 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
549 bool
550 wxDDEConnection::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/sizeof(char);
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*sizeof(char));
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
661 const 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
695 bool 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
715 bool 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
734 bool 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
754 bool 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
781 HDDEDATA 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
1046 static HSZ DDEAddAtom(const wxString& str)
1047 {
1048 HSZ atom = DDEAtomFromString(str);
1049 wxAtomTable[str] = atom;
1050 return atom;
1051 }
1052
1053 static 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
1064 The returned handle has to be freed by the caller (using
1065 (static) DDEFreeString).
1066 */
1067 static 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
1080 static 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
1091 static 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
1104 static 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
1114 static 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