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