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