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