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