]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dde.cpp
added wxLog::Suspend/Resume and wxYield() uses them now so that it won't flush
[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 {
5bd3a2da
VZ
401 DDELogError(wxString::Format(_("Failed to create connection to "
402 "server '%s' on topic '%s'"),
403 server.c_str(), topic.c_str()));
2bda0e17 404 }
5bd3a2da
VZ
405 else
406 {
407 wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection();
408 if (connection)
409 {
410 connection->m_hConv = (WXHCONV) hConv;
411 connection->m_topicName = topic;
412 connection->m_client = this;
413 m_connections.Append(connection);
414 return connection;
415 }
416 }
417
418 return (wxConnectionBase*) NULL;
2bda0e17
KB
419}
420
5bd3a2da 421wxConnectionBase *wxDDEClient::OnMakeConnection()
2bda0e17 422{
5bd3a2da 423 return new wxDDEConnection;
2bda0e17
KB
424}
425
426wxDDEConnection *wxDDEClient::FindConnection(WXHCONV conv)
427{
5bd3a2da
VZ
428 wxNode *node = m_connections.First();
429 wxDDEConnection *found = NULL;
430 while (node && !found)
431 {
432 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
433 if (connection->m_hConv == conv)
434 found = connection;
435 else node = node->Next();
436 }
437 return found;
2bda0e17
KB
438}
439
440// Only delete the entry in the map, not the actual connection
441bool wxDDEClient::DeleteConnection(WXHCONV conv)
442{
5bd3a2da
VZ
443 wxNode *node = m_connections.First();
444 bool found = FALSE;
445 while (node && !found)
2bda0e17 446 {
5bd3a2da
VZ
447 wxDDEConnection *connection = (wxDDEConnection *)node->Data();
448 if (connection->m_hConv == conv)
449 {
450 found = TRUE;
451 delete node;
452 }
453 else node = node->Next();
2bda0e17 454 }
5bd3a2da 455 return found;
2bda0e17
KB
456}
457
5bd3a2da
VZ
458// ----------------------------------------------------------------------------
459// wxDDEConnection
460// ----------------------------------------------------------------------------
2bda0e17
KB
461
462wxDDEConnection::wxDDEConnection(char *buffer, int size)
463{
5bd3a2da
VZ
464 if (buffer == NULL)
465 {
466 if (DDEDefaultIPCBuffer == NULL)
467 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
468 m_bufPtr = DDEDefaultIPCBuffer;
469 m_bufSize = DDEDefaultIPCBufferSize;
470 }
471 else
472 {
473 m_bufPtr = buffer;
474 m_bufSize = size;
475 }
2bda0e17 476
5bd3a2da
VZ
477 m_client = NULL;
478 m_server = NULL;
2bda0e17 479
5bd3a2da
VZ
480 m_hConv = 0;
481 m_sendingData = NULL;
2bda0e17
KB
482}
483
5bd3a2da 484wxDDEConnection::wxDDEConnection()
2bda0e17 485{
5bd3a2da
VZ
486 m_hConv = 0;
487 m_sendingData = NULL;
488 m_server = NULL;
489 m_client = NULL;
490 if (DDEDefaultIPCBuffer == NULL)
491 DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
2bda0e17 492
5bd3a2da
VZ
493 m_bufPtr = DDEDefaultIPCBuffer;
494 m_bufSize = DDEDefaultIPCBufferSize;
2bda0e17
KB
495}
496
5bd3a2da 497wxDDEConnection::~wxDDEConnection()
2bda0e17 498{
5bd3a2da
VZ
499 if (m_server)
500 m_server->GetConnections().DeleteObject(this);
501 else
502 m_client->GetConnections().DeleteObject(this);
2bda0e17
KB
503}
504
505// Calls that CLIENT can make
5bd3a2da 506bool wxDDEConnection::Disconnect()
2bda0e17 507{
5bd3a2da
VZ
508 DDEDeleteConnection(GetHConv());
509
510 bool ok = DdeDisconnect(GetHConv()) != 0;
511 if ( !ok )
512 {
513 DDELogError(_T("Failed to disconnect from DDE server gracefully"));
514 }
515
516 return ok;
2bda0e17
KB
517}
518
73974df1 519bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
2bda0e17 520{
5bd3a2da
VZ
521 DWORD result;
522 if (size < 0)
523 {
524 size = wxStrlen(data) + 1;
525 }
2bda0e17 526
5bd3a2da
VZ
527 bool ok = DdeClientTransaction((LPBYTE)data, size,
528 GetHConv(),
529 NULL,
530 format,
531 XTYP_EXECUTE,
532 DDE_TIMEOUT,
533 &result) != 0;
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,
737 connection->m_bufPtr,
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)
764 user_size = wxStrlen(data) + 1;
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,
795 connection->m_bufPtr,
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,
877 connection->m_bufPtr,
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
56880523 921 HSZ hsz = DdeCreateStringHandle(DDEIdInst, (char*) 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:
975 err = _("a DDEML function was called without first calling the DdeInitialize function,\n\ror an invalid instance identifier\n\rwas passed to a DDEML function.");
976 break;
977 case DMLERR_DLL_USAGE:
978 err = _("an application initialized as APPCLASS_MONITOR has\n\rattempted to perform a DDE transaction,\n\ror an application initialized as APPCMD_CLIENTONLY has \n\rattempted to perform server transactions.");
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:
1008 err = _("a server-side transaction was attempted on a conversation\n\rthat was terminated by the client, or the server\n\rterminated before completing a transaction.");
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:
1017 err = _("an invalid transaction identifier was passed to a DDEML function.\n\rOnce the application has returned from an XTYP_XACT_COMPLETE callback,\n\rthe transaction identifier for that callback is no longer valid.");
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