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