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