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