X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9ed0d735d588f42485461ea526596436c4c6ad4b..b404a8f3b072129c107c6d9a5e0f6f53cd34807b:/src/msw/dde.cpp diff --git a/src/msw/dde.cpp b/src/msw/dde.cpp index ce6914ee5c..d59e1256d3 100644 --- a/src/msw/dde.cpp +++ b/src/msw/dde.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: msw/dde.cpp +// Name: src/msw/dde.cpp // Purpose: DDE classes // Author: Julian Smart // Modified by: @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "dde.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -33,40 +29,20 @@ #ifndef WX_PRECOMP #include "wx/utils.h" #include "wx/app.h" + #include "wx/hashmap.h" + #include "wx/module.h" #endif -#include "wx/module.h" #include "wx/dde.h" #include "wx/intl.h" -#include "wx/hashmap.h" +#include "wx/buffer.h" +#include "wx/strconv.h" #include "wx/msw/private.h" #include #include -#ifdef __GNUWIN32_OLD__ - #include "wx/msw/gnuwin32/extra.h" -#endif - -// some compilers headers don't define this one (mingw32) -#ifndef DMLERR_NO_ERROR - #define DMLERR_NO_ERROR (0) - - // this one is also missing from some mingw32 headers, but there is no way - // to test for it (I know of) - the test for DMLERR_NO_ERROR works for me, - // but is surely not the right thing to do - extern "C" - HDDEDATA STDCALL DdeClientTransaction(LPBYTE pData, - DWORD cbData, - HCONV hConv, - HSZ hszItem, - UINT wFmt, - UINT wType, - DWORD dwTimeout, - LPDWORD pdwResult); -#endif // no DMLERR_NO_ERROR - // ---------------------------------------------------------------------------- // macros and constants // ---------------------------------------------------------------------------- @@ -112,6 +88,7 @@ static HSZ DDEGetAtom(const wxString& string); // string handles static HSZ DDEAtomFromString(const wxString& s); static wxString DDEStringFromAtom(HSZ hsz); +static void DDEFreeString(HSZ hsz); // error handling static wxString DDEGetErrorMsg(UINT error); @@ -129,9 +106,9 @@ static wxAtomMap wxAtomTable; #include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxDDEClientList); -WX_DEFINE_LIST(wxDDEServerList); -WX_DEFINE_LIST(wxDDEConnectionList); +WX_DEFINE_LIST(wxDDEClientList) +WX_DEFINE_LIST(wxDDEServerList) +WX_DEFINE_LIST(wxDDEConnectionList) static wxDDEClientList wxDDEClientObjects; static wxDDEServerList wxDDEServerObjects; @@ -162,7 +139,7 @@ private: IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase) IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase) -IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase) +IMPLEMENT_DYNAMIC_CLASS(wxDDEConnection, wxConnectionBase) IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule) // ============================================================================ @@ -183,7 +160,7 @@ extern void wxDDEInitialize() UINT rc = DdeInitialize(&DDEIdInst, callback, APPCLASS_STANDARD, 0L); if ( rc != DMLERR_NO_ERROR ) { - DDELogError(_T("Failed to initialize DDE"), rc); + DDELogError(wxT("Failed to initialize DDE"), rc); } else { @@ -194,8 +171,10 @@ extern void wxDDEInitialize() void wxDDECleanUp() { - WX_CLEAR_LIST(wxDDEClientList, wxDDEClientObjects); - WX_CLEAR_LIST(wxDDEServerList, wxDDEServerObjects); + // deleting them later won't work as DDE won't be initialized any more + wxASSERT_MSG( wxDDEServerObjects.empty() && + wxDDEClientObjects.empty(), + wxT("all DDE objects should be deleted by now") ); wxAtomTable.clear(); @@ -299,26 +278,45 @@ bool wxDDEServer::Create(const wxString& server) { m_serviceName = server; - if ( !DdeNameService(DDEIdInst, DDEAtomFromString(server), (HSZ)NULL, DNS_REGISTER) ) - { - DDELogError(wxString::Format(_("Failed to register DDE server '%s'"), - server.c_str())); + HSZ hsz = DDEAtomFromString(server); + if ( !hsz ) + { return false; } - return true; + + bool success = (DdeNameService(DDEIdInst, hsz, (HSZ) NULL, DNS_REGISTER) + != NULL); + + if (!success) + { + DDELogError(wxString::Format(_("Failed to register DDE server '%s'"), + server.c_str())); + } + + DDEFreeString(hsz); + + return success; } wxDDEServer::~wxDDEServer() { - if ( !!m_serviceName ) + if ( !m_serviceName.empty() ) { - if ( !DdeNameService(DDEIdInst, DDEAtomFromString(m_serviceName), - (HSZ)NULL, DNS_UNREGISTER) ) + HSZ hsz = DDEAtomFromString(m_serviceName); + + if (hsz) { - DDELogError(wxString::Format(_("Failed to unregister DDE server '%s'"), - m_serviceName.c_str())); + if ( !DdeNameService(DDEIdInst, hsz, + (HSZ) NULL, DNS_UNREGISTER) ) + { + DDELogError(wxString::Format( + _("Failed to unregister DDE server '%s'"), + m_serviceName.c_str())); + } + + DDEFreeString(hsz); } } @@ -329,7 +327,6 @@ wxDDEServer::~wxDDEServer() { wxDDEConnection *connection = node->GetData(); wxDDEConnectionList::compatibility_iterator next = node->GetNext(); - connection->SetConnected(false); connection->OnDisconnect(); // May delete the node implicitly node = next; } @@ -416,12 +413,35 @@ wxConnectionBase *wxDDEClient::MakeConnection(const wxString& WXUNUSED(host), const wxString& server, const wxString& topic) { - HCONV hConv = DdeConnect(DDEIdInst, DDEAtomFromString(server), DDEAtomFromString(topic), - (PCONVCONTEXT)NULL); + HSZ hszServer = DDEAtomFromString(server); + + if ( !hszServer ) + { + return NULL; + } + + + HSZ hszTopic = DDEAtomFromString(topic); + + if ( !hszTopic ) + { + DDEFreeString(hszServer); + return NULL; + } + + + HCONV hConv = ::DdeConnect(DDEIdInst, hszServer, hszTopic, + (PCONVCONTEXT) NULL); + + DDEFreeString(hszServer); + DDEFreeString(hszTopic); + + if ( !hConv ) { - DDELogError(wxString::Format(_("Failed to create connection to server '%s' on topic '%s'"), - server.c_str(), topic.c_str())); + DDELogError( wxString::Format( + _("Failed to create connection to server '%s' on topic '%s'"), + server.c_str(), topic.c_str()) ); } else { @@ -436,7 +456,7 @@ wxConnectionBase *wxDDEClient::MakeConnection(const wxString& WXUNUSED(host), } } - return (wxConnectionBase*) NULL; + return NULL; } wxConnectionBase *wxDDEClient::OnMakeConnection() @@ -479,7 +499,7 @@ bool wxDDEClient::DeleteConnection(WXHCONV conv) // wxDDEConnection // ---------------------------------------------------------------------------- -wxDDEConnection::wxDDEConnection(wxChar *buffer, int size) +wxDDEConnection::wxDDEConnection(void *buffer, size_t size) : wxConnectionBase(buffer, size) { m_client = NULL; @@ -518,7 +538,7 @@ bool wxDDEConnection::Disconnect() bool ok = DdeDisconnect(GetHConv()) != 0; if ( !ok ) { - DDELogError(_T("Failed to disconnect from DDE server gracefully")); + DDELogError(wxT("Failed to disconnect from DDE server gracefully")); } SetConnected( false ); // so we don't try and disconnect again @@ -526,31 +546,115 @@ bool wxDDEConnection::Disconnect() return ok; } -bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat format) +bool +wxDDEConnection::DoExecute(const void *data, size_t size, wxIPCFormat format) { - DWORD result; - if (size < 0) + wxCHECK_MSG( format == wxIPC_TEXT || + format == wxIPC_UTF8TEXT || + format == wxIPC_UNICODETEXT, + false, + wxT("wxDDEServer::Execute() supports only text data") ); + + wxMemoryBuffer buffer; + LPBYTE realData = NULL; + size_t realSize = 0; + wxMBConv *conv = NULL; + + // Windows only supports either ANSI or UTF-16 format depending on the + // build, so we need to convert the data if it doesn't use it already +#if wxUSE_UNICODE + if ( format == wxIPC_TEXT ) + { + conv = &wxConvLibc; + } + else if ( format == wxIPC_UTF8TEXT ) { - size = wxStrlen(data) + 1; + conv = &wxConvUTF8; } + else // no conversion necessary for wxIPC_UNICODETEXT + { + realData = (LPBYTE)data; + realSize = size; + } + + if ( conv ) + { + const char * const text = (const char *)data; + const size_t len = size/sizeof(char); + + realSize = conv->ToWChar(NULL, 0, text, len); + if ( realSize == wxCONV_FAILED ) + return false; + + realData = (LPBYTE)buffer.GetWriteBuf(realSize*sizeof(wchar_t)); + if ( !realData ) + return false; + + realSize = conv->ToWChar((wchar_t *)realData, realSize, text, len); + if ( realSize == wxCONV_FAILED ) + return false; + } +#else // !wxUSE_UNICODE + if ( format == wxIPC_UNICODETEXT ) + { + conv = &wxConvLibc; + } + else if ( format == wxIPC_UTF8TEXT ) + { + // we could implement this in theory but it's not obvious how to pass + // the format information and, basically, why bother -- just use + // Unicode build + wxFAIL_MSG( wxT("UTF-8 text not supported in ANSI build") ); + + return false; + } + else // don't convert wxIPC_TEXT + { + realData = (LPBYTE)data; + realSize = size; + } + + if ( conv ) + { + const wchar_t * const wtext = (const wchar_t *)data; + const size_t len = size/sizeof(wchar_t); - bool ok = DdeClientTransaction((LPBYTE)data, size, - GetHConv(), - NULL, - format, - XTYP_EXECUTE, - DDE_TIMEOUT, - &result) != 0; + realSize = conv->FromWChar(NULL, 0, wtext, len); + if ( realSize == wxCONV_FAILED ) + return false; + + realData = (LPBYTE)buffer.GetWriteBuf(realSize*sizeof(char)); + if ( !realData ) + return false; + + realSize = conv->FromWChar((char*)realData, realSize, wtext, len); + if ( realSize == wxCONV_FAILED ) + return false; + } +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + + DWORD result; + bool ok = DdeClientTransaction(realData, + realSize*sizeof(wxChar), + GetHConv(), + NULL, + // MSDN: if the transaction specified by + // the wType parameter does not pass data + // or is XTYP_EXECUTE, wFmt should be zero. + 0, + XTYP_EXECUTE, + DDE_TIMEOUT, + &result) != 0; if ( !ok ) { - DDELogError(_T("DDE execute request failed")); + DDELogError(wxT("DDE execute request failed")); } return ok; } -wxChar *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format) +const void *wxDDEConnection::Request(const wxString& item, size_t *size, wxIPCFormat format) { DWORD result; @@ -564,36 +668,33 @@ wxChar *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat fo &result); if ( !returned_data ) { - DDELogError(_T("DDE data request failed")); + DDELogError(wxT("DDE data request failed")); return NULL; } DWORD len = DdeGetData(returned_data, NULL, 0, 0); - wxChar *data = GetBufferAtLeast( len ); + void *data = GetBufferAtLeast(len); wxASSERT_MSG(data != NULL, - _T("Buffer too small in wxDDEConnection::Request") ); - DdeGetData(returned_data, (LPBYTE)data, len, 0); + wxT("Buffer too small in wxDDEConnection::Request") ); + (void) DdeGetData(returned_data, (LPBYTE)data, len, 0); - DdeFreeDataHandle(returned_data); + (void) DdeFreeDataHandle(returned_data); if (size) - *size = (int)len; + *size = (size_t)len; return data; } -bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format) +bool wxDDEConnection::DoPoke(const wxString& item, const void *data, size_t size, wxIPCFormat format) { DWORD result; - if (size < 0) - { - size = wxStrlen(data) + 1; - } HSZ item_atom = DDEGetAtom(item); - bool ok = DdeClientTransaction((LPBYTE)data, size, + bool ok = DdeClientTransaction((LPBYTE)data, + size, GetHConv(), item_atom, format, XTYP_POKE, @@ -646,21 +747,17 @@ bool wxDDEConnection::StopAdvise(const wxString& item) } // Calls that SERVER can make -bool wxDDEConnection::Advise(const wxString& item, - wxChar *data, - int size, - wxIPCFormat format) +bool wxDDEConnection::DoAdvise(const wxString& item, + const void *data, + size_t size, + wxIPCFormat format) { - if (size < 0) - { - size = wxStrlen(data) + 1; - } - HSZ item_atom = DDEGetAtom(item); HSZ topic_atom = DDEGetAtom(m_topicName); m_sendingData = data; // mrf: potential for scope problems here? m_dataSize = size; - m_dataType = format; + // wxIPC_PRIVATE does not succeed, so use text instead + m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format; bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0; if ( !ok ) @@ -671,12 +768,6 @@ bool wxDDEConnection::Advise(const wxString& item, return ok; } -bool wxDDEConnection::OnDisconnect() -{ - delete this; - return true; -} - // ---------------------------------------------------------------------------- // _DDECallback // ---------------------------------------------------------------------------- @@ -751,18 +842,27 @@ _DDECallback(WORD wType, { DWORD len = DdeGetData(hData, NULL, 0, 0); - wxChar *data = connection->GetBufferAtLeast( len ); + void *data = connection->GetBufferAtLeast(len); wxASSERT_MSG(data != NULL, - _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") ); + wxT("Buffer too small in _DDECallback (XTYP_EXECUTE)") ); DdeGetData(hData, (LPBYTE)data, len, 0); DdeFreeDataHandle(hData); + // XTYP_EXECUTE can be used for text only and the text is + // always in ANSI format for ANSI build and Unicode format + // in Unicode build + #if wxUSE_UNICODE + wFmt = wxIPC_UNICODETEXT; + #else + wFmt = wxIPC_TEXT; + #endif + if ( connection->OnExecute(connection->m_topicName, data, (int)len, - (wxIPCFormat) wFmt) ) + (wxIPCFormat)wFmt) ) { return (DDERETURN)(DWORD)DDE_FACK; } @@ -779,15 +879,26 @@ _DDECallback(WORD wType, { wxString item_name = DDEStringFromAtom(hsz2); - int user_size = -1; - wxChar *data = connection->OnRequest(connection->m_topicName, - item_name, - &user_size, - (wxIPCFormat) wFmt); + size_t user_size = wxNO_LEN; + const void *data = connection->OnRequest(connection->m_topicName, + item_name, + &user_size, + (wxIPCFormat)wFmt); if (data) { - if (user_size < 0) - user_size = wxStrlen((wxChar*)data) + 1; + if (user_size == wxNO_LEN) + switch (wFmt) + { + case wxIPC_TEXT: + case wxIPC_UTF8TEXT: + user_size = strlen((const char*)data) + 1; // includes final NUL + break; + case wxIPC_UNICODETEXT: + user_size = (wcslen((const wchar_t*)data) + 1) * sizeof(wchar_t); // includes final NUL + break; + default: + user_size = 0; + } HDDEDATA handle = DdeCreateDataHandle(DDEIdInst, (LPBYTE)data, @@ -812,9 +923,9 @@ _DDECallback(WORD wType, DWORD len = DdeGetData(hData, NULL, 0, 0); - wxChar *data = connection->GetBufferAtLeast( len ); + void *data = connection->GetBufferAtLeast(len); wxASSERT_MSG(data != NULL, - _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") ); + wxT("Buffer too small in _DDECallback (XTYP_POKE)") ); DdeGetData(hData, (LPBYTE)data, len, 0); @@ -899,9 +1010,9 @@ _DDECallback(WORD wType, DWORD len = DdeGetData(hData, NULL, 0, 0); - wxChar *data = connection->GetBufferAtLeast( len ); + void *data = connection->GetBufferAtLeast(len); wxASSERT_MSG(data != NULL, - _T("Buffer too small in _DDECallback (XTYP_ADVDATA)") ); + wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") ); DdeGetData(hData, (LPBYTE)data, len, 0); @@ -945,12 +1056,15 @@ static HSZ DDEGetAtom(const wxString& str) return DDEAddAtom(str); } -// atom <-> strings +/* atom <-> strings +The returned handle has to be freed by the caller (using +(static) DDEFreeString). +*/ static HSZ DDEAtomFromString(const wxString& s) { - wxASSERT_MSG( DDEIdInst, _T("DDE not initialized") ); + wxASSERT_MSG( DDEIdInst, wxT("DDE not initialized") ); - HSZ hsz = DdeCreateStringHandle(DDEIdInst, (wxChar*) s.c_str(), DDE_CP); + HSZ hsz = DdeCreateStringHandle(DDEIdInst, (wxChar*)s.wx_str(), DDE_CP); if ( !hsz ) { DDELogError(_("Failed to create DDE string")); @@ -965,12 +1079,20 @@ static wxString DDEStringFromAtom(HSZ hsz) static const size_t len = 256; wxString s; - (void)DdeQueryString(DDEIdInst, hsz, s.GetWriteBuf(len), len, DDE_CP); - s.UngetWriteBuf(); + (void)DdeQueryString(DDEIdInst, hsz, wxStringBuffer(s, len), len, DDE_CP); return s; } +static void DDEFreeString(HSZ hsz) +{ + // DS: Failure to free a string handle might indicate there's + // some other severe error. + bool ok = (::DdeFreeStringHandle(DDEIdInst, hsz) != 0); + wxASSERT_MSG( ok, wxT("Failed to free DDE string handle") ); + wxUnusedVar(ok); +} + // ---------------------------------------------------------------------------- // error handling // ---------------------------------------------------------------------------- @@ -982,7 +1104,7 @@ static void DDELogError(const wxString& s, UINT error) error = DdeGetLastError(DDEIdInst); } - wxLogError(s + _T(": ") + DDEGetErrorMsg(error)); + wxLogError(s + wxT(": ") + DDEGetErrorMsg(error)); } static wxString DDEGetErrorMsg(UINT error)