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