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_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(_T("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 _T("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
->SetConnected(false);
331 connection
->OnDisconnect(); // May delete the node implicitly
335 // If any left after this, delete them
336 node
= m_connections
.GetFirst();
339 wxDDEConnection
*connection
= node
->GetData();
340 wxDDEConnectionList::compatibility_iterator next
= node
->GetNext();
346 wxConnectionBase
*wxDDEServer::OnAcceptConnection(const wxString
& /* topic */)
348 return new wxDDEConnection
;
351 wxDDEConnection
*wxDDEServer::FindConnection(WXHCONV conv
)
353 wxDDEConnectionList::compatibility_iterator node
= m_connections
.GetFirst();
354 wxDDEConnection
*found
= NULL
;
355 while (node
&& !found
)
357 wxDDEConnection
*connection
= node
->GetData();
358 if (connection
->m_hConv
== conv
)
360 else node
= node
->GetNext();
365 // Only delete the entry in the map, not the actual connection
366 bool wxDDEServer::DeleteConnection(WXHCONV conv
)
368 wxDDEConnectionList::compatibility_iterator node
= m_connections
.GetFirst();
371 wxDDEConnection
*connection
= node
->GetData();
372 if (connection
->m_hConv
== conv
)
374 m_connections
.Erase(node
);
379 node
= node
->GetNext();
385 // ----------------------------------------------------------------------------
387 // ----------------------------------------------------------------------------
389 wxDDEClient::wxDDEClient()
393 wxDDEClientObjects
.Append(this);
396 wxDDEClient::~wxDDEClient()
398 wxDDEClientObjects
.DeleteObject(this);
399 wxDDEConnectionList::compatibility_iterator node
= m_connections
.GetFirst();
402 wxDDEConnection
*connection
= node
->GetData();
403 delete connection
; // Deletes the node implicitly (see ~wxDDEConnection)
404 node
= m_connections
.GetFirst();
408 bool wxDDEClient::ValidHost(const wxString
& /* host */)
413 wxConnectionBase
*wxDDEClient::MakeConnection(const wxString
& WXUNUSED(host
),
414 const wxString
& server
,
415 const wxString
& topic
)
417 HSZ hszServer
= DDEAtomFromString(server
);
421 return (wxConnectionBase
*) NULL
;
425 HSZ hszTopic
= DDEAtomFromString(topic
);
429 DDEFreeString(hszServer
);
430 return (wxConnectionBase
*) NULL
;
434 HCONV hConv
= ::DdeConnect(DDEIdInst
, hszServer
, hszTopic
,
435 (PCONVCONTEXT
) NULL
);
437 DDEFreeString(hszServer
);
438 DDEFreeString(hszTopic
);
443 DDELogError( wxString::Format(
444 _("Failed to create connection to server '%s' on topic '%s'"),
445 server
.c_str(), topic
.c_str()) );
449 wxDDEConnection
*connection
= (wxDDEConnection
*) OnMakeConnection();
452 connection
->m_hConv
= (WXHCONV
) hConv
;
453 connection
->m_topicName
= topic
;
454 connection
->m_client
= this;
455 m_connections
.Append(connection
);
460 return (wxConnectionBase
*) NULL
;
463 wxConnectionBase
*wxDDEClient::OnMakeConnection()
465 return new wxDDEConnection
;
468 wxDDEConnection
*wxDDEClient::FindConnection(WXHCONV conv
)
470 wxDDEConnectionList::compatibility_iterator node
= m_connections
.GetFirst();
471 wxDDEConnection
*found
= NULL
;
472 while (node
&& !found
)
474 wxDDEConnection
*connection
= node
->GetData();
475 if (connection
->m_hConv
== conv
)
477 else node
= node
->GetNext();
482 // Only delete the entry in the map, not the actual connection
483 bool wxDDEClient::DeleteConnection(WXHCONV conv
)
485 wxDDEConnectionList::compatibility_iterator node
= m_connections
.GetFirst();
488 wxDDEConnection
*connection
= node
->GetData();
489 if (connection
->m_hConv
== conv
)
491 m_connections
.Erase(node
);
494 else node
= node
->GetNext();
499 // ----------------------------------------------------------------------------
501 // ----------------------------------------------------------------------------
503 wxDDEConnection::wxDDEConnection(void *buffer
, size_t size
)
504 : wxConnectionBase(buffer
, size
)
510 m_sendingData
= NULL
;
513 wxDDEConnection::wxDDEConnection()
517 m_sendingData
= NULL
;
522 wxDDEConnection::~wxDDEConnection()
526 m_server
->GetConnections().DeleteObject(this);
528 m_client
->GetConnections().DeleteObject(this);
531 // Calls that CLIENT can make
532 bool wxDDEConnection::Disconnect()
534 if ( !GetConnected() )
537 DDEDeleteConnection(GetHConv());
539 bool ok
= DdeDisconnect(GetHConv()) != 0;
542 DDELogError(_T("Failed to disconnect from DDE server gracefully"));
545 SetConnected( false ); // so we don't try and disconnect again
551 wxDDEConnection::DoExecute(const void *data
, size_t size
, wxIPCFormat format
)
553 wxCHECK_MSG( format
== wxIPC_TEXT
||
554 format
== wxIPC_UTF8TEXT
||
555 format
== wxIPC_UNICODETEXT
,
557 _T("wxDDEServer::Execute() supports only text data") );
559 wxMemoryBuffer buffer
;
560 LPBYTE realData
wxDUMMY_INITIALIZE(NULL
);
561 size_t realSize
wxDUMMY_INITIALIZE(0);
562 wxMBConv
*conv
= NULL
;
564 // Windows only supports either ANSI or UTF-16 format depending on the
565 // build, so we need to convert the data if it doesn't use it already
567 if ( format
== wxIPC_TEXT
)
571 else if ( format
== wxIPC_UTF8TEXT
)
575 else // no conversion necessary for wxIPC_UNICODETEXT
577 realData
= (LPBYTE
)data
;
583 const char * const text
= (const char *)data
;
584 const size_t len
= size
/sizeof(char);
586 realSize
= conv
->ToWChar(NULL
, 0, text
, len
);
587 if ( realSize
== wxCONV_FAILED
)
590 realData
= (LPBYTE
)buffer
.GetWriteBuf(realSize
*sizeof(wchar_t));
594 realSize
= conv
->ToWChar((wchar_t *)realData
, realSize
, text
, len
);
595 if ( realSize
== wxCONV_FAILED
)
598 #else // !wxUSE_UNICODE
599 if ( format
== wxIPC_UNICODETEXT
)
603 else if ( format
== wxIPC_UTF8TEXT
)
605 // we could implement this in theory but it's not obvious how to pass
606 // the format information and, basically, why bother -- just use
608 wxFAIL_MSG( _T("UTF-8 text not supported in ANSI build") );
612 else // don't convert wxIPC_TEXT
614 realData
= (LPBYTE
)data
;
620 const wchar_t * const wtext
= (const wchar_t *)data
;
621 const size_t len
= size
/sizeof(wchar_t);
623 realSize
= conv
->FromWChar(NULL
, 0, wtext
, len
);
624 if ( realSize
== wxCONV_FAILED
)
627 realData
= (LPBYTE
)buffer
.GetWriteBuf(realSize
*sizeof(char));
631 realSize
= conv
->FromWChar((char*)realData
, realSize
, wtext
, len
);
632 if ( realSize
== wxCONV_FAILED
)
635 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
638 bool ok
= DdeClientTransaction(realData
,
642 // MSDN: if the transaction specified by
643 // the wType parameter does not pass data
644 // or is XTYP_EXECUTE, wFmt should be zero.
652 DDELogError(_T("DDE execute request failed"));
658 const void *wxDDEConnection::Request(const wxString
& item
, size_t *size
, wxIPCFormat format
)
662 HSZ atom
= DDEGetAtom(item
);
664 HDDEDATA returned_data
= DdeClientTransaction(NULL
, 0,
670 if ( !returned_data
)
672 DDELogError(_T("DDE data request failed"));
677 DWORD len
= DdeGetData(returned_data
, NULL
, 0, 0);
679 void *data
= GetBufferAtLeast(len
);
680 wxASSERT_MSG(data
!= NULL
,
681 _T("Buffer too small in wxDDEConnection::Request") );
682 (void) DdeGetData(returned_data
, (LPBYTE
)data
, len
, 0);
684 (void) DdeFreeDataHandle(returned_data
);
692 bool wxDDEConnection::DoPoke(const wxString
& item
, const void *data
, size_t size
, wxIPCFormat format
)
696 HSZ item_atom
= DDEGetAtom(item
);
697 bool ok
= DdeClientTransaction((LPBYTE
)data
,
706 DDELogError(_("DDE poke request failed"));
712 bool wxDDEConnection::StartAdvise(const wxString
& item
)
715 HSZ atom
= DDEGetAtom(item
);
717 bool ok
= DdeClientTransaction(NULL
, 0,
725 DDELogError(_("Failed to establish an advise loop with DDE server"));
731 bool wxDDEConnection::StopAdvise(const wxString
& item
)
734 HSZ atom
= DDEGetAtom(item
);
736 bool ok
= DdeClientTransaction(NULL
, 0,
744 DDELogError(_("Failed to terminate the advise loop with DDE server"));
750 // Calls that SERVER can make
751 bool wxDDEConnection::DoAdvise(const wxString
& item
,
756 HSZ item_atom
= DDEGetAtom(item
);
757 HSZ topic_atom
= DDEGetAtom(m_topicName
);
758 m_sendingData
= data
; // mrf: potential for scope problems here?
760 // wxIPC_PRIVATE does not succeed, so use text instead
761 m_dataType
= format
== wxIPC_PRIVATE
? wxIPC_TEXT
: format
;
763 bool ok
= DdePostAdvise(DDEIdInst
, topic_atom
, item_atom
) != 0;
766 DDELogError(_("Failed to send DDE advise notification"));
772 // ----------------------------------------------------------------------------
774 // ----------------------------------------------------------------------------
776 #define DDERETURN HDDEDATA
778 HDDEDATA EXPENTRY _EXPORT
779 _DDECallback(WORD wType
,
785 DWORD
WXUNUSED(lData1
),
786 DWORD
WXUNUSED(lData2
))
792 wxString topic
= DDEStringFromAtom(hsz1
),
793 srv
= DDEStringFromAtom(hsz2
);
794 wxDDEServer
*server
= DDEFindServer(srv
);
797 wxDDEConnection
*connection
=
798 (wxDDEConnection
*) server
->OnAcceptConnection(topic
);
801 connection
->m_server
= server
;
802 server
->GetConnections().Append(connection
);
803 connection
->m_hConv
= 0;
804 connection
->m_topicName
= topic
;
805 DDECurrentlyConnecting
= connection
;
806 return (DDERETURN
)(DWORD
)true;
812 case XTYP_CONNECT_CONFIRM
:
814 if (DDECurrentlyConnecting
)
816 DDECurrentlyConnecting
->m_hConv
= (WXHCONV
) hConv
;
817 DDECurrentlyConnecting
= NULL
;
818 return (DDERETURN
)(DWORD
)true;
823 case XTYP_DISCONNECT
:
825 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
828 connection
->SetConnected( false );
829 if (connection
->OnDisconnect())
831 DDEDeleteConnection(hConv
); // Delete mapping: hConv => connection
832 return (DDERETURN
)(DWORD
)true;
840 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
844 DWORD len
= DdeGetData(hData
, NULL
, 0, 0);
846 void *data
= connection
->GetBufferAtLeast(len
);
847 wxASSERT_MSG(data
!= NULL
,
848 _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") );
850 DdeGetData(hData
, (LPBYTE
)data
, len
, 0);
852 DdeFreeDataHandle(hData
);
854 // XTYP_EXECUTE can be used for text only and the text is
855 // always in ANSI format for ANSI build and Unicode format
858 wFmt
= wxIPC_UNICODETEXT
;
863 if ( connection
->OnExecute(connection
->m_topicName
,
868 return (DDERETURN
)(DWORD
)DDE_FACK
;
872 return (DDERETURN
)DDE_FNOTPROCESSED
;
877 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
881 wxString item_name
= DDEStringFromAtom(hsz2
);
883 size_t user_size
= wxNO_LEN
;
884 const void *data
= connection
->OnRequest(connection
->m_topicName
,
890 if (user_size
== wxNO_LEN
)
895 user_size
= strlen((const char*)data
) + 1; // includes final NUL
897 case wxIPC_UNICODETEXT
:
898 user_size
= (wcslen((const wchar_t*)data
) + 1) * sizeof(wchar_t); // includes final NUL
904 HDDEDATA handle
= DdeCreateDataHandle(DDEIdInst
,
911 return (DDERETURN
)handle
;
919 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
923 wxString item_name
= DDEStringFromAtom(hsz2
);
925 DWORD len
= DdeGetData(hData
, NULL
, 0, 0);
927 void *data
= connection
->GetBufferAtLeast(len
);
928 wxASSERT_MSG(data
!= NULL
,
929 _T("Buffer too small in _DDECallback (XTYP_POKE)") );
931 DdeGetData(hData
, (LPBYTE
)data
, len
, 0);
933 DdeFreeDataHandle(hData
);
935 connection
->OnPoke(connection
->m_topicName
,
941 return (DDERETURN
)DDE_FACK
;
945 return (DDERETURN
)DDE_FNOTPROCESSED
;
951 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
955 wxString item_name
= DDEStringFromAtom(hsz2
);
957 return (DDERETURN
)connection
->
958 OnStartAdvise(connection
->m_topicName
, item_name
);
966 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
970 wxString item_name
= DDEStringFromAtom(hsz2
);
972 return (DDERETURN
)connection
->
973 OnStopAdvise(connection
->m_topicName
, item_name
);
981 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
983 if (connection
&& connection
->m_sendingData
)
985 HDDEDATA data
= DdeCreateDataHandle
988 (LPBYTE
)connection
->m_sendingData
,
989 connection
->m_dataSize
,
992 connection
->m_dataType
,
996 connection
->m_sendingData
= NULL
;
998 return (DDERETURN
)data
;
1006 wxDDEConnection
*connection
= DDEFindConnection(hConv
);
1010 wxString item_name
= DDEStringFromAtom(hsz2
);
1012 DWORD len
= DdeGetData(hData
, NULL
, 0, 0);
1014 void *data
= connection
->GetBufferAtLeast(len
);
1015 wxASSERT_MSG(data
!= NULL
,
1016 _T("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
1018 DdeGetData(hData
, (LPBYTE
)data
, len
, 0);
1020 DdeFreeDataHandle(hData
);
1021 if ( connection
->OnAdvise(connection
->m_topicName
,
1025 (wxIPCFormat
) wFmt
) )
1027 return (DDERETURN
)(DWORD
)DDE_FACK
;
1031 return (DDERETURN
)DDE_FNOTPROCESSED
;
1035 return (DDERETURN
)0;
1038 // ----------------------------------------------------------------------------
1039 // DDE strings and atoms
1040 // ----------------------------------------------------------------------------
1043 static HSZ
DDEAddAtom(const wxString
& str
)
1045 HSZ atom
= DDEAtomFromString(str
);
1046 wxAtomTable
[str
] = atom
;
1050 static HSZ
DDEGetAtom(const wxString
& str
)
1052 wxAtomMap::iterator it
= wxAtomTable
.find(str
);
1054 if (it
!= wxAtomTable
.end())
1057 return DDEAddAtom(str
);
1061 The returned handle has to be freed by the caller (using
1062 (static) DDEFreeString).
1064 static HSZ
DDEAtomFromString(const wxString
& s
)
1066 wxASSERT_MSG( DDEIdInst
, _T("DDE not initialized") );
1068 HSZ hsz
= DdeCreateStringHandle(DDEIdInst
, (wxChar
*)s
.wx_str(), DDE_CP
);
1071 DDELogError(_("Failed to create DDE string"));
1077 static wxString
DDEStringFromAtom(HSZ hsz
)
1079 // all DDE strings are normally limited to 255 bytes
1080 static const size_t len
= 256;
1083 (void)DdeQueryString(DDEIdInst
, hsz
, wxStringBuffer(s
, len
), len
, DDE_CP
);
1088 static void DDEFreeString(HSZ hsz
)
1090 // DS: Failure to free a string handle might indicate there's
1091 // some other severe error.
1092 bool ok
= (::DdeFreeStringHandle(DDEIdInst
, hsz
) != 0);
1093 wxASSERT_MSG( ok
, wxT("Failed to free DDE string handle") );
1097 // ----------------------------------------------------------------------------
1099 // ----------------------------------------------------------------------------
1101 static void DDELogError(const wxString
& s
, UINT error
)
1105 error
= DdeGetLastError(DDEIdInst
);
1108 wxLogError(s
+ _T(": ") + DDEGetErrorMsg(error
));
1111 static wxString
DDEGetErrorMsg(UINT error
)
1116 case DMLERR_NO_ERROR
:
1117 err
= _("no DDE error.");
1120 case DMLERR_ADVACKTIMEOUT
:
1121 err
= _("a request for a synchronous advise transaction has timed out.");
1124 err
= _("the response to the transaction caused the DDE_FBUSY bit to be set.");
1126 case DMLERR_DATAACKTIMEOUT
:
1127 err
= _("a request for a synchronous data transaction has timed out.");
1129 case DMLERR_DLL_NOT_INITIALIZED
:
1130 err
= _("a DDEML function was called without first calling the DdeInitialize function,\nor an invalid instance identifier\nwas passed to a DDEML function.");
1132 case DMLERR_DLL_USAGE
:
1133 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.");
1135 case DMLERR_EXECACKTIMEOUT
:
1136 err
= _("a request for a synchronous execute transaction has timed out.");
1138 case DMLERR_INVALIDPARAMETER
:
1139 err
= _("a parameter failed to be validated by the DDEML.");
1141 case DMLERR_LOW_MEMORY
:
1142 err
= _("a DDEML application has created a prolonged race condition.");
1144 case DMLERR_MEMORY_ERROR
:
1145 err
= _("a memory allocation failed.");
1147 case DMLERR_NO_CONV_ESTABLISHED
:
1148 err
= _("a client's attempt to establish a conversation has failed.");
1150 case DMLERR_NOTPROCESSED
:
1151 err
= _("a transaction failed.");
1153 case DMLERR_POKEACKTIMEOUT
:
1154 err
= _("a request for a synchronous poke transaction has timed out.");
1156 case DMLERR_POSTMSG_FAILED
:
1157 err
= _("an internal call to the PostMessage function has failed. ");
1159 case DMLERR_REENTRANCY
:
1160 err
= _("reentrancy problem.");
1162 case DMLERR_SERVER_DIED
:
1163 err
= _("a server-side transaction was attempted on a conversation\nthat was terminated by the client, or the server\nterminated before completing a transaction.");
1165 case DMLERR_SYS_ERROR
:
1166 err
= _("an internal error has occurred in the DDEML.");
1168 case DMLERR_UNADVACKTIMEOUT
:
1169 err
= _("a request to end an advise transaction has timed out.");
1171 case DMLERR_UNFOUND_QUEUE_ID
:
1172 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.");
1175 err
.Printf(_("Unknown DDE error %08x"), error
);