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