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