]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dde.cpp
more synonyms for UCS-2/4
[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
5bd3a2da
VZ
48// ----------------------------------------------------------------------------
49// macros and constants
50// ----------------------------------------------------------------------------
2bda0e17
KB
51
52#ifdef __WIN32__
5bd3a2da 53 #define _EXPORT
2bda0e17 54#else
5bd3a2da 55 #define _EXPORT _export
2bda0e17
KB
56#endif
57
5bd3a2da
VZ
58#if wxUSE_UNICODE
59 #define DDE_CP CP_WINUNICODE
60#else
61 #define DDE_CP CP_WINANSI
62#endif
63
64#define GetHConv() ((HCONV)m_hConv)
65
66// default timeout for DDE operations (5sec)
67#define DDE_TIMEOUT 5000
68
69// ----------------------------------------------------------------------------
70// private functions
71// ----------------------------------------------------------------------------
2bda0e17
KB
72
73static wxDDEConnection *DDEFindConnection(HCONV hConv);
74static void DDEDeleteConnection(HCONV hConv);
75static wxDDEServer *DDEFindServer(const wxString& s);
76
5bd3a2da
VZ
77extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback(WORD wType,
78 WORD wFmt,
79 HCONV hConv,
80 HSZ hsz1,
81 HSZ hsz2,
82 HDDEDATA hData,
83 DWORD lData1,
84 DWORD lData2);
2bda0e17
KB
85
86// Add topic name to atom table before using in conversations
87static HSZ DDEAddAtom(const wxString& string);
88static HSZ DDEGetAtom(const wxString& string);
5bd3a2da
VZ
89
90// string handles
91static HSZ DDEAtomFromString(const wxString& s);
92static wxString DDEStringFromAtom(HSZ hsz);
0ebb0e5c 93static void DDEFreeString(HSZ hsz);
5bd3a2da
VZ
94
95// error handling
96static wxString DDEGetErrorMsg(UINT error);
97static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR);
98
99// ----------------------------------------------------------------------------
100// global variables
101// ----------------------------------------------------------------------------
2bda0e17 102
df5168c4
MB
103WX_DECLARE_STRING_HASH_MAP( HSZ, wxAtomMap );
104
2bda0e17
KB
105static DWORD DDEIdInst = 0L;
106static wxDDEConnection *DDECurrentlyConnecting = NULL;
df5168c4 107static wxAtomMap wxAtomTable;
d162a7ee
VZ
108
109#include "wx/listimpl.cpp"
110
111WX_DEFINE_LIST(wxDDEClientList);
112WX_DEFINE_LIST(wxDDEServerList);
113WX_DEFINE_LIST(wxDDEConnectionList);
114
115static wxDDEClientList wxDDEClientObjects;
116static wxDDEServerList wxDDEServerObjects;
2bda0e17 117
cdd64cc0 118static bool DDEInitialized = false;
2bda0e17 119
5bd3a2da
VZ
120// ----------------------------------------------------------------------------
121// private classes
122// ----------------------------------------------------------------------------
2bda0e17 123
5bd3a2da
VZ
124// A module to allow DDE cleanup without calling these functions
125// from app.cpp or from the user's application.
2bda0e17 126
5bd3a2da 127class wxDDEModule : public wxModule
2bda0e17 128{
5bd3a2da
VZ
129public:
130 wxDDEModule() {}
cdd64cc0 131 bool OnInit() { return true; }
5bd3a2da 132 void OnExit() { wxDDECleanUp(); }
2bda0e17 133
5bd3a2da
VZ
134private:
135 DECLARE_DYNAMIC_CLASS(wxDDEModule)
136};
2bda0e17 137
5bd3a2da
VZ
138// ----------------------------------------------------------------------------
139// wxWin macros
140// ----------------------------------------------------------------------------
2bda0e17 141
5bd3a2da
VZ
142IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
143IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
144IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase)
145IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
146
147// ============================================================================
148// implementation
149// ============================================================================
150
151// ----------------------------------------------------------------------------
152// initialization and cleanup
153// ----------------------------------------------------------------------------
154
155extern void wxDDEInitialize()
2bda0e17 156{
5bd3a2da
VZ
157 if ( !DDEInitialized )
158 {
159 // Should insert filter flags
160 PFNCALLBACK callback = (PFNCALLBACK)
161 MakeProcInstance((FARPROC)_DDECallback, wxGetInstance());
162 UINT rc = DdeInitialize(&DDEIdInst, callback, APPCLASS_STANDARD, 0L);
163 if ( rc != DMLERR_NO_ERROR )
164 {
165 DDELogError(_T("Failed to initialize DDE"), rc);
166 }
167 else
168 {
cdd64cc0 169 DDEInitialized = true;
5bd3a2da
VZ
170 }
171 }
2bda0e17
KB
172}
173
5bd3a2da 174void wxDDECleanUp()
e2a6f233 175{
bd947cc9
VZ
176 // deleting them later won't work as DDE won't be initialized any more
177 wxASSERT_MSG( wxDDEServerObjects.empty() &&
178 wxDDEClientObjects.empty(),
179 _T("all DDE objects should be deleted by now") );
5a33bc09 180
df5168c4 181 wxAtomTable.clear();
5a33bc09 182
5bd3a2da
VZ
183 if ( DDEIdInst != 0 )
184 {
185 DdeUninitialize(DDEIdInst);
186 DDEIdInst = 0;
187 }
5bd3a2da
VZ
188}
189
190// ----------------------------------------------------------------------------
191// functions working with the global connection list(s)
192// ----------------------------------------------------------------------------
e2a6f233 193
2bda0e17
KB
194// Global find connection
195static wxDDEConnection *DDEFindConnection(HCONV hConv)
196{
df5168c4 197 wxDDEServerList::compatibility_iterator serverNode = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
198 wxDDEConnection *found = NULL;
199 while (serverNode && !found)
200 {
201 wxDDEServer *object = serverNode->GetData();
202 found = object->FindConnection((WXHCONV) hConv);
203 serverNode = serverNode->GetNext();
204 }
205
206 if (found)
207 {
208 return found;
209 }
210
df5168c4 211 wxDDEClientList::compatibility_iterator clientNode = wxDDEClientObjects.GetFirst();
d162a7ee
VZ
212 while (clientNode && !found)
213 {
214 wxDDEClient *object = clientNode->GetData();
215 found = object->FindConnection((WXHCONV) hConv);
216 clientNode = clientNode->GetNext();
217 }
218 return found;
2bda0e17
KB
219}
220
221// Global delete connection
222static void DDEDeleteConnection(HCONV hConv)
223{
df5168c4 224 wxDDEServerList::compatibility_iterator serverNode = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
225 bool found = false;
226 while (serverNode && !found)
227 {
228 wxDDEServer *object = serverNode->GetData();
229 found = object->DeleteConnection((WXHCONV) hConv);
230 serverNode = serverNode->GetNext();
231 }
232 if (found)
233 {
234 return;
235 }
236
df5168c4 237 wxDDEClientList::compatibility_iterator clientNode = wxDDEClientObjects.GetFirst();
d162a7ee
VZ
238 while (clientNode && !found)
239 {
240 wxDDEClient *object = clientNode->GetData();
241 found = object->DeleteConnection((WXHCONV) hConv);
242 clientNode = clientNode->GetNext();
243 }
2bda0e17
KB
244}
245
246// Find a server from a service name
247static wxDDEServer *DDEFindServer(const wxString& s)
248{
df5168c4 249 wxDDEServerList::compatibility_iterator node = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
250 wxDDEServer *found = NULL;
251 while (node && !found)
252 {
253 wxDDEServer *object = node->GetData();
254
255 if (object->GetServiceName() == s)
256 {
257 found = object;
258 }
259 else
260 {
261 node = node->GetNext();
262 }
263 }
264
265 return found;
2bda0e17
KB
266}
267
5bd3a2da
VZ
268// ----------------------------------------------------------------------------
269// wxDDEServer
270// ----------------------------------------------------------------------------
2bda0e17 271
5bd3a2da 272wxDDEServer::wxDDEServer()
2bda0e17 273{
5bd3a2da
VZ
274 wxDDEInitialize();
275
276 wxDDEServerObjects.Append(this);
2bda0e17
KB
277}
278
5bd3a2da 279bool wxDDEServer::Create(const wxString& server)
2bda0e17 280{
5bd3a2da 281 m_serviceName = server;
2bda0e17 282
0ebb0e5c 283 HSZ hsz = DDEAtomFromString(server);
5bd3a2da 284
0ebb0e5c
DS
285 if ( !hsz )
286 {
cdd64cc0 287 return false;
5bd3a2da
VZ
288 }
289
0ebb0e5c
DS
290
291 bool success = (DdeNameService(DDEIdInst, hsz, (HSZ) NULL, DNS_REGISTER)
292 != NULL);
293
294 if (!success)
295 {
296 DDELogError(wxString::Format(_("Failed to register DDE server '%s'"),
297 server.c_str()));
298 }
299
300 DDEFreeString(hsz);
301
302 return success;
2bda0e17
KB
303}
304
5bd3a2da 305wxDDEServer::~wxDDEServer()
2bda0e17 306{
d71cc120 307 if ( !m_serviceName.IsEmpty() )
2bda0e17 308 {
0ebb0e5c
DS
309 HSZ hsz = DDEAtomFromString(m_serviceName);
310
311 if (hsz)
5bd3a2da 312 {
0ebb0e5c
DS
313 if ( !DdeNameService(DDEIdInst, hsz,
314 (HSZ) NULL, DNS_UNREGISTER) )
315 {
316 DDELogError(wxString::Format(
317 _("Failed to unregister DDE server '%s'"),
318 m_serviceName.c_str()));
319 }
320
321 DDEFreeString(hsz);
5bd3a2da 322 }
2bda0e17 323 }
2bda0e17 324
5bd3a2da 325 wxDDEServerObjects.DeleteObject(this);
2bda0e17 326
df5168c4 327 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
5bd3a2da
VZ
328 while (node)
329 {
d162a7ee 330 wxDDEConnection *connection = node->GetData();
df5168c4 331 wxDDEConnectionList::compatibility_iterator next = node->GetNext();
f010ad48 332 connection->SetConnected(false);
5bd3a2da
VZ
333 connection->OnDisconnect(); // May delete the node implicitly
334 node = next;
335 }
336
337 // If any left after this, delete them
cdd64cc0 338 node = m_connections.GetFirst();
5bd3a2da
VZ
339 while (node)
340 {
d162a7ee 341 wxDDEConnection *connection = node->GetData();
df5168c4 342 wxDDEConnectionList::compatibility_iterator next = node->GetNext();
5bd3a2da
VZ
343 delete connection;
344 node = next;
345 }
2bda0e17
KB
346}
347
348wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */)
349{
5bd3a2da 350 return new wxDDEConnection;
2bda0e17
KB
351}
352
353wxDDEConnection *wxDDEServer::FindConnection(WXHCONV conv)
354{
df5168c4 355 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
5bd3a2da
VZ
356 wxDDEConnection *found = NULL;
357 while (node && !found)
358 {
d162a7ee 359 wxDDEConnection *connection = node->GetData();
5bd3a2da
VZ
360 if (connection->m_hConv == conv)
361 found = connection;
cdd64cc0 362 else node = node->GetNext();
5bd3a2da
VZ
363 }
364 return found;
2bda0e17
KB
365}
366
367// Only delete the entry in the map, not the actual connection
368bool wxDDEServer::DeleteConnection(WXHCONV conv)
369{
df5168c4
MB
370 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
371 while (node)
2bda0e17 372 {
d162a7ee 373 wxDDEConnection *connection = node->GetData();
5bd3a2da
VZ
374 if (connection->m_hConv == conv)
375 {
df5168c4
MB
376 m_connections.Erase(node);
377 return true;
5bd3a2da 378 }
d162a7ee
VZ
379 else
380 {
381 node = node->GetNext();
382 }
2bda0e17 383 }
df5168c4 384 return false;
2bda0e17
KB
385}
386
5bd3a2da
VZ
387// ----------------------------------------------------------------------------
388// wxDDEClient
389// ----------------------------------------------------------------------------
2bda0e17 390
5bd3a2da 391wxDDEClient::wxDDEClient()
2bda0e17 392{
5bd3a2da
VZ
393 wxDDEInitialize();
394
395 wxDDEClientObjects.Append(this);
2bda0e17
KB
396}
397
5bd3a2da 398wxDDEClient::~wxDDEClient()
2bda0e17 399{
5bd3a2da 400 wxDDEClientObjects.DeleteObject(this);
df5168c4 401 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
5bd3a2da
VZ
402 while (node)
403 {
d162a7ee 404 wxDDEConnection *connection = node->GetData();
5bd3a2da 405 delete connection; // Deletes the node implicitly (see ~wxDDEConnection)
cdd64cc0 406 node = m_connections.GetFirst();
5bd3a2da 407 }
2bda0e17
KB
408}
409
410bool wxDDEClient::ValidHost(const wxString& /* host */)
411{
cdd64cc0 412 return true;
2bda0e17
KB
413}
414
5bd3a2da
VZ
415wxConnectionBase *wxDDEClient::MakeConnection(const wxString& WXUNUSED(host),
416 const wxString& server,
417 const wxString& topic)
2bda0e17 418{
0ebb0e5c
DS
419 HSZ hszServer = DDEAtomFromString(server);
420
421 if ( !hszServer )
422 {
423 return (wxConnectionBase*) NULL;
424 }
425
426
427 HSZ hszTopic = DDEAtomFromString(topic);
428
429 if ( !hszTopic )
430 {
431 DDEFreeString(hszServer);
432 return (wxConnectionBase*) NULL;
433 }
434
435
436 HCONV hConv = ::DdeConnect(DDEIdInst, hszServer, hszTopic,
437 (PCONVCONTEXT) NULL);
438
439 DDEFreeString(hszServer);
440 DDEFreeString(hszTopic);
441
442
5bd3a2da 443 if ( !hConv )
2bda0e17 444 {
0ebb0e5c
DS
445 DDELogError( wxString::Format(
446 _("Failed to create connection to server '%s' on topic '%s'"),
447 server.c_str(), topic.c_str()) );
2bda0e17 448 }
5bd3a2da
VZ
449 else
450 {
451 wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection();
452 if (connection)
453 {
454 connection->m_hConv = (WXHCONV) hConv;
455 connection->m_topicName = topic;
456 connection->m_client = this;
457 m_connections.Append(connection);
458 return connection;
459 }
460 }
461
462 return (wxConnectionBase*) NULL;
2bda0e17
KB
463}
464
5bd3a2da 465wxConnectionBase *wxDDEClient::OnMakeConnection()
2bda0e17 466{
5bd3a2da 467 return new wxDDEConnection;
2bda0e17
KB
468}
469
470wxDDEConnection *wxDDEClient::FindConnection(WXHCONV conv)
471{
df5168c4 472 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
5bd3a2da
VZ
473 wxDDEConnection *found = NULL;
474 while (node && !found)
475 {
d162a7ee 476 wxDDEConnection *connection = node->GetData();
5bd3a2da
VZ
477 if (connection->m_hConv == conv)
478 found = connection;
cdd64cc0 479 else node = node->GetNext();
5bd3a2da
VZ
480 }
481 return found;
2bda0e17
KB
482}
483
484// Only delete the entry in the map, not the actual connection
485bool wxDDEClient::DeleteConnection(WXHCONV conv)
486{
df5168c4
MB
487 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
488 while (node)
2bda0e17 489 {
d162a7ee 490 wxDDEConnection *connection = node->GetData();
5bd3a2da
VZ
491 if (connection->m_hConv == conv)
492 {
df5168c4
MB
493 m_connections.Erase(node);
494 return true;
5bd3a2da 495 }
cdd64cc0 496 else node = node->GetNext();
2bda0e17 497 }
df5168c4 498 return false;
2bda0e17
KB
499}
500
5bd3a2da
VZ
501// ----------------------------------------------------------------------------
502// wxDDEConnection
503// ----------------------------------------------------------------------------
2bda0e17 504
d38e8d5f 505wxDDEConnection::wxDDEConnection(wxChar *buffer, int size)
f010ad48 506 : wxConnectionBase(buffer, size)
2bda0e17 507{
5bd3a2da
VZ
508 m_client = NULL;
509 m_server = NULL;
2bda0e17 510
5bd3a2da
VZ
511 m_hConv = 0;
512 m_sendingData = NULL;
2bda0e17
KB
513}
514
5bd3a2da 515wxDDEConnection::wxDDEConnection()
f010ad48 516 : wxConnectionBase()
2bda0e17 517{
5bd3a2da
VZ
518 m_hConv = 0;
519 m_sendingData = NULL;
520 m_server = NULL;
521 m_client = NULL;
2bda0e17
KB
522}
523
5bd3a2da 524wxDDEConnection::~wxDDEConnection()
2bda0e17 525{
f010ad48 526 Disconnect();
5bd3a2da
VZ
527 if (m_server)
528 m_server->GetConnections().DeleteObject(this);
529 else
530 m_client->GetConnections().DeleteObject(this);
2bda0e17
KB
531}
532
533// Calls that CLIENT can make
5bd3a2da 534bool wxDDEConnection::Disconnect()
2bda0e17 535{
f010ad48
JS
536 if ( !GetConnected() )
537 return true;
538
5bd3a2da
VZ
539 DDEDeleteConnection(GetHConv());
540
541 bool ok = DdeDisconnect(GetHConv()) != 0;
542 if ( !ok )
543 {
544 DDELogError(_T("Failed to disconnect from DDE server gracefully"));
545 }
546
f010ad48
JS
547 SetConnected( false ); // so we don't try and disconnect again
548
5bd3a2da 549 return ok;
2bda0e17
KB
550}
551
9d860992 552bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat WXUNUSED(format))
2bda0e17 553{
5bd3a2da
VZ
554 DWORD result;
555 if (size < 0)
556 {
9d860992 557 size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
5bd3a2da 558 }
2bda0e17 559
d71cc120 560 bool ok = DdeClientTransaction((LPBYTE)data,
9d860992 561 size,
5bd3a2da
VZ
562 GetHConv(),
563 NULL,
9d860992
JS
564// If the transaction specified by the wType parameter does not pass data or is XTYP_EXECUTE,
565// wFmt should be zero.
566 0,
5bd3a2da
VZ
567 XTYP_EXECUTE,
568 DDE_TIMEOUT,
569 &result) != 0;
6ba63600 570
5bd3a2da
VZ
571 if ( !ok )
572 {
573 DDELogError(_T("DDE execute request failed"));
574 }
2bda0e17 575
5bd3a2da 576 return ok;
2bda0e17
KB
577}
578
d38e8d5f 579wxChar *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
2bda0e17 580{
5bd3a2da 581 DWORD result;
f010ad48 582
5bd3a2da
VZ
583 HSZ atom = DDEGetAtom(item);
584
585 HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
586 GetHConv(),
587 atom, format,
588 XTYP_REQUEST,
589 DDE_TIMEOUT,
590 &result);
591 if ( !returned_data )
592 {
593 DDELogError(_T("DDE data request failed"));
594
595 return NULL;
596 }
2bda0e17 597
f010ad48
JS
598 DWORD len = DdeGetData(returned_data, NULL, 0, 0);
599
940ef730 600 wxChar *data = GetBufferAtLeast( len );
f010ad48
JS
601 wxASSERT_MSG(data != NULL,
602 _T("Buffer too small in wxDDEConnection::Request") );
0ebb0e5c 603 (void) DdeGetData(returned_data, (LPBYTE)data, len, 0);
2bda0e17 604
0ebb0e5c 605 (void) DdeFreeDataHandle(returned_data);
2bda0e17 606
5bd3a2da 607 if (size)
9d860992 608 *size = (int)len;
2bda0e17 609
f010ad48 610 return data;
2bda0e17
KB
611}
612
837e5743 613bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
2bda0e17 614{
5bd3a2da
VZ
615 DWORD result;
616 if (size < 0)
617 {
9d860992 618 size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
5bd3a2da 619 }
2bda0e17 620
5bd3a2da 621 HSZ item_atom = DDEGetAtom(item);
d71cc120 622 bool ok = DdeClientTransaction((LPBYTE)data,
9d860992 623 size,
5bd3a2da
VZ
624 GetHConv(),
625 item_atom, format,
626 XTYP_POKE,
627 DDE_TIMEOUT,
628 &result) != 0;
629 if ( !ok )
630 {
631 DDELogError(_("DDE poke request failed"));
632 }
2bda0e17 633
5bd3a2da 634 return ok;
2bda0e17
KB
635}
636
637bool wxDDEConnection::StartAdvise(const wxString& item)
638{
5bd3a2da
VZ
639 DWORD result;
640 HSZ atom = DDEGetAtom(item);
2bda0e17 641
5bd3a2da
VZ
642 bool ok = DdeClientTransaction(NULL, 0,
643 GetHConv(),
644 atom, CF_TEXT,
645 XTYP_ADVSTART,
646 DDE_TIMEOUT,
647 &result) != 0;
648 if ( !ok )
649 {
650 DDELogError(_("Failed to establish an advise loop with DDE server"));
651 }
652
653 return ok;
2bda0e17
KB
654}
655
656bool wxDDEConnection::StopAdvise(const wxString& item)
657{
5bd3a2da
VZ
658 DWORD result;
659 HSZ atom = DDEGetAtom(item);
2bda0e17 660
5bd3a2da
VZ
661 bool ok = DdeClientTransaction(NULL, 0,
662 GetHConv(),
663 atom, CF_TEXT,
664 XTYP_ADVSTOP,
665 DDE_TIMEOUT,
666 &result) != 0;
667 if ( !ok )
668 {
669 DDELogError(_("Failed to terminate the advise loop with DDE server"));
670 }
671
672 return ok;
2bda0e17
KB
673}
674
675// Calls that SERVER can make
5bd3a2da
VZ
676bool wxDDEConnection::Advise(const wxString& item,
677 wxChar *data,
678 int size,
679 wxIPCFormat format)
2bda0e17 680{
5bd3a2da
VZ
681 if (size < 0)
682 {
9d860992 683 size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
5bd3a2da 684 }
2bda0e17 685
5bd3a2da
VZ
686 HSZ item_atom = DDEGetAtom(item);
687 HSZ topic_atom = DDEGetAtom(m_topicName);
f010ad48 688 m_sendingData = data; // mrf: potential for scope problems here?
5bd3a2da 689 m_dataSize = size;
9d860992
JS
690 // wxIPC_PRIVATE does not succeed, so use text instead
691 m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format;
2bda0e17 692
5bd3a2da
VZ
693 bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
694 if ( !ok )
695 {
696 DDELogError(_("Failed to send DDE advise notification"));
697 }
698
699 return ok;
2bda0e17
KB
700}
701
5bd3a2da 702bool wxDDEConnection::OnDisconnect()
2bda0e17 703{
5bd3a2da 704 delete this;
cdd64cc0 705 return true;
2bda0e17
KB
706}
707
5bd3a2da
VZ
708// ----------------------------------------------------------------------------
709// _DDECallback
710// ----------------------------------------------------------------------------
2bda0e17
KB
711
712#define DDERETURN HDDEDATA
713
5bd3a2da
VZ
714HDDEDATA EXPENTRY _EXPORT
715_DDECallback(WORD wType,
716 WORD wFmt,
717 HCONV hConv,
718 HSZ hsz1,
719 HSZ hsz2,
720 HDDEDATA hData,
721 DWORD WXUNUSED(lData1),
722 DWORD WXUNUSED(lData2))
723{
724 switch (wType)
2bda0e17 725 {
5bd3a2da
VZ
726 case XTYP_CONNECT:
727 {
728 wxString topic = DDEStringFromAtom(hsz1),
729 srv = DDEStringFromAtom(hsz2);
730 wxDDEServer *server = DDEFindServer(srv);
731 if (server)
732 {
733 wxDDEConnection *connection =
734 (wxDDEConnection*) server->OnAcceptConnection(topic);
735 if (connection)
736 {
737 connection->m_server = server;
738 server->GetConnections().Append(connection);
739 connection->m_hConv = 0;
740 connection->m_topicName = topic;
741 DDECurrentlyConnecting = connection;
cdd64cc0 742 return (DDERETURN)(DWORD)true;
5bd3a2da
VZ
743 }
744 }
745 break;
746 }
747
748 case XTYP_CONNECT_CONFIRM:
749 {
750 if (DDECurrentlyConnecting)
751 {
752 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
753 DDECurrentlyConnecting = NULL;
cdd64cc0 754 return (DDERETURN)(DWORD)true;
5bd3a2da
VZ
755 }
756 break;
757 }
758
759 case XTYP_DISCONNECT:
760 {
761 wxDDEConnection *connection = DDEFindConnection(hConv);
f010ad48 762 if (connection)
5bd3a2da 763 {
f010ad48
JS
764 connection->SetConnected( false );
765 if (connection->OnDisconnect())
766 {
767 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
cdd64cc0 768 return (DDERETURN)(DWORD)true;
f010ad48 769 }
5bd3a2da
VZ
770 }
771 break;
772 }
773
774 case XTYP_EXECUTE:
775 {
776 wxDDEConnection *connection = DDEFindConnection(hConv);
777
778 if (connection)
779 {
f010ad48
JS
780 DWORD len = DdeGetData(hData, NULL, 0, 0);
781
940ef730 782 wxChar *data = connection->GetBufferAtLeast( len );
f010ad48
JS
783 wxASSERT_MSG(data != NULL,
784 _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") );
785
786 DdeGetData(hData, (LPBYTE)data, len, 0);
787
5bd3a2da 788 DdeFreeDataHandle(hData);
f010ad48 789
9d860992 790// XTYP_EXECUTE cannot be used for arbitrary data, but only for text
5bd3a2da 791 if ( connection->OnExecute(connection->m_topicName,
f010ad48 792 data,
940ef730 793 (int)len,
9d860992 794 wxIPC_TEXT ) )
5bd3a2da
VZ
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)
9d860992 819 user_size = (wxStrlen((wxChar*)data) + 1) * sizeof(wxChar); // includes final NUL
5bd3a2da
VZ
820
821 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
822 (LPBYTE)data,
9d860992 823 user_size,
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
940ef730 844 wxChar *data = connection->GetBufferAtLeast( len );
f010ad48 845 wxASSERT_MSG(data != NULL,
9d860992 846 _T("Buffer too small in _DDECallback (XTYP_POKE)") );
f010ad48
JS
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,
940ef730 855 (int)len,
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,
9d860992 906 connection->m_dataSize,
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
940ef730 931 wxChar *data = connection->GetBufferAtLeast( len );
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,
940ef730 941 (int)len,
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