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