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