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