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