]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dde.cpp
Added chapter on collection and container classes to contents
[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;
533 if ( !ok )
534 {
535 DDELogError(_T("DDE execute request failed"));
536 }
2bda0e17 537
5bd3a2da 538 return ok;
2bda0e17
KB
539}
540
0d2a2b60 541char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
2bda0e17 542{
5bd3a2da
VZ
543 DWORD result;
544 HSZ atom = DDEGetAtom(item);
545
546 HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
547 GetHConv(),
548 atom, format,
549 XTYP_REQUEST,
550 DDE_TIMEOUT,
551 &result);
552 if ( !returned_data )
553 {
554 DDELogError(_T("DDE data request failed"));
555
556 return NULL;
557 }
2bda0e17 558
5bd3a2da 559 DWORD len = DdeGetData(returned_data, (LPBYTE)m_bufPtr, m_bufSize, 0);
2bda0e17 560
5bd3a2da 561 DdeFreeDataHandle(returned_data);
2bda0e17 562
5bd3a2da
VZ
563 if (size)
564 *size = (int)len;
2bda0e17 565
b3324be2 566 return m_bufPtr;
2bda0e17
KB
567}
568
837e5743 569bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
2bda0e17 570{
5bd3a2da
VZ
571 DWORD result;
572 if (size < 0)
573 {
574 size = wxStrlen(data) + 1;
575 }
2bda0e17 576
5bd3a2da
VZ
577 HSZ item_atom = DDEGetAtom(item);
578 bool ok = DdeClientTransaction((LPBYTE)data, size,
579 GetHConv(),
580 item_atom, format,
581 XTYP_POKE,
582 DDE_TIMEOUT,
583 &result) != 0;
584 if ( !ok )
585 {
586 DDELogError(_("DDE poke request failed"));
587 }
2bda0e17 588
5bd3a2da 589 return ok;
2bda0e17
KB
590}
591
592bool wxDDEConnection::StartAdvise(const wxString& item)
593{
5bd3a2da
VZ
594 DWORD result;
595 HSZ atom = DDEGetAtom(item);
2bda0e17 596
5bd3a2da
VZ
597 bool ok = DdeClientTransaction(NULL, 0,
598 GetHConv(),
599 atom, CF_TEXT,
600 XTYP_ADVSTART,
601 DDE_TIMEOUT,
602 &result) != 0;
603 if ( !ok )
604 {
605 DDELogError(_("Failed to establish an advise loop with DDE server"));
606 }
607
608 return ok;
2bda0e17
KB
609}
610
611bool wxDDEConnection::StopAdvise(const wxString& item)
612{
5bd3a2da
VZ
613 DWORD result;
614 HSZ atom = DDEGetAtom(item);
2bda0e17 615
5bd3a2da
VZ
616 bool ok = DdeClientTransaction(NULL, 0,
617 GetHConv(),
618 atom, CF_TEXT,
619 XTYP_ADVSTOP,
620 DDE_TIMEOUT,
621 &result) != 0;
622 if ( !ok )
623 {
624 DDELogError(_("Failed to terminate the advise loop with DDE server"));
625 }
626
627 return ok;
2bda0e17
KB
628}
629
630// Calls that SERVER can make
5bd3a2da
VZ
631bool wxDDEConnection::Advise(const wxString& item,
632 wxChar *data,
633 int size,
634 wxIPCFormat format)
2bda0e17 635{
5bd3a2da
VZ
636 if (size < 0)
637 {
638 size = wxStrlen(data) + 1;
639 }
2bda0e17 640
5bd3a2da
VZ
641 HSZ item_atom = DDEGetAtom(item);
642 HSZ topic_atom = DDEGetAtom(m_topicName);
643 m_sendingData = data;
644 m_dataSize = size;
645 m_dataType = format;
2bda0e17 646
5bd3a2da
VZ
647 bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
648 if ( !ok )
649 {
650 DDELogError(_("Failed to send DDE advise notification"));
651 }
652
653 return ok;
2bda0e17
KB
654}
655
5bd3a2da 656bool wxDDEConnection::OnDisconnect()
2bda0e17 657{
5bd3a2da
VZ
658 delete this;
659 return TRUE;
2bda0e17
KB
660}
661
5bd3a2da
VZ
662// ----------------------------------------------------------------------------
663// _DDECallback
664// ----------------------------------------------------------------------------
2bda0e17
KB
665
666#define DDERETURN HDDEDATA
667
5bd3a2da
VZ
668HDDEDATA EXPENTRY _EXPORT
669_DDECallback(WORD wType,
670 WORD wFmt,
671 HCONV hConv,
672 HSZ hsz1,
673 HSZ hsz2,
674 HDDEDATA hData,
675 DWORD WXUNUSED(lData1),
676 DWORD WXUNUSED(lData2))
677{
678 switch (wType)
2bda0e17 679 {
5bd3a2da
VZ
680 case XTYP_CONNECT:
681 {
682 wxString topic = DDEStringFromAtom(hsz1),
683 srv = DDEStringFromAtom(hsz2);
684 wxDDEServer *server = DDEFindServer(srv);
685 if (server)
686 {
687 wxDDEConnection *connection =
688 (wxDDEConnection*) server->OnAcceptConnection(topic);
689 if (connection)
690 {
691 connection->m_server = server;
692 server->GetConnections().Append(connection);
693 connection->m_hConv = 0;
694 connection->m_topicName = topic;
695 DDECurrentlyConnecting = connection;
696 return (DDERETURN)(DWORD)TRUE;
697 }
698 }
699 break;
700 }
701
702 case XTYP_CONNECT_CONFIRM:
703 {
704 if (DDECurrentlyConnecting)
705 {
706 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
707 DDECurrentlyConnecting = NULL;
708 return (DDERETURN)(DWORD)TRUE;
709 }
710 break;
711 }
712
713 case XTYP_DISCONNECT:
714 {
715 wxDDEConnection *connection = DDEFindConnection(hConv);
716 if (connection && connection->OnDisconnect())
717 {
718 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
719 return (DDERETURN)(DWORD)TRUE;
720 }
721 break;
722 }
723
724 case XTYP_EXECUTE:
725 {
726 wxDDEConnection *connection = DDEFindConnection(hConv);
727
728 if (connection)
729 {
730 DWORD len = DdeGetData(hData,
731 (LPBYTE)connection->m_bufPtr,
732 connection->m_bufSize,
733 0);
734 DdeFreeDataHandle(hData);
735 if ( connection->OnExecute(connection->m_topicName,
736 connection->m_bufPtr,
737 (int)len,
738 (wxIPCFormat) wFmt) )
739 {
740 return (DDERETURN)(DWORD)DDE_FACK;
741 }
742 }
743
744 return (DDERETURN)DDE_FNOTPROCESSED;
745 }
746
747 case XTYP_REQUEST:
748 {
749 wxDDEConnection *connection = DDEFindConnection(hConv);
750
751 if (connection)
752 {
753 wxString item_name = DDEStringFromAtom(hsz2);
754
755 int user_size = -1;
756 char *data = connection->OnRequest(connection->m_topicName,
757 item_name,
758 &user_size,
759 (wxIPCFormat) wFmt);
760 if (data)
761 {
762 if (user_size < 0)
f6bcfd97 763 user_size = wxStrlen((wxChar*)data) + 1;
5bd3a2da
VZ
764
765 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
766 (LPBYTE)data,
767 user_size,
768 0,
769 hsz2,
770 wFmt,
771 0);
772 return (DDERETURN)handle;
773 }
774 }
775 break;
776 }
777
778 case XTYP_POKE:
779 {
780 wxDDEConnection *connection = DDEFindConnection(hConv);
781
782 if (connection)
783 {
784 wxString item_name = DDEStringFromAtom(hsz2);
785
786 DWORD len = DdeGetData(hData,
787 (LPBYTE)connection->m_bufPtr,
788 connection->m_bufSize,
789 0);
790 DdeFreeDataHandle(hData);
791
792 connection->OnPoke(connection->m_topicName,
793 item_name,
f6bcfd97 794 (wxChar*)connection->m_bufPtr,
5bd3a2da
VZ
795 (int)len,
796 (wxIPCFormat) wFmt);
797
798 return (DDERETURN)DDE_FACK;
799 }
800 else
801 {
802 return (DDERETURN)DDE_FNOTPROCESSED;
803 }
804 }
805
806 case XTYP_ADVSTART:
807 {
808 wxDDEConnection *connection = DDEFindConnection(hConv);
809
810 if (connection)
811 {
812 wxString item_name = DDEStringFromAtom(hsz2);
813
814 return (DDERETURN)connection->
815 OnStartAdvise(connection->m_topicName, item_name);
816 }
817
818 break;
819 }
820
821 case XTYP_ADVSTOP:
822 {
823 wxDDEConnection *connection = DDEFindConnection(hConv);
824
825 if (connection)
826 {
827 wxString item_name = DDEStringFromAtom(hsz2);
828
829 return (DDERETURN)connection->
830 OnStopAdvise(connection->m_topicName, item_name);
831 }
832
833 break;
834 }
835
836 case XTYP_ADVREQ:
837 {
838 wxDDEConnection *connection = DDEFindConnection(hConv);
839
840 if (connection && connection->m_sendingData)
841 {
842 HDDEDATA data = DdeCreateDataHandle
843 (
844 DDEIdInst,
845 (LPBYTE)connection->m_sendingData,
846 connection->m_dataSize,
847 0,
848 hsz2,
849 connection->m_dataType,
850 0
851 );
852
853 connection->m_sendingData = NULL;
854
855 return (DDERETURN)data;
856 }
857
858 break;
859 }
860
861 case XTYP_ADVDATA:
862 {
863 wxDDEConnection *connection = DDEFindConnection(hConv);
864
865 if (connection)
866 {
867 wxString item_name = DDEStringFromAtom(hsz2);
868
869 DWORD len = DdeGetData(hData,
870 (LPBYTE)connection->m_bufPtr,
871 connection->m_bufSize,
872 0);
873 DdeFreeDataHandle(hData);
874 if ( connection->OnAdvise(connection->m_topicName,
875 item_name,
876 connection->m_bufPtr,
877 (int)len,
878 (wxIPCFormat) wFmt) )
879 {
880 return (DDERETURN)(DWORD)DDE_FACK;
881 }
882 }
883
884 return (DDERETURN)DDE_FNOTPROCESSED;
885 }
2bda0e17
KB
886 }
887
5bd3a2da
VZ
888 return (DDERETURN)0;
889}
2bda0e17 890
5bd3a2da
VZ
891// ----------------------------------------------------------------------------
892// DDE strings and atoms
893// ----------------------------------------------------------------------------
2bda0e17 894
5bd3a2da
VZ
895// Atom table stuff
896static HSZ DDEAddAtom(const wxString& string)
897{
898 HSZ atom = DDEAtomFromString(string);
899 wxAtomTable.Append(string, (wxObject *)atom);
900 return atom;
901}
2bda0e17 902
5bd3a2da
VZ
903static HSZ DDEGetAtom(const wxString& string)
904{
905 wxNode *node = wxAtomTable.Find(string);
906 if (node)
907 return (HSZ)node->Data();
908 else
2bda0e17 909 {
5bd3a2da
VZ
910 DDEAddAtom(string);
911 return (HSZ)(wxAtomTable.Find(string)->Data());
2bda0e17 912 }
5bd3a2da 913}
2bda0e17 914
5bd3a2da
VZ
915// atom <-> strings
916static HSZ DDEAtomFromString(const wxString& s)
917{
918 wxASSERT_MSG( DDEIdInst, _T("DDE not initialized") );
919
f6bcfd97 920 HSZ hsz = DdeCreateStringHandle(DDEIdInst, (wxChar*) s.c_str(), DDE_CP);
5bd3a2da 921 if ( !hsz )
2bda0e17 922 {
5bd3a2da 923 DDELogError(_("Failed to create DDE string"));
2bda0e17
KB
924 }
925
5bd3a2da
VZ
926 return hsz;
927}
2bda0e17 928
5bd3a2da
VZ
929static wxString DDEStringFromAtom(HSZ hsz)
930{
931 // all DDE strings are normally limited to 255 bytes
932 static const size_t len = 256;
2bda0e17 933
5bd3a2da
VZ
934 wxString s;
935 (void)DdeQueryString(DDEIdInst, hsz, s.GetWriteBuf(len), len, DDE_CP);
936 s.UngetWriteBuf();
2bda0e17 937
5bd3a2da
VZ
938 return s;
939}
2bda0e17 940
5bd3a2da
VZ
941// ----------------------------------------------------------------------------
942// error handling
943// ----------------------------------------------------------------------------
2bda0e17 944
5bd3a2da
VZ
945static void DDELogError(const wxString& s, UINT error)
946{
947 if ( !error )
2bda0e17 948 {
5bd3a2da 949 error = DdeGetLastError(DDEIdInst);
2bda0e17 950 }
2bda0e17 951
5bd3a2da 952 wxLogError(s + _T(": ") + DDEGetErrorMsg(error));
2bda0e17
KB
953}
954
5bd3a2da 955static wxString DDEGetErrorMsg(UINT error)
2bda0e17 956{
5bd3a2da
VZ
957 wxString err;
958 switch ( error )
959 {
960 case DMLERR_NO_ERROR:
961 err = _("no DDE error.");
962 break;
963
964 case DMLERR_ADVACKTIMEOUT:
965 err = _("a request for a synchronous advise transaction has timed out.");
966 break;
967 case DMLERR_BUSY:
968 err = _("the response to the transaction caused the DDE_FBUSY bit to be set.");
969 break;
970 case DMLERR_DATAACKTIMEOUT:
971 err = _("a request for a synchronous data transaction has timed out.");
972 break;
973 case DMLERR_DLL_NOT_INITIALIZED:
f83e3685 974 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
975 break;
976 case DMLERR_DLL_USAGE:
f83e3685 977 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
978 break;
979 case DMLERR_EXECACKTIMEOUT:
980 err = _("a request for a synchronous execute transaction has timed out.");
981 break;
982 case DMLERR_INVALIDPARAMETER:
983 err = _("a parameter failed to be validated by the DDEML.");
984 break;
985 case DMLERR_LOW_MEMORY:
986 err = _("a DDEML application has created a prolonged race condition.");
987 break;
988 case DMLERR_MEMORY_ERROR:
989 err = _("a memory allocation failed.");
990 break;
991 case DMLERR_NO_CONV_ESTABLISHED:
992 err = _("a client's attempt to establish a conversation has failed.");
993 break;
994 case DMLERR_NOTPROCESSED:
995 err = _("a transaction failed.");
996 break;
997 case DMLERR_POKEACKTIMEOUT:
998 err = _("a request for a synchronous poke transaction has timed out.");
999 break;
1000 case DMLERR_POSTMSG_FAILED:
1001 err = _("an internal call to the PostMessage function has failed. ");
1002 break;
1003 case DMLERR_REENTRANCY:
1004 err = _("reentrancy problem.");
1005 break;
1006 case DMLERR_SERVER_DIED:
f83e3685 1007 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
1008 break;
1009 case DMLERR_SYS_ERROR:
1010 err = _("an internal error has occurred in the DDEML.");
1011 break;
1012 case DMLERR_UNADVACKTIMEOUT:
1013 err = _("a request to end an advise transaction has timed out.");
1014 break;
1015 case DMLERR_UNFOUND_QUEUE_ID:
f83e3685 1016 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
1017 break;
1018 default:
1019 err.Printf(_("Unknown DDE error %08x"), error);
1020 }
2bda0e17 1021
5bd3a2da 1022 return err;
2bda0e17
KB
1023}
1024
1025#endif
47d67540 1026 // wxUSE_IPC