]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dde.cpp
give frame a reasonable default size if none specified
[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 if ( !ok )
534 {
535 DDELogError(_T("DDE execute request failed"));
536 }
537
538 return ok;
539 }
540
541 char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
542 {
543 DWORD result;
544 HSZ atom = DDEGetAtom(item);
545
546 HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
547 GetHConv(),
548 atom, format,
549 XTYP_REQUEST,
550 DDE_TIMEOUT,
551 &result);
552 if ( !returned_data )
553 {
554 DDELogError(_T("DDE data request failed"));
555
556 return NULL;
557 }
558
559 DWORD len = DdeGetData(returned_data, (LPBYTE)m_bufPtr, m_bufSize, 0);
560
561 DdeFreeDataHandle(returned_data);
562
563 if (size)
564 *size = (int)len;
565
566 return m_bufPtr;
567 }
568
569 bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
570 {
571 DWORD result;
572 if (size < 0)
573 {
574 size = wxStrlen(data) + 1;
575 }
576
577 HSZ item_atom = DDEGetAtom(item);
578 bool ok = DdeClientTransaction((LPBYTE)data, size,
579 GetHConv(),
580 item_atom, format,
581 XTYP_POKE,
582 DDE_TIMEOUT,
583 &result) != 0;
584 if ( !ok )
585 {
586 DDELogError(_("DDE poke request failed"));
587 }
588
589 return ok;
590 }
591
592 bool wxDDEConnection::StartAdvise(const wxString& item)
593 {
594 DWORD result;
595 HSZ atom = DDEGetAtom(item);
596
597 bool ok = DdeClientTransaction(NULL, 0,
598 GetHConv(),
599 atom, CF_TEXT,
600 XTYP_ADVSTART,
601 DDE_TIMEOUT,
602 &result) != 0;
603 if ( !ok )
604 {
605 DDELogError(_("Failed to establish an advise loop with DDE server"));
606 }
607
608 return ok;
609 }
610
611 bool wxDDEConnection::StopAdvise(const wxString& item)
612 {
613 DWORD result;
614 HSZ atom = DDEGetAtom(item);
615
616 bool ok = DdeClientTransaction(NULL, 0,
617 GetHConv(),
618 atom, CF_TEXT,
619 XTYP_ADVSTOP,
620 DDE_TIMEOUT,
621 &result) != 0;
622 if ( !ok )
623 {
624 DDELogError(_("Failed to terminate the advise loop with DDE server"));
625 }
626
627 return ok;
628 }
629
630 // Calls that SERVER can make
631 bool wxDDEConnection::Advise(const wxString& item,
632 wxChar *data,
633 int size,
634 wxIPCFormat format)
635 {
636 if (size < 0)
637 {
638 size = wxStrlen(data) + 1;
639 }
640
641 HSZ item_atom = DDEGetAtom(item);
642 HSZ topic_atom = DDEGetAtom(m_topicName);
643 m_sendingData = data;
644 m_dataSize = size;
645 m_dataType = format;
646
647 bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
648 if ( !ok )
649 {
650 DDELogError(_("Failed to send DDE advise notification"));
651 }
652
653 return ok;
654 }
655
656 bool wxDDEConnection::OnDisconnect()
657 {
658 delete this;
659 return TRUE;
660 }
661
662 // ----------------------------------------------------------------------------
663 // _DDECallback
664 // ----------------------------------------------------------------------------
665
666 #define DDERETURN HDDEDATA
667
668 HDDEDATA EXPENTRY _EXPORT
669 _DDECallback(WORD wType,
670 WORD wFmt,
671 HCONV hConv,
672 HSZ hsz1,
673 HSZ hsz2,
674 HDDEDATA hData,
675 DWORD WXUNUSED(lData1),
676 DWORD WXUNUSED(lData2))
677 {
678 switch (wType)
679 {
680 case XTYP_CONNECT:
681 {
682 wxString topic = DDEStringFromAtom(hsz1),
683 srv = DDEStringFromAtom(hsz2);
684 wxDDEServer *server = DDEFindServer(srv);
685 if (server)
686 {
687 wxDDEConnection *connection =
688 (wxDDEConnection*) server->OnAcceptConnection(topic);
689 if (connection)
690 {
691 connection->m_server = server;
692 server->GetConnections().Append(connection);
693 connection->m_hConv = 0;
694 connection->m_topicName = topic;
695 DDECurrentlyConnecting = connection;
696 return (DDERETURN)(DWORD)TRUE;
697 }
698 }
699 break;
700 }
701
702 case XTYP_CONNECT_CONFIRM:
703 {
704 if (DDECurrentlyConnecting)
705 {
706 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
707 DDECurrentlyConnecting = NULL;
708 return (DDERETURN)(DWORD)TRUE;
709 }
710 break;
711 }
712
713 case XTYP_DISCONNECT:
714 {
715 wxDDEConnection *connection = DDEFindConnection(hConv);
716 if (connection && connection->OnDisconnect())
717 {
718 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
719 return (DDERETURN)(DWORD)TRUE;
720 }
721 break;
722 }
723
724 case XTYP_EXECUTE:
725 {
726 wxDDEConnection *connection = DDEFindConnection(hConv);
727
728 if (connection)
729 {
730 DWORD len = DdeGetData(hData,
731 (LPBYTE)connection->m_bufPtr,
732 connection->m_bufSize,
733 0);
734 DdeFreeDataHandle(hData);
735 if ( connection->OnExecute(connection->m_topicName,
736 connection->m_bufPtr,
737 (int)len,
738 (wxIPCFormat) wFmt) )
739 {
740 return (DDERETURN)(DWORD)DDE_FACK;
741 }
742 }
743
744 return (DDERETURN)DDE_FNOTPROCESSED;
745 }
746
747 case XTYP_REQUEST:
748 {
749 wxDDEConnection *connection = DDEFindConnection(hConv);
750
751 if (connection)
752 {
753 wxString item_name = DDEStringFromAtom(hsz2);
754
755 int user_size = -1;
756 char *data = connection->OnRequest(connection->m_topicName,
757 item_name,
758 &user_size,
759 (wxIPCFormat) wFmt);
760 if (data)
761 {
762 if (user_size < 0)
763 user_size = wxStrlen((wxChar*)data) + 1;
764
765 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
766 (LPBYTE)data,
767 user_size,
768 0,
769 hsz2,
770 wFmt,
771 0);
772 return (DDERETURN)handle;
773 }
774 }
775 break;
776 }
777
778 case XTYP_POKE:
779 {
780 wxDDEConnection *connection = DDEFindConnection(hConv);
781
782 if (connection)
783 {
784 wxString item_name = DDEStringFromAtom(hsz2);
785
786 DWORD len = DdeGetData(hData,
787 (LPBYTE)connection->m_bufPtr,
788 connection->m_bufSize,
789 0);
790 DdeFreeDataHandle(hData);
791
792 connection->OnPoke(connection->m_topicName,
793 item_name,
794 (wxChar*)connection->m_bufPtr,
795 (int)len,
796 (wxIPCFormat) wFmt);
797
798 return (DDERETURN)DDE_FACK;
799 }
800 else
801 {
802 return (DDERETURN)DDE_FNOTPROCESSED;
803 }
804 }
805
806 case XTYP_ADVSTART:
807 {
808 wxDDEConnection *connection = DDEFindConnection(hConv);
809
810 if (connection)
811 {
812 wxString item_name = DDEStringFromAtom(hsz2);
813
814 return (DDERETURN)connection->
815 OnStartAdvise(connection->m_topicName, item_name);
816 }
817
818 break;
819 }
820
821 case XTYP_ADVSTOP:
822 {
823 wxDDEConnection *connection = DDEFindConnection(hConv);
824
825 if (connection)
826 {
827 wxString item_name = DDEStringFromAtom(hsz2);
828
829 return (DDERETURN)connection->
830 OnStopAdvise(connection->m_topicName, item_name);
831 }
832
833 break;
834 }
835
836 case XTYP_ADVREQ:
837 {
838 wxDDEConnection *connection = DDEFindConnection(hConv);
839
840 if (connection && connection->m_sendingData)
841 {
842 HDDEDATA data = DdeCreateDataHandle
843 (
844 DDEIdInst,
845 (LPBYTE)connection->m_sendingData,
846 connection->m_dataSize,
847 0,
848 hsz2,
849 connection->m_dataType,
850 0
851 );
852
853 connection->m_sendingData = NULL;
854
855 return (DDERETURN)data;
856 }
857
858 break;
859 }
860
861 case XTYP_ADVDATA:
862 {
863 wxDDEConnection *connection = DDEFindConnection(hConv);
864
865 if (connection)
866 {
867 wxString item_name = DDEStringFromAtom(hsz2);
868
869 DWORD len = DdeGetData(hData,
870 (LPBYTE)connection->m_bufPtr,
871 connection->m_bufSize,
872 0);
873 DdeFreeDataHandle(hData);
874 if ( connection->OnAdvise(connection->m_topicName,
875 item_name,
876 connection->m_bufPtr,
877 (int)len,
878 (wxIPCFormat) wFmt) )
879 {
880 return (DDERETURN)(DWORD)DDE_FACK;
881 }
882 }
883
884 return (DDERETURN)DDE_FNOTPROCESSED;
885 }
886 }
887
888 return (DDERETURN)0;
889 }
890
891 // ----------------------------------------------------------------------------
892 // DDE strings and atoms
893 // ----------------------------------------------------------------------------
894
895 // Atom table stuff
896 static HSZ DDEAddAtom(const wxString& string)
897 {
898 HSZ atom = DDEAtomFromString(string);
899 wxAtomTable.Append(string, (wxObject *)atom);
900 return atom;
901 }
902
903 static HSZ DDEGetAtom(const wxString& string)
904 {
905 wxNode *node = wxAtomTable.Find(string);
906 if (node)
907 return (HSZ)node->Data();
908 else
909 {
910 DDEAddAtom(string);
911 return (HSZ)(wxAtomTable.Find(string)->Data());
912 }
913 }
914
915 // atom <-> strings
916 static HSZ DDEAtomFromString(const wxString& s)
917 {
918 wxASSERT_MSG( DDEIdInst, _T("DDE not initialized") );
919
920 HSZ hsz = DdeCreateStringHandle(DDEIdInst, (wxChar*) s.c_str(), DDE_CP);
921 if ( !hsz )
922 {
923 DDELogError(_("Failed to create DDE string"));
924 }
925
926 return hsz;
927 }
928
929 static wxString DDEStringFromAtom(HSZ hsz)
930 {
931 // all DDE strings are normally limited to 255 bytes
932 static const size_t len = 256;
933
934 wxString s;
935 (void)DdeQueryString(DDEIdInst, hsz, s.GetWriteBuf(len), len, DDE_CP);
936 s.UngetWriteBuf();
937
938 return s;
939 }
940
941 // ----------------------------------------------------------------------------
942 // error handling
943 // ----------------------------------------------------------------------------
944
945 static void DDELogError(const wxString& s, UINT error)
946 {
947 if ( !error )
948 {
949 error = DdeGetLastError(DDEIdInst);
950 }
951
952 wxLogError(s + _T(": ") + DDEGetErrorMsg(error));
953 }
954
955 static wxString DDEGetErrorMsg(UINT error)
956 {
957 wxString err;
958 switch ( error )
959 {
960 case DMLERR_NO_ERROR:
961 err = _("no DDE error.");
962 break;
963
964 case DMLERR_ADVACKTIMEOUT:
965 err = _("a request for a synchronous advise transaction has timed out.");
966 break;
967 case DMLERR_BUSY:
968 err = _("the response to the transaction caused the DDE_FBUSY bit to be set.");
969 break;
970 case DMLERR_DATAACKTIMEOUT:
971 err = _("a request for a synchronous data transaction has timed out.");
972 break;
973 case DMLERR_DLL_NOT_INITIALIZED:
974 err = _("a DDEML function was called without first calling the DdeInitialize function,\nor an invalid instance identifier\nwas passed to a DDEML function.");
975 break;
976 case DMLERR_DLL_USAGE:
977 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.");
978 break;
979 case DMLERR_EXECACKTIMEOUT:
980 err = _("a request for a synchronous execute transaction has timed out.");
981 break;
982 case DMLERR_INVALIDPARAMETER:
983 err = _("a parameter failed to be validated by the DDEML.");
984 break;
985 case DMLERR_LOW_MEMORY:
986 err = _("a DDEML application has created a prolonged race condition.");
987 break;
988 case DMLERR_MEMORY_ERROR:
989 err = _("a memory allocation failed.");
990 break;
991 case DMLERR_NO_CONV_ESTABLISHED:
992 err = _("a client's attempt to establish a conversation has failed.");
993 break;
994 case DMLERR_NOTPROCESSED:
995 err = _("a transaction failed.");
996 break;
997 case DMLERR_POKEACKTIMEOUT:
998 err = _("a request for a synchronous poke transaction has timed out.");
999 break;
1000 case DMLERR_POSTMSG_FAILED:
1001 err = _("an internal call to the PostMessage function has failed. ");
1002 break;
1003 case DMLERR_REENTRANCY:
1004 err = _("reentrancy problem.");
1005 break;
1006 case DMLERR_SERVER_DIED:
1007 err = _("a server-side transaction was attempted on a conversation\nthat was terminated by the client, or the server\nterminated before completing a transaction.");
1008 break;
1009 case DMLERR_SYS_ERROR:
1010 err = _("an internal error has occurred in the DDEML.");
1011 break;
1012 case DMLERR_UNADVACKTIMEOUT:
1013 err = _("a request to end an advise transaction has timed out.");
1014 break;
1015 case DMLERR_UNFOUND_QUEUE_ID:
1016 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.");
1017 break;
1018 default:
1019 err.Printf(_("Unknown DDE error %08x"), error);
1020 }
1021
1022 return err;
1023 }
1024
1025 #endif
1026 // wxUSE_IPC