]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dde.cpp
Correct making the newly inserted menu item owner drawn in some cases.
[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
6c9a19aa 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
2bda0e17
KB
9/////////////////////////////////////////////////////////////////////////////
10
5bd3a2da
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
2bda0e17
KB
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
5bd3a2da 23 #pragma hdrstop
2bda0e17
KB
24#endif
25
47d67540 26#if wxUSE_IPC
2bda0e17
KB
27
28#ifndef WX_PRECOMP
5bd3a2da
VZ
29 #include "wx/utils.h"
30 #include "wx/app.h"
df69528b 31 #include "wx/hashmap.h"
02761f6c 32 #include "wx/module.h"
2bda0e17
KB
33#endif
34
2bda0e17 35#include "wx/dde.h"
56880523 36#include "wx/intl.h"
8b1350d4
VZ
37#include "wx/buffer.h"
38#include "wx/strconv.h"
2bda0e17 39
03ab016d 40#include "wx/msw/private.h"
5bd3a2da
VZ
41
42#include <string.h>
03ab016d
JS
43#include <ddeml.h>
44
5bd3a2da
VZ
45// ----------------------------------------------------------------------------
46// macros and constants
47// ----------------------------------------------------------------------------
2bda0e17
KB
48
49#ifdef __WIN32__
5bd3a2da 50 #define _EXPORT
2bda0e17 51#else
5bd3a2da 52 #define _EXPORT _export
2bda0e17
KB
53#endif
54
5bd3a2da
VZ
55#if wxUSE_UNICODE
56 #define DDE_CP CP_WINUNICODE
57#else
58 #define DDE_CP CP_WINANSI
59#endif
60
61#define GetHConv() ((HCONV)m_hConv)
62
63// default timeout for DDE operations (5sec)
64#define DDE_TIMEOUT 5000
65
66// ----------------------------------------------------------------------------
67// private functions
68// ----------------------------------------------------------------------------
2bda0e17
KB
69
70static wxDDEConnection *DDEFindConnection(HCONV hConv);
71static void DDEDeleteConnection(HCONV hConv);
72static wxDDEServer *DDEFindServer(const wxString& s);
73
5bd3a2da
VZ
74extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback(WORD wType,
75 WORD wFmt,
76 HCONV hConv,
77 HSZ hsz1,
78 HSZ hsz2,
79 HDDEDATA hData,
80 DWORD lData1,
81 DWORD lData2);
2bda0e17
KB
82
83// Add topic name to atom table before using in conversations
84static HSZ DDEAddAtom(const wxString& string);
85static HSZ DDEGetAtom(const wxString& string);
5bd3a2da
VZ
86
87// string handles
88static HSZ DDEAtomFromString(const wxString& s);
89static wxString DDEStringFromAtom(HSZ hsz);
0ebb0e5c 90static void DDEFreeString(HSZ hsz);
5bd3a2da
VZ
91
92// error handling
93static wxString DDEGetErrorMsg(UINT error);
94static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR);
95
96// ----------------------------------------------------------------------------
97// global variables
98// ----------------------------------------------------------------------------
2bda0e17 99
3f5c62f9 100WX_DECLARE_STRING_HASH_MAP( HSZ, wxAtomMap );
df5168c4 101
2bda0e17
KB
102static DWORD DDEIdInst = 0L;
103static wxDDEConnection *DDECurrentlyConnecting = NULL;
df5168c4 104static wxAtomMap wxAtomTable;
d162a7ee
VZ
105
106#include "wx/listimpl.cpp"
107
4115960d
VZ
108WX_DEFINE_LIST(wxDDEClientList)
109WX_DEFINE_LIST(wxDDEServerList)
110WX_DEFINE_LIST(wxDDEConnectionList)
d162a7ee
VZ
111
112static wxDDEClientList wxDDEClientObjects;
113static wxDDEServerList wxDDEServerObjects;
2bda0e17 114
cdd64cc0 115static bool DDEInitialized = false;
2bda0e17 116
5bd3a2da
VZ
117// ----------------------------------------------------------------------------
118// private classes
119// ----------------------------------------------------------------------------
2bda0e17 120
5bd3a2da
VZ
121// A module to allow DDE cleanup without calling these functions
122// from app.cpp or from the user's application.
2bda0e17 123
5bd3a2da 124class wxDDEModule : public wxModule
2bda0e17 125{
5bd3a2da
VZ
126public:
127 wxDDEModule() {}
cdd64cc0 128 bool OnInit() { return true; }
5bd3a2da 129 void OnExit() { wxDDECleanUp(); }
2bda0e17 130
5bd3a2da
VZ
131private:
132 DECLARE_DYNAMIC_CLASS(wxDDEModule)
133};
2bda0e17 134
5bd3a2da
VZ
135// ----------------------------------------------------------------------------
136// wxWin macros
137// ----------------------------------------------------------------------------
2bda0e17 138
5bd3a2da
VZ
139IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase)
140IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase)
0a8d6945 141IMPLEMENT_DYNAMIC_CLASS(wxDDEConnection, wxConnectionBase)
5bd3a2da
VZ
142IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
143
144// ============================================================================
145// implementation
146// ============================================================================
147
148// ----------------------------------------------------------------------------
149// initialization and cleanup
150// ----------------------------------------------------------------------------
151
152extern void wxDDEInitialize()
2bda0e17 153{
5bd3a2da
VZ
154 if ( !DDEInitialized )
155 {
156 // Should insert filter flags
157 PFNCALLBACK callback = (PFNCALLBACK)
158 MakeProcInstance((FARPROC)_DDECallback, wxGetInstance());
159 UINT rc = DdeInitialize(&DDEIdInst, callback, APPCLASS_STANDARD, 0L);
160 if ( rc != DMLERR_NO_ERROR )
161 {
9a83f860 162 DDELogError(wxT("Failed to initialize DDE"), rc);
5bd3a2da
VZ
163 }
164 else
165 {
cdd64cc0 166 DDEInitialized = true;
5bd3a2da
VZ
167 }
168 }
2bda0e17
KB
169}
170
5bd3a2da 171void wxDDECleanUp()
e2a6f233 172{
bd947cc9
VZ
173 // deleting them later won't work as DDE won't be initialized any more
174 wxASSERT_MSG( wxDDEServerObjects.empty() &&
175 wxDDEClientObjects.empty(),
9a83f860 176 wxT("all DDE objects should be deleted by now") );
5a33bc09 177
df5168c4 178 wxAtomTable.clear();
5a33bc09 179
5bd3a2da
VZ
180 if ( DDEIdInst != 0 )
181 {
182 DdeUninitialize(DDEIdInst);
183 DDEIdInst = 0;
184 }
5bd3a2da
VZ
185}
186
187// ----------------------------------------------------------------------------
188// functions working with the global connection list(s)
189// ----------------------------------------------------------------------------
e2a6f233 190
2bda0e17
KB
191// Global find connection
192static wxDDEConnection *DDEFindConnection(HCONV hConv)
193{
df5168c4 194 wxDDEServerList::compatibility_iterator serverNode = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
195 wxDDEConnection *found = NULL;
196 while (serverNode && !found)
197 {
198 wxDDEServer *object = serverNode->GetData();
199 found = object->FindConnection((WXHCONV) hConv);
200 serverNode = serverNode->GetNext();
201 }
202
203 if (found)
204 {
205 return found;
206 }
207
df5168c4 208 wxDDEClientList::compatibility_iterator clientNode = wxDDEClientObjects.GetFirst();
d162a7ee
VZ
209 while (clientNode && !found)
210 {
211 wxDDEClient *object = clientNode->GetData();
212 found = object->FindConnection((WXHCONV) hConv);
213 clientNode = clientNode->GetNext();
214 }
215 return found;
2bda0e17
KB
216}
217
218// Global delete connection
219static void DDEDeleteConnection(HCONV hConv)
220{
df5168c4 221 wxDDEServerList::compatibility_iterator serverNode = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
222 bool found = false;
223 while (serverNode && !found)
224 {
225 wxDDEServer *object = serverNode->GetData();
226 found = object->DeleteConnection((WXHCONV) hConv);
227 serverNode = serverNode->GetNext();
228 }
229 if (found)
230 {
231 return;
232 }
233
df5168c4 234 wxDDEClientList::compatibility_iterator clientNode = wxDDEClientObjects.GetFirst();
d162a7ee
VZ
235 while (clientNode && !found)
236 {
237 wxDDEClient *object = clientNode->GetData();
238 found = object->DeleteConnection((WXHCONV) hConv);
239 clientNode = clientNode->GetNext();
240 }
2bda0e17
KB
241}
242
243// Find a server from a service name
244static wxDDEServer *DDEFindServer(const wxString& s)
245{
df5168c4 246 wxDDEServerList::compatibility_iterator node = wxDDEServerObjects.GetFirst();
d162a7ee
VZ
247 wxDDEServer *found = NULL;
248 while (node && !found)
249 {
250 wxDDEServer *object = node->GetData();
251
252 if (object->GetServiceName() == s)
253 {
254 found = object;
255 }
256 else
257 {
258 node = node->GetNext();
259 }
260 }
261
262 return found;
2bda0e17
KB
263}
264
5bd3a2da
VZ
265// ----------------------------------------------------------------------------
266// wxDDEServer
267// ----------------------------------------------------------------------------
2bda0e17 268
5bd3a2da 269wxDDEServer::wxDDEServer()
2bda0e17 270{
5bd3a2da
VZ
271 wxDDEInitialize();
272
273 wxDDEServerObjects.Append(this);
2bda0e17
KB
274}
275
5bd3a2da 276bool wxDDEServer::Create(const wxString& server)
2bda0e17 277{
5bd3a2da 278 m_serviceName = server;
2bda0e17 279
0ebb0e5c 280 HSZ hsz = DDEAtomFromString(server);
5bd3a2da 281
0ebb0e5c
DS
282 if ( !hsz )
283 {
cdd64cc0 284 return false;
5bd3a2da
VZ
285 }
286
0ebb0e5c
DS
287
288 bool success = (DdeNameService(DDEIdInst, hsz, (HSZ) NULL, DNS_REGISTER)
289 != NULL);
290
291 if (!success)
292 {
293 DDELogError(wxString::Format(_("Failed to register DDE server '%s'"),
294 server.c_str()));
295 }
296
297 DDEFreeString(hsz);
298
299 return success;
2bda0e17
KB
300}
301
5bd3a2da 302wxDDEServer::~wxDDEServer()
2bda0e17 303{
df69528b 304 if ( !m_serviceName.empty() )
2bda0e17 305 {
0ebb0e5c
DS
306 HSZ hsz = DDEAtomFromString(m_serviceName);
307
308 if (hsz)
5bd3a2da 309 {
0ebb0e5c
DS
310 if ( !DdeNameService(DDEIdInst, hsz,
311 (HSZ) NULL, DNS_UNREGISTER) )
312 {
313 DDELogError(wxString::Format(
314 _("Failed to unregister DDE server '%s'"),
315 m_serviceName.c_str()));
316 }
317
318 DDEFreeString(hsz);
5bd3a2da 319 }
2bda0e17 320 }
2bda0e17 321
5bd3a2da 322 wxDDEServerObjects.DeleteObject(this);
2bda0e17 323
df5168c4 324 wxDDEConnectionList::compatibility_iterator node = m_connections.GetFirst();
5bd3a2da
VZ
325 while (node)
326 {
d162a7ee 327 wxDDEConnection *connection = node->GetData();
df5168c4 328 wxDDEConnectionList::compatibility_iterator next = node->GetNext();
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 {
d3b9f782 419 return NULL;
0ebb0e5c
DS
420 }
421
422
423 HSZ hszTopic = DDEAtomFromString(topic);
424
425 if ( !hszTopic )
426 {
427 DDEFreeString(hszServer);
d3b9f782 428 return NULL;
0ebb0e5c
DS
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
d3b9f782 458 return 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 {
9a83f860 540 DDELogError(wxT("Failed to disconnect from DDE server gracefully"));
5bd3a2da
VZ
541 }
542
f010ad48
JS
543 SetConnected( false ); // so we don't try and disconnect again
544
5bd3a2da 545 return ok;
2bda0e17
KB
546}
547
8b1350d4
VZ
548bool
549wxDDEConnection::DoExecute(const void *data, size_t size, wxIPCFormat format)
2bda0e17 550{
8b1350d4
VZ
551 wxCHECK_MSG( format == wxIPC_TEXT ||
552 format == wxIPC_UTF8TEXT ||
553 format == wxIPC_UNICODETEXT,
554 false,
9a83f860 555 wxT("wxDDEServer::Execute() supports only text data") );
8b1350d4
VZ
556
557 wxMemoryBuffer buffer;
d6906a06
VZ
558 LPBYTE realData = NULL;
559 size_t realSize = 0;
8b1350d4
VZ
560 wxMBConv *conv = NULL;
561
562 // Windows only supports either ANSI or UTF-16 format depending on the
563 // build, so we need to convert the data if it doesn't use it already
564#if wxUSE_UNICODE
565 if ( format == wxIPC_TEXT )
566 {
567 conv = &wxConvLibc;
568 }
569 else if ( format == wxIPC_UTF8TEXT )
570 {
571 conv = &wxConvUTF8;
572 }
573 else // no conversion necessary for wxIPC_UNICODETEXT
574 {
575 realData = (LPBYTE)data;
576 realSize = size;
577 }
2bda0e17 578
8b1350d4
VZ
579 if ( conv )
580 {
581 const char * const text = (const char *)data;
784d9056 582 const size_t len = size;
8b1350d4
VZ
583
584 realSize = conv->ToWChar(NULL, 0, text, len);
585 if ( realSize == wxCONV_FAILED )
586 return false;
587
588 realData = (LPBYTE)buffer.GetWriteBuf(realSize*sizeof(wchar_t));
589 if ( !realData )
590 return false;
591
592 realSize = conv->ToWChar((wchar_t *)realData, realSize, text, len);
593 if ( realSize == wxCONV_FAILED )
594 return false;
5e9d3bf7
VZ
595
596 // We need to pass the size of the buffer to DdeClientTransaction() and
597 // not the length of the string.
598 realSize *= sizeof(wchar_t);
8b1350d4
VZ
599 }
600#else // !wxUSE_UNICODE
601 if ( format == wxIPC_UNICODETEXT )
602 {
603 conv = &wxConvLibc;
604 }
605 else if ( format == wxIPC_UTF8TEXT )
606 {
607 // we could implement this in theory but it's not obvious how to pass
608 // the format information and, basically, why bother -- just use
609 // Unicode build
9a83f860 610 wxFAIL_MSG( wxT("UTF-8 text not supported in ANSI build") );
8b1350d4
VZ
611
612 return false;
613 }
614 else // don't convert wxIPC_TEXT
615 {
616 realData = (LPBYTE)data;
617 realSize = size;
618 }
619
620 if ( conv )
621 {
622 const wchar_t * const wtext = (const wchar_t *)data;
623 const size_t len = size/sizeof(wchar_t);
624
625 realSize = conv->FromWChar(NULL, 0, wtext, len);
626 if ( realSize == wxCONV_FAILED )
627 return false;
628
784d9056 629 realData = (LPBYTE)buffer.GetWriteBuf(realSize);
8b1350d4
VZ
630 if ( !realData )
631 return false;
632
633 realSize = conv->FromWChar((char*)realData, realSize, wtext, len);
634 if ( realSize == wxCONV_FAILED )
635 return false;
636 }
637#endif // wxUSE_UNICODE/!wxUSE_UNICODE
638
639 DWORD result;
640 bool ok = DdeClientTransaction(realData,
5e9d3bf7 641 realSize,
b81885a6
VZ
642 GetHConv(),
643 NULL,
644 // MSDN: if the transaction specified by
645 // the wType parameter does not pass data
646 // or is XTYP_EXECUTE, wFmt should be zero.
647 0,
648 XTYP_EXECUTE,
649 DDE_TIMEOUT,
650 &result) != 0;
6ba63600 651
5bd3a2da
VZ
652 if ( !ok )
653 {
9a83f860 654 DDELogError(wxT("DDE execute request failed"));
5bd3a2da 655 }
2bda0e17 656
5bd3a2da 657 return ok;
2bda0e17
KB
658}
659
50c549b9 660const void *wxDDEConnection::Request(const wxString& item, size_t *size, wxIPCFormat format)
2bda0e17 661{
5bd3a2da 662 DWORD result;
f010ad48 663
5bd3a2da
VZ
664 HSZ atom = DDEGetAtom(item);
665
666 HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
667 GetHConv(),
668 atom, format,
669 XTYP_REQUEST,
670 DDE_TIMEOUT,
671 &result);
672 if ( !returned_data )
673 {
9a83f860 674 DDELogError(wxT("DDE data request failed"));
5bd3a2da
VZ
675
676 return NULL;
677 }
2bda0e17 678
f010ad48
JS
679 DWORD len = DdeGetData(returned_data, NULL, 0, 0);
680
50c549b9 681 void *data = GetBufferAtLeast(len);
f010ad48 682 wxASSERT_MSG(data != NULL,
9a83f860 683 wxT("Buffer too small in wxDDEConnection::Request") );
0ebb0e5c 684 (void) DdeGetData(returned_data, (LPBYTE)data, len, 0);
2bda0e17 685
0ebb0e5c 686 (void) DdeFreeDataHandle(returned_data);
2bda0e17 687
5bd3a2da 688 if (size)
50c549b9 689 *size = (size_t)len;
2bda0e17 690
f010ad48 691 return data;
2bda0e17
KB
692}
693
50c549b9 694bool wxDDEConnection::DoPoke(const wxString& item, const void *data, size_t size, wxIPCFormat format)
2bda0e17 695{
5bd3a2da 696 DWORD result;
2bda0e17 697
5bd3a2da 698 HSZ item_atom = DDEGetAtom(item);
d71cc120 699 bool ok = DdeClientTransaction((LPBYTE)data,
9d860992 700 size,
5bd3a2da
VZ
701 GetHConv(),
702 item_atom, format,
703 XTYP_POKE,
704 DDE_TIMEOUT,
705 &result) != 0;
706 if ( !ok )
707 {
708 DDELogError(_("DDE poke request failed"));
709 }
2bda0e17 710
5bd3a2da 711 return ok;
2bda0e17
KB
712}
713
714bool wxDDEConnection::StartAdvise(const wxString& item)
715{
5bd3a2da
VZ
716 DWORD result;
717 HSZ atom = DDEGetAtom(item);
2bda0e17 718
5bd3a2da
VZ
719 bool ok = DdeClientTransaction(NULL, 0,
720 GetHConv(),
721 atom, CF_TEXT,
722 XTYP_ADVSTART,
723 DDE_TIMEOUT,
724 &result) != 0;
725 if ( !ok )
726 {
727 DDELogError(_("Failed to establish an advise loop with DDE server"));
728 }
729
730 return ok;
2bda0e17
KB
731}
732
733bool wxDDEConnection::StopAdvise(const wxString& item)
734{
5bd3a2da
VZ
735 DWORD result;
736 HSZ atom = DDEGetAtom(item);
2bda0e17 737
5bd3a2da
VZ
738 bool ok = DdeClientTransaction(NULL, 0,
739 GetHConv(),
740 atom, CF_TEXT,
741 XTYP_ADVSTOP,
742 DDE_TIMEOUT,
743 &result) != 0;
744 if ( !ok )
745 {
746 DDELogError(_("Failed to terminate the advise loop with DDE server"));
747 }
748
749 return ok;
2bda0e17
KB
750}
751
752// Calls that SERVER can make
50c549b9
VZ
753bool wxDDEConnection::DoAdvise(const wxString& item,
754 const void *data,
755 size_t size,
756 wxIPCFormat format)
2bda0e17 757{
5bd3a2da
VZ
758 HSZ item_atom = DDEGetAtom(item);
759 HSZ topic_atom = DDEGetAtom(m_topicName);
f010ad48 760 m_sendingData = data; // mrf: potential for scope problems here?
5bd3a2da 761 m_dataSize = size;
9d860992
JS
762 // wxIPC_PRIVATE does not succeed, so use text instead
763 m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format;
2bda0e17 764
5bd3a2da
VZ
765 bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
766 if ( !ok )
767 {
768 DDELogError(_("Failed to send DDE advise notification"));
769 }
770
771 return ok;
2bda0e17
KB
772}
773
5bd3a2da
VZ
774// ----------------------------------------------------------------------------
775// _DDECallback
776// ----------------------------------------------------------------------------
2bda0e17
KB
777
778#define DDERETURN HDDEDATA
779
5bd3a2da
VZ
780HDDEDATA EXPENTRY _EXPORT
781_DDECallback(WORD wType,
782 WORD wFmt,
783 HCONV hConv,
784 HSZ hsz1,
785 HSZ hsz2,
786 HDDEDATA hData,
787 DWORD WXUNUSED(lData1),
788 DWORD WXUNUSED(lData2))
789{
790 switch (wType)
2bda0e17 791 {
5bd3a2da
VZ
792 case XTYP_CONNECT:
793 {
794 wxString topic = DDEStringFromAtom(hsz1),
795 srv = DDEStringFromAtom(hsz2);
796 wxDDEServer *server = DDEFindServer(srv);
797 if (server)
798 {
799 wxDDEConnection *connection =
800 (wxDDEConnection*) server->OnAcceptConnection(topic);
801 if (connection)
802 {
803 connection->m_server = server;
804 server->GetConnections().Append(connection);
805 connection->m_hConv = 0;
806 connection->m_topicName = topic;
807 DDECurrentlyConnecting = connection;
cdd64cc0 808 return (DDERETURN)(DWORD)true;
5bd3a2da
VZ
809 }
810 }
811 break;
812 }
813
814 case XTYP_CONNECT_CONFIRM:
815 {
816 if (DDECurrentlyConnecting)
817 {
818 DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv;
819 DDECurrentlyConnecting = NULL;
cdd64cc0 820 return (DDERETURN)(DWORD)true;
5bd3a2da
VZ
821 }
822 break;
823 }
824
825 case XTYP_DISCONNECT:
826 {
827 wxDDEConnection *connection = DDEFindConnection(hConv);
f010ad48 828 if (connection)
5bd3a2da 829 {
f010ad48
JS
830 connection->SetConnected( false );
831 if (connection->OnDisconnect())
832 {
833 DDEDeleteConnection(hConv); // Delete mapping: hConv => connection
cdd64cc0 834 return (DDERETURN)(DWORD)true;
f010ad48 835 }
5bd3a2da
VZ
836 }
837 break;
838 }
839
840 case XTYP_EXECUTE:
841 {
842 wxDDEConnection *connection = DDEFindConnection(hConv);
843
844 if (connection)
845 {
f010ad48
JS
846 DWORD len = DdeGetData(hData, NULL, 0, 0);
847
50c549b9 848 void *data = connection->GetBufferAtLeast(len);
f010ad48 849 wxASSERT_MSG(data != NULL,
9a83f860 850 wxT("Buffer too small in _DDECallback (XTYP_EXECUTE)") );
f010ad48
JS
851
852 DdeGetData(hData, (LPBYTE)data, len, 0);
853
5bd3a2da 854 DdeFreeDataHandle(hData);
f010ad48 855
8b1350d4
VZ
856 // XTYP_EXECUTE can be used for text only and the text is
857 // always in ANSI format for ANSI build and Unicode format
858 // in Unicode build
859 #if wxUSE_UNICODE
860 wFmt = wxIPC_UNICODETEXT;
861 #else
862 wFmt = wxIPC_TEXT;
863 #endif
864
5bd3a2da 865 if ( connection->OnExecute(connection->m_topicName,
f010ad48 866 data,
940ef730 867 (int)len,
8b1350d4 868 (wxIPCFormat)wFmt) )
5bd3a2da
VZ
869 {
870 return (DDERETURN)(DWORD)DDE_FACK;
871 }
872 }
873
874 return (DDERETURN)DDE_FNOTPROCESSED;
875 }
876
877 case XTYP_REQUEST:
878 {
879 wxDDEConnection *connection = DDEFindConnection(hConv);
880
881 if (connection)
882 {
883 wxString item_name = DDEStringFromAtom(hsz2);
884
50c549b9
VZ
885 size_t user_size = wxNO_LEN;
886 const void *data = connection->OnRequest(connection->m_topicName,
887 item_name,
888 &user_size,
889 (wxIPCFormat)wFmt);
5bd3a2da
VZ
890 if (data)
891 {
50c549b9
VZ
892 if (user_size == wxNO_LEN)
893 switch (wFmt)
894 {
895 case wxIPC_TEXT:
896 case wxIPC_UTF8TEXT:
897 user_size = strlen((const char*)data) + 1; // includes final NUL
898 break;
899 case wxIPC_UNICODETEXT:
900 user_size = (wcslen((const wchar_t*)data) + 1) * sizeof(wchar_t); // includes final NUL
901 break;
902 default:
903 user_size = 0;
904 }
5bd3a2da
VZ
905
906 HDDEDATA handle = DdeCreateDataHandle(DDEIdInst,
907 (LPBYTE)data,
9d860992 908 user_size,
5bd3a2da
VZ
909 0,
910 hsz2,
911 wFmt,
912 0);
913 return (DDERETURN)handle;
914 }
915 }
916 break;
917 }
918
919 case XTYP_POKE:
920 {
921 wxDDEConnection *connection = DDEFindConnection(hConv);
922
923 if (connection)
924 {
925 wxString item_name = DDEStringFromAtom(hsz2);
926
f010ad48
JS
927 DWORD len = DdeGetData(hData, NULL, 0, 0);
928
50c549b9 929 void *data = connection->GetBufferAtLeast(len);
f010ad48 930 wxASSERT_MSG(data != NULL,
9a83f860 931 wxT("Buffer too small in _DDECallback (XTYP_POKE)") );
f010ad48
JS
932
933 DdeGetData(hData, (LPBYTE)data, len, 0);
934
5bd3a2da
VZ
935 DdeFreeDataHandle(hData);
936
937 connection->OnPoke(connection->m_topicName,
938 item_name,
f010ad48 939 data,
940ef730 940 (int)len,
5bd3a2da
VZ
941 (wxIPCFormat) wFmt);
942
943 return (DDERETURN)DDE_FACK;
944 }
945 else
946 {
947 return (DDERETURN)DDE_FNOTPROCESSED;
948 }
949 }
950
951 case XTYP_ADVSTART:
952 {
953 wxDDEConnection *connection = DDEFindConnection(hConv);
954
955 if (connection)
956 {
957 wxString item_name = DDEStringFromAtom(hsz2);
958
959 return (DDERETURN)connection->
960 OnStartAdvise(connection->m_topicName, item_name);
961 }
962
963 break;
964 }
965
966 case XTYP_ADVSTOP:
967 {
968 wxDDEConnection *connection = DDEFindConnection(hConv);
969
970 if (connection)
971 {
972 wxString item_name = DDEStringFromAtom(hsz2);
973
974 return (DDERETURN)connection->
975 OnStopAdvise(connection->m_topicName, item_name);
976 }
977
978 break;
979 }
980
981 case XTYP_ADVREQ:
982 {
983 wxDDEConnection *connection = DDEFindConnection(hConv);
984
985 if (connection && connection->m_sendingData)
986 {
987 HDDEDATA data = DdeCreateDataHandle
988 (
989 DDEIdInst,
990 (LPBYTE)connection->m_sendingData,
9d860992 991 connection->m_dataSize,
5bd3a2da
VZ
992 0,
993 hsz2,
994 connection->m_dataType,
995 0
996 );
997
998 connection->m_sendingData = NULL;
999
1000 return (DDERETURN)data;
1001 }
1002
1003 break;
1004 }
1005
1006 case XTYP_ADVDATA:
1007 {
1008 wxDDEConnection *connection = DDEFindConnection(hConv);
1009
1010 if (connection)
1011 {
1012 wxString item_name = DDEStringFromAtom(hsz2);
1013
f010ad48
JS
1014 DWORD len = DdeGetData(hData, NULL, 0, 0);
1015
50c549b9 1016 void *data = connection->GetBufferAtLeast(len);
f010ad48 1017 wxASSERT_MSG(data != NULL,
9a83f860 1018 wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
f010ad48
JS
1019
1020 DdeGetData(hData, (LPBYTE)data, len, 0);
1021
5bd3a2da
VZ
1022 DdeFreeDataHandle(hData);
1023 if ( connection->OnAdvise(connection->m_topicName,
1024 item_name,
f010ad48 1025 data,
940ef730 1026 (int)len,
5bd3a2da
VZ
1027 (wxIPCFormat) wFmt) )
1028 {
1029 return (DDERETURN)(DWORD)DDE_FACK;
1030 }
1031 }
1032
1033 return (DDERETURN)DDE_FNOTPROCESSED;
1034 }
2bda0e17
KB
1035 }
1036
5bd3a2da
VZ
1037 return (DDERETURN)0;
1038}
2bda0e17 1039
5bd3a2da
VZ
1040// ----------------------------------------------------------------------------
1041// DDE strings and atoms
1042// ----------------------------------------------------------------------------
2bda0e17 1043
5bd3a2da 1044// Atom table stuff
df5168c4 1045static HSZ DDEAddAtom(const wxString& str)
5bd3a2da 1046{
df5168c4
MB
1047 HSZ atom = DDEAtomFromString(str);
1048 wxAtomTable[str] = atom;
5bd3a2da
VZ
1049 return atom;
1050}
2bda0e17 1051
df5168c4 1052static HSZ DDEGetAtom(const wxString& str)
5bd3a2da 1053{
df5168c4
MB
1054 wxAtomMap::iterator it = wxAtomTable.find(str);
1055
1056 if (it != wxAtomTable.end())
1057 return it->second;
1058
1059 return DDEAddAtom(str);
5bd3a2da 1060}
2bda0e17 1061
0ebb0e5c
DS
1062/* atom <-> strings
1063The returned handle has to be freed by the caller (using
1064(static) DDEFreeString).
1065*/
5bd3a2da
VZ
1066static HSZ DDEAtomFromString(const wxString& s)
1067{
9a83f860 1068 wxASSERT_MSG( DDEIdInst, wxT("DDE not initialized") );
5bd3a2da 1069
125afca0 1070 HSZ hsz = DdeCreateStringHandle(DDEIdInst, wxMSW_CONV_LPTSTR(s), DDE_CP);
5bd3a2da 1071 if ( !hsz )
2bda0e17 1072 {
5bd3a2da 1073 DDELogError(_("Failed to create DDE string"));
2bda0e17
KB
1074 }
1075
5bd3a2da
VZ
1076 return hsz;
1077}
2bda0e17 1078
5bd3a2da
VZ
1079static wxString DDEStringFromAtom(HSZ hsz)
1080{
1081 // all DDE strings are normally limited to 255 bytes
1082 static const size_t len = 256;
2bda0e17 1083
5bd3a2da 1084 wxString s;
de564874 1085 (void)DdeQueryString(DDEIdInst, hsz, wxStringBuffer(s, len), len, DDE_CP);
2bda0e17 1086
5bd3a2da
VZ
1087 return s;
1088}
2bda0e17 1089
0ebb0e5c
DS
1090static void DDEFreeString(HSZ hsz)
1091{
1092 // DS: Failure to free a string handle might indicate there's
1093 // some other severe error.
1094 bool ok = (::DdeFreeStringHandle(DDEIdInst, hsz) != 0);
1095 wxASSERT_MSG( ok, wxT("Failed to free DDE string handle") );
1096 wxUnusedVar(ok);
1097}
1098
5bd3a2da
VZ
1099// ----------------------------------------------------------------------------
1100// error handling
1101// ----------------------------------------------------------------------------
2bda0e17 1102
5bd3a2da
VZ
1103static void DDELogError(const wxString& s, UINT error)
1104{
1105 if ( !error )
2bda0e17 1106 {
5bd3a2da 1107 error = DdeGetLastError(DDEIdInst);
2bda0e17 1108 }
2bda0e17 1109
9a83f860 1110 wxLogError(s + wxT(": ") + DDEGetErrorMsg(error));
2bda0e17
KB
1111}
1112
5bd3a2da 1113static wxString DDEGetErrorMsg(UINT error)
2bda0e17 1114{
5bd3a2da
VZ
1115 wxString err;
1116 switch ( error )
1117 {
1118 case DMLERR_NO_ERROR:
1119 err = _("no DDE error.");
1120 break;
1121
1122 case DMLERR_ADVACKTIMEOUT:
1123 err = _("a request for a synchronous advise transaction has timed out.");
1124 break;
1125 case DMLERR_BUSY:
1126 err = _("the response to the transaction caused the DDE_FBUSY bit to be set.");
1127 break;
1128 case DMLERR_DATAACKTIMEOUT:
1129 err = _("a request for a synchronous data transaction has timed out.");
1130 break;
1131 case DMLERR_DLL_NOT_INITIALIZED:
f83e3685 1132 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
1133 break;
1134 case DMLERR_DLL_USAGE:
f83e3685 1135 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
1136 break;
1137 case DMLERR_EXECACKTIMEOUT:
1138 err = _("a request for a synchronous execute transaction has timed out.");
1139 break;
1140 case DMLERR_INVALIDPARAMETER:
1141 err = _("a parameter failed to be validated by the DDEML.");
1142 break;
1143 case DMLERR_LOW_MEMORY:
1144 err = _("a DDEML application has created a prolonged race condition.");
1145 break;
1146 case DMLERR_MEMORY_ERROR:
1147 err = _("a memory allocation failed.");
1148 break;
1149 case DMLERR_NO_CONV_ESTABLISHED:
1150 err = _("a client's attempt to establish a conversation has failed.");
1151 break;
1152 case DMLERR_NOTPROCESSED:
1153 err = _("a transaction failed.");
1154 break;
1155 case DMLERR_POKEACKTIMEOUT:
1156 err = _("a request for a synchronous poke transaction has timed out.");
1157 break;
1158 case DMLERR_POSTMSG_FAILED:
1159 err = _("an internal call to the PostMessage function has failed. ");
1160 break;
1161 case DMLERR_REENTRANCY:
1162 err = _("reentrancy problem.");
1163 break;
1164 case DMLERR_SERVER_DIED:
f83e3685 1165 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
1166 break;
1167 case DMLERR_SYS_ERROR:
1168 err = _("an internal error has occurred in the DDEML.");
1169 break;
1170 case DMLERR_UNADVACKTIMEOUT:
1171 err = _("a request to end an advise transaction has timed out.");
1172 break;
1173 case DMLERR_UNFOUND_QUEUE_ID:
f83e3685 1174 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
1175 break;
1176 default:
1177 err.Printf(_("Unknown DDE error %08x"), error);
1178 }
2bda0e17 1179
5bd3a2da 1180 return err;
2bda0e17
KB
1181}
1182
1183#endif
47d67540 1184 // wxUSE_IPC