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