1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/dde.cpp 
   3 // Purpose:     DDE classes 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  32     #include "wx/hashmap.h" 
  33     #include "wx/module.h" 
  38 #include "wx/buffer.h" 
  39 #include "wx/strconv.h" 
  41 #include "wx/msw/private.h" 
  46 // ---------------------------------------------------------------------------- 
  47 // macros and constants 
  48 // ---------------------------------------------------------------------------- 
  53     #define _EXPORT _export 
  57     #define DDE_CP      CP_WINUNICODE 
  59     #define DDE_CP      CP_WINANSI 
  62 #define GetHConv()       ((HCONV)m_hConv) 
  64 // default timeout for DDE operations (5sec) 
  65 #define DDE_TIMEOUT     5000 
  67 // ---------------------------------------------------------------------------- 
  69 // ---------------------------------------------------------------------------- 
  71 static wxDDEConnection 
*DDEFindConnection(HCONV hConv
); 
  72 static void DDEDeleteConnection(HCONV hConv
); 
  73 static wxDDEServer 
*DDEFindServer(const wxString
& s
); 
  75 extern "C" HDDEDATA EXPENTRY _EXPORT 
_DDECallback(WORD wType
, 
  84 // Add topic name to atom table before using in conversations 
  85 static HSZ 
DDEAddAtom(const wxString
& string
); 
  86 static HSZ 
DDEGetAtom(const wxString
& string
); 
  89 static HSZ 
DDEAtomFromString(const wxString
& s
); 
  90 static wxString 
DDEStringFromAtom(HSZ hsz
); 
  91 static void DDEFreeString(HSZ hsz
); 
  94 static wxString 
DDEGetErrorMsg(UINT error
); 
  95 static void DDELogError(const wxString
& s
, UINT error 
= DMLERR_NO_ERROR
); 
  97 // ---------------------------------------------------------------------------- 
  99 // ---------------------------------------------------------------------------- 
 101 WX_DECLARE_STRING_HASH_MAP( HSZ
, wxAtomMap 
); 
 103 static DWORD DDEIdInst 
= 0L; 
 104 static wxDDEConnection 
*DDECurrentlyConnecting 
= NULL
; 
 105 static wxAtomMap wxAtomTable
; 
 107 #include "wx/listimpl.cpp" 
 109 WX_DEFINE_LIST(wxDDEClientList
) 
 110 WX_DEFINE_LIST(wxDDEServerList
) 
 111 WX_DEFINE_LIST(wxDDEConnectionList
) 
 113 static wxDDEClientList wxDDEClientObjects
; 
 114 static wxDDEServerList wxDDEServerObjects
; 
 116 static bool DDEInitialized 
= false; 
 118 // ---------------------------------------------------------------------------- 
 120 // ---------------------------------------------------------------------------- 
 122 // A module to allow DDE cleanup without calling these functions 
 123 // from app.cpp or from the user's application. 
 125 class wxDDEModule 
: public wxModule
 
 129     bool OnInit() { return true; } 
 130     void OnExit() { wxDDECleanUp(); } 
 133     DECLARE_DYNAMIC_CLASS(wxDDEModule
) 
 136 // ---------------------------------------------------------------------------- 
 138 // ---------------------------------------------------------------------------- 
 140 IMPLEMENT_DYNAMIC_CLASS(wxDDEServer
, wxServerBase
) 
 141 IMPLEMENT_DYNAMIC_CLASS(wxDDEClient
, wxClientBase
) 
 142 IMPLEMENT_DYNAMIC_CLASS(wxDDEConnection
, wxConnectionBase
) 
 143 IMPLEMENT_DYNAMIC_CLASS(wxDDEModule
, wxModule
) 
 145 // ============================================================================ 
 147 // ============================================================================ 
 149 // ---------------------------------------------------------------------------- 
 150 // initialization and cleanup 
 151 // ---------------------------------------------------------------------------- 
 153 extern void wxDDEInitialize() 
 155     if ( !DDEInitialized 
) 
 157         // Should insert filter flags 
 158         PFNCALLBACK callback 
= (PFNCALLBACK
) 
 159             MakeProcInstance((FARPROC
)_DDECallback
, wxGetInstance()); 
 160         UINT rc 
= DdeInitialize(&DDEIdInst
, callback
, APPCLASS_STANDARD
, 0L); 
 161         if ( rc 
!= DMLERR_NO_ERROR 
) 
 163             DDELogError(wxT("Failed to initialize DDE"), rc
); 
 167             DDEInitialized 
= true; 
 174     // deleting them later won't work as DDE won't be initialized any more 
 175     wxASSERT_MSG( wxDDEServerObjects
.empty() && 
 176                     wxDDEClientObjects
.empty(), 
 177                     wxT("all DDE objects should be deleted by now") ); 
 181     if ( DDEIdInst 
!= 0 ) 
 183         DdeUninitialize(DDEIdInst
); 
 188 // ---------------------------------------------------------------------------- 
 189 // functions working with the global connection list(s) 
 190 // ---------------------------------------------------------------------------- 
 192 // Global find connection 
 193 static wxDDEConnection 
*DDEFindConnection(HCONV hConv
) 
 195     wxDDEServerList::compatibility_iterator serverNode 
= wxDDEServerObjects
.GetFirst(); 
 196     wxDDEConnection 
*found 
= NULL
; 
 197     while (serverNode 
&& !found
) 
 199         wxDDEServer 
*object 
= serverNode
->GetData(); 
 200         found 
= object
->FindConnection((WXHCONV
) hConv
); 
 201         serverNode 
= serverNode
->GetNext(); 
 209     wxDDEClientList::compatibility_iterator clientNode 
= wxDDEClientObjects
.GetFirst(); 
 210     while (clientNode 
&& !found
) 
 212         wxDDEClient 
*object 
= clientNode
->GetData(); 
 213         found 
= object
->FindConnection((WXHCONV
) hConv
); 
 214         clientNode 
= clientNode
->GetNext(); 
 219 // Global delete connection 
 220 static void DDEDeleteConnection(HCONV hConv
) 
 222     wxDDEServerList::compatibility_iterator serverNode 
= wxDDEServerObjects
.GetFirst(); 
 224     while (serverNode 
&& !found
) 
 226         wxDDEServer 
*object 
= serverNode
->GetData(); 
 227         found 
= object
->DeleteConnection((WXHCONV
) hConv
); 
 228         serverNode 
= serverNode
->GetNext(); 
 235     wxDDEClientList::compatibility_iterator clientNode 
= wxDDEClientObjects
.GetFirst(); 
 236     while (clientNode 
&& !found
) 
 238         wxDDEClient 
*object 
= clientNode
->GetData(); 
 239         found 
= object
->DeleteConnection((WXHCONV
) hConv
); 
 240         clientNode 
= clientNode
->GetNext(); 
 244 // Find a server from a service name 
 245 static wxDDEServer 
*DDEFindServer(const wxString
& s
) 
 247     wxDDEServerList::compatibility_iterator node 
= wxDDEServerObjects
.GetFirst(); 
 248     wxDDEServer 
*found 
= NULL
; 
 249     while (node 
&& !found
) 
 251         wxDDEServer 
*object 
= node
->GetData(); 
 253         if (object
->GetServiceName() == s
) 
 259             node 
= node
->GetNext(); 
 266 // ---------------------------------------------------------------------------- 
 268 // ---------------------------------------------------------------------------- 
 270 wxDDEServer::wxDDEServer() 
 274     wxDDEServerObjects
.Append(this); 
 277 bool wxDDEServer::Create(const wxString
& server
) 
 279     m_serviceName 
= server
; 
 281     HSZ hsz 
= DDEAtomFromString(server
); 
 289     bool success 
= (DdeNameService(DDEIdInst
, hsz
, (HSZ
) NULL
, DNS_REGISTER
) 
 294         DDELogError(wxString::Format(_("Failed to register DDE server '%s'"), 
 303 wxDDEServer::~wxDDEServer() 
 305     if ( !m_serviceName
.empty() ) 
 307         HSZ hsz 
= DDEAtomFromString(m_serviceName
); 
 311             if ( !DdeNameService(DDEIdInst
, hsz
, 
 312                 (HSZ
) NULL
, DNS_UNREGISTER
) ) 
 314                 DDELogError(wxString::Format( 
 315                     _("Failed to unregister DDE server '%s'"), 
 316                     m_serviceName
.c_str())); 
 323     wxDDEServerObjects
.DeleteObject(this); 
 325     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 328         wxDDEConnection 
*connection 
= node
->GetData(); 
 329         wxDDEConnectionList::compatibility_iterator next 
= node
->GetNext(); 
 330         connection
->OnDisconnect(); // May delete the node implicitly 
 334     // If any left after this, delete them 
 335     node 
= m_connections
.GetFirst(); 
 338         wxDDEConnection 
*connection 
= node
->GetData(); 
 339         wxDDEConnectionList::compatibility_iterator next 
= node
->GetNext(); 
 345 wxConnectionBase 
*wxDDEServer::OnAcceptConnection(const wxString
& /* topic */) 
 347     return new wxDDEConnection
; 
 350 wxDDEConnection 
*wxDDEServer::FindConnection(WXHCONV conv
) 
 352     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 353     wxDDEConnection 
*found 
= NULL
; 
 354     while (node 
&& !found
) 
 356         wxDDEConnection 
*connection 
= node
->GetData(); 
 357         if (connection
->m_hConv 
== conv
) 
 359         else node 
= node
->GetNext(); 
 364 // Only delete the entry in the map, not the actual connection 
 365 bool wxDDEServer::DeleteConnection(WXHCONV conv
) 
 367     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 370         wxDDEConnection 
*connection 
= node
->GetData(); 
 371         if (connection
->m_hConv 
== conv
) 
 373             m_connections
.Erase(node
); 
 378             node 
= node
->GetNext(); 
 384 // ---------------------------------------------------------------------------- 
 386 // ---------------------------------------------------------------------------- 
 388 wxDDEClient::wxDDEClient() 
 392     wxDDEClientObjects
.Append(this); 
 395 wxDDEClient::~wxDDEClient() 
 397     wxDDEClientObjects
.DeleteObject(this); 
 398     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 401         wxDDEConnection 
*connection 
= node
->GetData(); 
 402         delete connection
;  // Deletes the node implicitly (see ~wxDDEConnection) 
 403         node 
= m_connections
.GetFirst(); 
 407 bool wxDDEClient::ValidHost(const wxString
& /* host */) 
 412 wxConnectionBase 
*wxDDEClient::MakeConnection(const wxString
& WXUNUSED(host
), 
 413                                               const wxString
& server
, 
 414                                               const wxString
& topic
) 
 416     HSZ hszServer 
= DDEAtomFromString(server
); 
 424     HSZ hszTopic 
= DDEAtomFromString(topic
); 
 428         DDEFreeString(hszServer
); 
 433     HCONV hConv 
= ::DdeConnect(DDEIdInst
, hszServer
, hszTopic
, 
 434         (PCONVCONTEXT
) NULL
); 
 436     DDEFreeString(hszServer
); 
 437     DDEFreeString(hszTopic
); 
 442         DDELogError( wxString::Format( 
 443             _("Failed to create connection to server '%s' on topic '%s'"), 
 444             server
.c_str(), topic
.c_str()) ); 
 448         wxDDEConnection 
*connection 
= (wxDDEConnection
*) OnMakeConnection(); 
 451             connection
->m_hConv 
= (WXHCONV
) hConv
; 
 452             connection
->m_topicName 
= topic
; 
 453             connection
->m_client 
= this; 
 454             m_connections
.Append(connection
); 
 462 wxConnectionBase 
*wxDDEClient::OnMakeConnection() 
 464     return new wxDDEConnection
; 
 467 wxDDEConnection 
*wxDDEClient::FindConnection(WXHCONV conv
) 
 469     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 470     wxDDEConnection 
*found 
= NULL
; 
 471     while (node 
&& !found
) 
 473         wxDDEConnection 
*connection 
= node
->GetData(); 
 474         if (connection
->m_hConv 
== conv
) 
 476         else node 
= node
->GetNext(); 
 481 // Only delete the entry in the map, not the actual connection 
 482 bool wxDDEClient::DeleteConnection(WXHCONV conv
) 
 484     wxDDEConnectionList::compatibility_iterator node 
= m_connections
.GetFirst(); 
 487         wxDDEConnection 
*connection 
= node
->GetData(); 
 488         if (connection
->m_hConv 
== conv
) 
 490             m_connections
.Erase(node
); 
 493         else node 
= node
->GetNext(); 
 498 // ---------------------------------------------------------------------------- 
 500 // ---------------------------------------------------------------------------- 
 502 wxDDEConnection::wxDDEConnection(void *buffer
, size_t size
) 
 503      : wxConnectionBase(buffer
, size
) 
 509     m_sendingData 
= NULL
; 
 512 wxDDEConnection::wxDDEConnection() 
 516     m_sendingData 
= NULL
; 
 521 wxDDEConnection::~wxDDEConnection() 
 525         m_server
->GetConnections().DeleteObject(this); 
 527         m_client
->GetConnections().DeleteObject(this); 
 530 // Calls that CLIENT can make 
 531 bool wxDDEConnection::Disconnect() 
 533     if ( !GetConnected() ) 
 536     DDEDeleteConnection(GetHConv()); 
 538     bool ok 
= DdeDisconnect(GetHConv()) != 0; 
 541         DDELogError(wxT("Failed to disconnect from DDE server gracefully")); 
 544     SetConnected( false );  // so we don't try and disconnect again 
 550 wxDDEConnection::DoExecute(const void *data
, size_t size
, wxIPCFormat format
) 
 552     wxCHECK_MSG( format 
== wxIPC_TEXT 
|| 
 553                  format 
== wxIPC_UTF8TEXT 
|| 
 554                  format 
== wxIPC_UNICODETEXT
, 
 556                  wxT("wxDDEServer::Execute() supports only text data") ); 
 558     wxMemoryBuffer buffer
; 
 559     LPBYTE realData 
= NULL
; 
 561     wxMBConv 
*conv 
= NULL
; 
 563     // Windows only supports either ANSI or UTF-16 format depending on the 
 564     // build, so we need to convert the data if it doesn't use it already 
 566     if ( format 
== wxIPC_TEXT 
) 
 570     else if ( format 
== wxIPC_UTF8TEXT 
) 
 574     else // no conversion necessary for wxIPC_UNICODETEXT 
 576         realData 
= (LPBYTE
)data
; 
 582         const char * const text 
= (const char *)data
; 
 583         const size_t len 
= size
/sizeof(char); 
 585         realSize 
= conv
->ToWChar(NULL
, 0, text
, len
); 
 586         if ( realSize 
== wxCONV_FAILED 
) 
 589         realData 
= (LPBYTE
)buffer
.GetWriteBuf(realSize
*sizeof(wchar_t)); 
 593         realSize 
= conv
->ToWChar((wchar_t *)realData
, realSize
, text
, len
); 
 594         if ( realSize 
== wxCONV_FAILED 
) 
 597         // We need to pass the size of the buffer to DdeClientTransaction() and 
 598         // not the length of the string. 
 599         realSize 
*= sizeof(wchar_t); 
 601 #else // !wxUSE_UNICODE 
 602     if ( format 
== wxIPC_UNICODETEXT 
) 
 606     else if ( format 
== wxIPC_UTF8TEXT 
) 
 608         // we could implement this in theory but it's not obvious how to pass 
 609         // the format information and, basically, why bother -- just use 
 611         wxFAIL_MSG( wxT("UTF-8 text not supported in ANSI build") ); 
 615     else // don't convert wxIPC_TEXT 
 617         realData 
= (LPBYTE
)data
; 
 623         const wchar_t * const wtext 
= (const wchar_t *)data
; 
 624         const size_t len 
= size
/sizeof(wchar_t); 
 626         realSize 
= conv
->FromWChar(NULL
, 0, wtext
, len
); 
 627         if ( realSize 
== wxCONV_FAILED 
) 
 630         realData 
= (LPBYTE
)buffer
.GetWriteBuf(realSize
*sizeof(char)); 
 634         realSize 
= conv
->FromWChar((char*)realData
, realSize
, wtext
, len
); 
 635         if ( realSize 
== wxCONV_FAILED 
) 
 638 #endif // wxUSE_UNICODE/!wxUSE_UNICODE 
 641     bool ok 
= DdeClientTransaction(realData
, 
 645                                    // MSDN: if the transaction specified by 
 646                                    // the wType parameter does not pass data 
 647                                    // or is XTYP_EXECUTE, wFmt should be zero. 
 655         DDELogError(wxT("DDE execute request failed")); 
 661 const void *wxDDEConnection::Request(const wxString
& item
, size_t *size
, wxIPCFormat format
) 
 665     HSZ atom 
= DDEGetAtom(item
); 
 667     HDDEDATA returned_data 
= DdeClientTransaction(NULL
, 0, 
 673     if ( !returned_data 
) 
 675         DDELogError(wxT("DDE data request failed")); 
 680     DWORD len 
= DdeGetData(returned_data
, NULL
, 0, 0); 
 682     void *data 
= GetBufferAtLeast(len
); 
 683     wxASSERT_MSG(data 
!= NULL
, 
 684                  wxT("Buffer too small in wxDDEConnection::Request") ); 
 685     (void) DdeGetData(returned_data
, (LPBYTE
)data
, len
, 0); 
 687     (void) DdeFreeDataHandle(returned_data
); 
 695 bool wxDDEConnection::DoPoke(const wxString
& item
, const void *data
, size_t size
, wxIPCFormat format
) 
 699     HSZ item_atom 
= DDEGetAtom(item
); 
 700     bool ok 
= DdeClientTransaction((LPBYTE
)data
, 
 709         DDELogError(_("DDE poke request failed")); 
 715 bool wxDDEConnection::StartAdvise(const wxString
& item
) 
 718     HSZ atom 
= DDEGetAtom(item
); 
 720     bool ok 
= DdeClientTransaction(NULL
, 0, 
 728         DDELogError(_("Failed to establish an advise loop with DDE server")); 
 734 bool wxDDEConnection::StopAdvise(const wxString
& item
) 
 737     HSZ atom 
= DDEGetAtom(item
); 
 739     bool ok 
= DdeClientTransaction(NULL
, 0, 
 747         DDELogError(_("Failed to terminate the advise loop with DDE server")); 
 753 // Calls that SERVER can make 
 754 bool wxDDEConnection::DoAdvise(const wxString
& item
, 
 759     HSZ item_atom 
= DDEGetAtom(item
); 
 760     HSZ topic_atom 
= DDEGetAtom(m_topicName
); 
 761     m_sendingData 
= data
;  // mrf: potential for scope problems here? 
 763     // wxIPC_PRIVATE does not succeed, so use text instead 
 764     m_dataType 
= format 
== wxIPC_PRIVATE 
? wxIPC_TEXT 
: format
; 
 766     bool ok 
= DdePostAdvise(DDEIdInst
, topic_atom
, item_atom
) != 0; 
 769         DDELogError(_("Failed to send DDE advise notification")); 
 775 // ---------------------------------------------------------------------------- 
 777 // ---------------------------------------------------------------------------- 
 779 #define DDERETURN HDDEDATA 
 781 HDDEDATA EXPENTRY _EXPORT
 
 782 _DDECallback(WORD wType
, 
 788              DWORD 
WXUNUSED(lData1
), 
 789              DWORD 
WXUNUSED(lData2
)) 
 795                 wxString topic 
= DDEStringFromAtom(hsz1
), 
 796                          srv 
= DDEStringFromAtom(hsz2
); 
 797                 wxDDEServer 
*server 
= DDEFindServer(srv
); 
 800                     wxDDEConnection 
*connection 
= 
 801                         (wxDDEConnection
*) server
->OnAcceptConnection(topic
); 
 804                         connection
->m_server 
= server
; 
 805                         server
->GetConnections().Append(connection
); 
 806                         connection
->m_hConv 
= 0; 
 807                         connection
->m_topicName 
= topic
; 
 808                         DDECurrentlyConnecting 
= connection
; 
 809                         return (DDERETURN
)(DWORD
)true; 
 815         case XTYP_CONNECT_CONFIRM
: 
 817                 if (DDECurrentlyConnecting
) 
 819                     DDECurrentlyConnecting
->m_hConv 
= (WXHCONV
) hConv
; 
 820                     DDECurrentlyConnecting 
= NULL
; 
 821                     return (DDERETURN
)(DWORD
)true; 
 826         case XTYP_DISCONNECT
: 
 828                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 831                     connection
->SetConnected( false ); 
 832                     if (connection
->OnDisconnect()) 
 834                         DDEDeleteConnection(hConv
);  // Delete mapping: hConv => connection 
 835                         return (DDERETURN
)(DWORD
)true; 
 843                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 847                     DWORD len 
= DdeGetData(hData
, NULL
, 0, 0); 
 849                     void *data 
= connection
->GetBufferAtLeast(len
); 
 850                     wxASSERT_MSG(data 
!= NULL
, 
 851                                  wxT("Buffer too small in _DDECallback (XTYP_EXECUTE)") ); 
 853                     DdeGetData(hData
, (LPBYTE
)data
, len
, 0); 
 855                     DdeFreeDataHandle(hData
); 
 857                     // XTYP_EXECUTE can be used for text only and the text is 
 858                     // always in ANSI format for ANSI build and Unicode format 
 861                         wFmt 
= wxIPC_UNICODETEXT
; 
 866                     if ( connection
->OnExecute(connection
->m_topicName
, 
 871                         return (DDERETURN
)(DWORD
)DDE_FACK
; 
 875                 return (DDERETURN
)DDE_FNOTPROCESSED
; 
 880                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 884                     wxString item_name 
= DDEStringFromAtom(hsz2
); 
 886                     size_t user_size 
= wxNO_LEN
; 
 887                     const void *data 
= connection
->OnRequest(connection
->m_topicName
, 
 893                       if (user_size 
== wxNO_LEN
) 
 898                             user_size 
= strlen((const char*)data
) + 1;  // includes final NUL 
 900                           case wxIPC_UNICODETEXT
: 
 901                             user_size 
= (wcslen((const wchar_t*)data
) + 1) * sizeof(wchar_t);  // includes final NUL 
 907                         HDDEDATA handle 
= DdeCreateDataHandle(DDEIdInst
, 
 914                         return (DDERETURN
)handle
; 
 922                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 926                     wxString item_name 
= DDEStringFromAtom(hsz2
); 
 928                     DWORD len 
= DdeGetData(hData
, NULL
, 0, 0); 
 930                     void *data 
= connection
->GetBufferAtLeast(len
); 
 931                     wxASSERT_MSG(data 
!= NULL
, 
 932                                  wxT("Buffer too small in _DDECallback (XTYP_POKE)") ); 
 934                     DdeGetData(hData
, (LPBYTE
)data
, len
, 0); 
 936                     DdeFreeDataHandle(hData
); 
 938                     connection
->OnPoke(connection
->m_topicName
, 
 944                     return (DDERETURN
)DDE_FACK
; 
 948                     return (DDERETURN
)DDE_FNOTPROCESSED
; 
 954                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 958                     wxString item_name 
= DDEStringFromAtom(hsz2
); 
 960                     return (DDERETURN
)connection
-> 
 961                                 OnStartAdvise(connection
->m_topicName
, item_name
); 
 969                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 973                     wxString item_name 
= DDEStringFromAtom(hsz2
); 
 975                     return (DDERETURN
)connection
-> 
 976                         OnStopAdvise(connection
->m_topicName
, item_name
); 
 984                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
 986                 if (connection 
&& connection
->m_sendingData
) 
 988                     HDDEDATA data 
= DdeCreateDataHandle
 
 991                                         (LPBYTE
)connection
->m_sendingData
, 
 992                                         connection
->m_dataSize
, 
 995                                         connection
->m_dataType
, 
 999                     connection
->m_sendingData 
= NULL
; 
1001                     return (DDERETURN
)data
; 
1009                 wxDDEConnection 
*connection 
= DDEFindConnection(hConv
); 
1013                     wxString item_name 
= DDEStringFromAtom(hsz2
); 
1015                     DWORD len 
= DdeGetData(hData
, NULL
, 0, 0); 
1017                     void *data 
= connection
->GetBufferAtLeast(len
); 
1018                     wxASSERT_MSG(data 
!= NULL
, 
1019                                  wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") ); 
1021                     DdeGetData(hData
, (LPBYTE
)data
, len
, 0); 
1023                     DdeFreeDataHandle(hData
); 
1024                     if ( connection
->OnAdvise(connection
->m_topicName
, 
1028                                               (wxIPCFormat
) wFmt
) ) 
1030                         return (DDERETURN
)(DWORD
)DDE_FACK
; 
1034                 return (DDERETURN
)DDE_FNOTPROCESSED
; 
1038     return (DDERETURN
)0; 
1041 // ---------------------------------------------------------------------------- 
1042 // DDE strings and atoms 
1043 // ---------------------------------------------------------------------------- 
1046 static HSZ 
DDEAddAtom(const wxString
& str
) 
1048     HSZ atom 
= DDEAtomFromString(str
); 
1049     wxAtomTable
[str
] = atom
; 
1053 static HSZ 
DDEGetAtom(const wxString
& str
) 
1055     wxAtomMap::iterator it 
= wxAtomTable
.find(str
); 
1057     if (it 
!= wxAtomTable
.end()) 
1060     return DDEAddAtom(str
); 
1064 The returned handle has to be freed by the caller (using 
1065 (static) DDEFreeString). 
1067 static HSZ 
DDEAtomFromString(const wxString
& s
) 
1069     wxASSERT_MSG( DDEIdInst
, wxT("DDE not initialized") ); 
1071     HSZ hsz 
= DdeCreateStringHandle(DDEIdInst
, const_cast<wxChar
*>(static_cast<const wxChar
*>(s
.t_str())), DDE_CP
); 
1074         DDELogError(_("Failed to create DDE string")); 
1080 static wxString 
DDEStringFromAtom(HSZ hsz
) 
1082     // all DDE strings are normally limited to 255 bytes 
1083     static const size_t len 
= 256; 
1086     (void)DdeQueryString(DDEIdInst
, hsz
, wxStringBuffer(s
, len
), len
, DDE_CP
); 
1091 static void DDEFreeString(HSZ hsz
) 
1093     // DS: Failure to free a string handle might indicate there's 
1094     // some other severe error. 
1095     bool ok 
= (::DdeFreeStringHandle(DDEIdInst
, hsz
) != 0); 
1096     wxASSERT_MSG( ok
, wxT("Failed to free DDE string handle") ); 
1100 // ---------------------------------------------------------------------------- 
1102 // ---------------------------------------------------------------------------- 
1104 static void DDELogError(const wxString
& s
, UINT error
) 
1108         error 
= DdeGetLastError(DDEIdInst
); 
1111     wxLogError(s 
+ wxT(": ") + DDEGetErrorMsg(error
)); 
1114 static wxString 
DDEGetErrorMsg(UINT error
) 
1119         case DMLERR_NO_ERROR
: 
1120             err 
= _("no DDE error."); 
1123         case DMLERR_ADVACKTIMEOUT
: 
1124             err 
= _("a request for a synchronous advise transaction has timed out."); 
1127             err 
= _("the response to the transaction caused the DDE_FBUSY bit to be set."); 
1129         case DMLERR_DATAACKTIMEOUT
: 
1130             err 
= _("a request for a synchronous data transaction has timed out."); 
1132         case DMLERR_DLL_NOT_INITIALIZED
: 
1133             err 
= _("a DDEML function was called without first calling the DdeInitialize function,\nor an invalid instance identifier\nwas passed to a DDEML function."); 
1135         case DMLERR_DLL_USAGE
: 
1136             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."); 
1138         case DMLERR_EXECACKTIMEOUT
: 
1139             err 
= _("a request for a synchronous execute transaction has timed out."); 
1141         case DMLERR_INVALIDPARAMETER
: 
1142             err 
= _("a parameter failed to be validated by the DDEML."); 
1144         case DMLERR_LOW_MEMORY
: 
1145             err 
= _("a DDEML application has created a prolonged race condition."); 
1147         case DMLERR_MEMORY_ERROR
: 
1148             err 
= _("a memory allocation failed."); 
1150         case DMLERR_NO_CONV_ESTABLISHED
: 
1151             err 
= _("a client's attempt to establish a conversation has failed."); 
1153         case DMLERR_NOTPROCESSED
: 
1154             err 
= _("a transaction failed."); 
1156         case DMLERR_POKEACKTIMEOUT
: 
1157             err 
= _("a request for a synchronous poke transaction has timed out."); 
1159         case DMLERR_POSTMSG_FAILED
: 
1160             err 
= _("an internal call to the PostMessage function has failed. "); 
1162         case DMLERR_REENTRANCY
: 
1163             err 
= _("reentrancy problem."); 
1165         case DMLERR_SERVER_DIED
: 
1166             err 
= _("a server-side transaction was attempted on a conversation\nthat was terminated by the client, or the server\nterminated before completing a transaction."); 
1168         case DMLERR_SYS_ERROR
: 
1169             err 
= _("an internal error has occurred in the DDEML."); 
1171         case DMLERR_UNADVACKTIMEOUT
: 
1172             err 
= _("a request to end an advise transaction has timed out."); 
1174         case DMLERR_UNFOUND_QUEUE_ID
: 
1175             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."); 
1178             err
.Printf(_("Unknown DDE error %08x"), error
);