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