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