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