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