From c657fd3d61828e0507c9dae5522f6c007e87628c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 24 Dec 2018 01:42:12 +0100 Subject: [PATCH] Fix passing Unicode strings via wxIPC when using DDE wxIPC API doesn't map well onto DDE, as we don't have wxIPCFormat parameter in StartAdvise() but do allow specifying the format when calling Advise() itself, whereas DDE requires specifying the format when establishing the advise loop and the data always must use this format later. Because of this, we have to pass the actual format with the data itself instead of relying on DDE formats support. This has the advantage of allowing wxIPC_UTF8TEXT to work, while previously it didn't and couldn't, as DDE only supports the standard (or custom, but registered) clipboard formats and it wasn't one of them. Of course, this also has a disadvantage of having to make another copy of the data, but this seems unavoidable. This change allow Advise() overload taking wxString to work, including for non-ASCII strings, as shown by the update to the IPC sample. It also makes wxDDEConnection::m_dataType unnecessary, as we must always use the format passed to DDE callback anyhow when handling XTYP_ADVREQ. Closes #17900. --- docs/changes.txt | 4 ++++ include/wx/msw/dde.h | 1 - samples/ipc/server.cpp | 6 +++++- src/msw/dde.cpp | 32 ++++++++++++++++++++++---------- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 16cb9613f5..404da6917a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -124,6 +124,10 @@ All (GUI): - Allow changing tooltip text for button allowing to enter a new string in wxPGArrayEditorDialog. +wxMSW: + +- Fix passing Unicode strings via wxIPC when using DDE. + 3.1.2: (released 2018-12-10) ---------------------------- diff --git a/include/wx/msw/dde.h b/include/wx/msw/dde.h index 91fdd06f96..a7cd04ccda 100644 --- a/include/wx/msw/dde.h +++ b/include/wx/msw/dde.h @@ -70,7 +70,6 @@ public: WXHCONV m_hConv; const void* m_sendingData; int m_dataSize; - wxIPCFormat m_dataType; wxDECLARE_NO_COPY_CLASS(wxDDEConnection); wxDECLARE_DYNAMIC_CLASS(wxDDEConnection); diff --git a/samples/ipc/server.cpp b/samples/ipc/server.cpp index 25a4420cc1..8058eb983a 100644 --- a/samples/ipc/server.cpp +++ b/samples/ipc/server.cpp @@ -268,7 +268,11 @@ void MyServer::Advise() { const wxDateTime now = wxDateTime::Now(); - m_connection->Advise(m_connection->m_advise, now.Format()); + m_connection->Advise + ( + m_connection->m_advise, + wxString::FromUTF8("\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82") + ); const wxString s = now.FormatTime() + " " + now.FormatDate(); m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN); diff --git a/src/msw/dde.cpp b/src/msw/dde.cpp index ccea317306..11199fad2f 100644 --- a/src/msw/dde.cpp +++ b/src/msw/dde.cpp @@ -748,12 +748,20 @@ bool wxDDEConnection::DoAdvise(const wxString& item, size_t size, wxIPCFormat format) { + // Unfortunately we currently always use the same CF_TEXT in StartAdvise() + // but allow calling Advise() with different formats. This doesn't map well + // to the DDE API, so the price to pay for it is that we need to send the + // actual format used as part of the data, even if this means making + // another copy of it. + wxCharBuffer buf; + buf.extend(size + 1); + *buf.data() = format; + memcpy(buf.data() + 1, data, size); + HSZ item_atom = DDEGetAtom(item); HSZ topic_atom = DDEGetAtom(m_topicName); - m_sendingData = data; // mrf: potential for scope problems here? - m_dataSize = size; - // wxIPC_PRIVATE does not succeed, so use text instead - m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format; + m_sendingData = buf.data(); + m_dataSize = size + 1; bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0; if ( !ok ) @@ -986,11 +994,12 @@ _DDECallback(UINT wType, connection->m_dataSize, 0, hsz2, - connection->m_dataType, + wFmt, 0 ); connection->m_sendingData = NULL; + connection->m_dataSize = 0; return (DDERETURN)data; } @@ -1008,18 +1017,21 @@ _DDECallback(UINT wType, DWORD len = DdeGetData(hData, NULL, 0, 0); - void *data = connection->GetBufferAtLeast(len); + BYTE* const data = static_cast(connection->GetBufferAtLeast(len)); wxASSERT_MSG(data != NULL, wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") ); - DdeGetData(hData, (LPBYTE)data, len, 0); + DdeGetData(hData, data, len, 0); DdeFreeDataHandle(hData); + + // Our code in DoAdvise() prepends the actual format of the + // data as the first byte, extract it back now. if ( connection->OnAdvise(connection->m_topicName, item_name, - data, - (int)len, - (wxIPCFormat) wFmt) ) + data + 1, + (int)len - 1, + (wxIPCFormat)*data) ) { return (DDERETURN)(DWORD)DDE_FACK; }