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