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