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