Send Unicode data as UTF-8 text when using DDE-based IPC
This is a more hackish but more compatible solution to the problem of
data sent using wxIPC_UTF8TEXT format being simply lost when using DDE
for IPC classes. We must use CF_TEXT for the DDE to pass our data, but
we can try to decode it as UTF-8 in the client and assume it was sent in
this format if it worked. This obviously suffers from false positives as
any ASCII string will still be assumed to be UTF-8, but there shouldn't
be any real harm coming from this.
This change also makes sending data in wxIPC_UTF{16,32}TEXT formats work
as well by converting it to UTF-8.
Update the sample to call Advise() with both wxIPC_UTF{8,16}TEXT formats
and remove the now unnecessary wxDDEConnection::m_dataType member.
Closes #17900.
			
			
This commit is contained in:
		@@ -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)
 | 
			
		||||
----------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -268,8 +268,15 @@ void MyServer::Advise()
 | 
			
		||||
    {
 | 
			
		||||
        const wxDateTime now = wxDateTime::Now();
 | 
			
		||||
 | 
			
		||||
        m_connection->Advise(m_connection->m_advise, now.Format());
 | 
			
		||||
        wxString str = wxString::FromUTF8("\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82");
 | 
			
		||||
        m_connection->Advise(m_connection->m_advise, str + " (using UTF-8)");
 | 
			
		||||
 | 
			
		||||
        str += " (using wchar_t)";
 | 
			
		||||
        m_connection->Advise(m_connection->m_advise,
 | 
			
		||||
                             str.wc_str(), (str.length() + 1)*sizeof(wchar_t),
 | 
			
		||||
                             wxIPC_UNICODETEXT);
 | 
			
		||||
 | 
			
		||||
        // This one uses wxIPC_TEXT by default.
 | 
			
		||||
        const wxString s = now.FormatTime() + " " + now.FormatDate();
 | 
			
		||||
        m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -742,6 +742,14 @@ bool wxDDEConnection::StopAdvise(const wxString& item)
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Small helper function converting the data from the format used by the given
 | 
			
		||||
// conversion to UTF-8.
 | 
			
		||||
static
 | 
			
		||||
wxCharBuffer ConvertToUTF8(const wxMBConv& conv, const void* data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    return wxConvUTF8.cWC2MB(conv.cMB2WC((const char*)data, size, NULL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Calls that SERVER can make
 | 
			
		||||
bool wxDDEConnection::DoAdvise(const wxString& item,
 | 
			
		||||
                               const void *data,
 | 
			
		||||
@@ -750,10 +758,55 @@ bool wxDDEConnection::DoAdvise(const wxString& item,
 | 
			
		||||
{
 | 
			
		||||
    HSZ item_atom = DDEGetAtom(item);
 | 
			
		||||
    HSZ topic_atom = DDEGetAtom(m_topicName);
 | 
			
		||||
    m_sendingData = data;  // mrf: potential for scope problems here?
 | 
			
		||||
 | 
			
		||||
    // Define the buffer which, if it's used at all, needs to stay alive until
 | 
			
		||||
    // after DdePostAdvise() call which uses it.
 | 
			
		||||
    wxCharBuffer buf;
 | 
			
		||||
 | 
			
		||||
    // As we always use CF_TEXT for XTYP_ADVSTART, we have to use wxIPC_TEXT
 | 
			
		||||
    // here, even if a different format was specified for this value. Of
 | 
			
		||||
    // course, this can only be done for just a few of the formats, so check
 | 
			
		||||
    // that we have one of them here.
 | 
			
		||||
    switch ( format )
 | 
			
		||||
    {
 | 
			
		||||
        case wxIPC_TEXT:
 | 
			
		||||
        case wxIPC_OEMTEXT:
 | 
			
		||||
        case wxIPC_UTF8TEXT:
 | 
			
		||||
        case wxIPC_PRIVATE:
 | 
			
		||||
            // Use the data directly.
 | 
			
		||||
            m_sendingData = data;
 | 
			
		||||
            m_dataSize = size;
 | 
			
		||||
    // wxIPC_PRIVATE does not succeed, so use text instead
 | 
			
		||||
    m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case wxIPC_UTF16TEXT:
 | 
			
		||||
        case wxIPC_UTF32TEXT:
 | 
			
		||||
            // We need to convert the data to UTF-8 as UTF-16 or 32 would
 | 
			
		||||
            // appear as mojibake in the client when received as CF_TEXT.
 | 
			
		||||
            buf = format == wxIPC_UTF16TEXT
 | 
			
		||||
                    ? ConvertToUTF8(wxMBConvUTF16(), data, size)
 | 
			
		||||
                    : ConvertToUTF8(wxMBConvUTF32(), data, size);
 | 
			
		||||
 | 
			
		||||
            m_sendingData = buf.data();
 | 
			
		||||
            m_dataSize = buf.length();
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case wxIPC_INVALID:
 | 
			
		||||
        case wxIPC_BITMAP:
 | 
			
		||||
        case wxIPC_METAFILE:
 | 
			
		||||
        case wxIPC_SYLK:
 | 
			
		||||
        case wxIPC_DIF:
 | 
			
		||||
        case wxIPC_TIFF:
 | 
			
		||||
        case wxIPC_DIB:
 | 
			
		||||
        case wxIPC_PALETTE:
 | 
			
		||||
        case wxIPC_PENDATA:
 | 
			
		||||
        case wxIPC_RIFF:
 | 
			
		||||
        case wxIPC_WAVE:
 | 
			
		||||
        case wxIPC_ENHMETAFILE:
 | 
			
		||||
        case wxIPC_FILENAME:
 | 
			
		||||
        case wxIPC_LOCALE:
 | 
			
		||||
            wxFAIL_MSG( "Unsupported IPC format for Advise()" );
 | 
			
		||||
            return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
 | 
			
		||||
    if ( !ok )
 | 
			
		||||
@@ -986,7 +1039,7 @@ _DDECallback(UINT wType,
 | 
			
		||||
                                        connection->m_dataSize,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        hsz2,
 | 
			
		||||
                                        connection->m_dataType,
 | 
			
		||||
                                        wFmt,
 | 
			
		||||
                                        0
 | 
			
		||||
                                    );
 | 
			
		||||
 | 
			
		||||
@@ -1008,18 +1061,34 @@ _DDECallback(UINT wType,
 | 
			
		||||
 | 
			
		||||
                    DWORD len = DdeGetData(hData, NULL, 0, 0);
 | 
			
		||||
 | 
			
		||||
                    void *data = connection->GetBufferAtLeast(len);
 | 
			
		||||
                    char* const data = (char *)connection->GetBufferAtLeast(len);
 | 
			
		||||
                    wxASSERT_MSG(data != NULL,
 | 
			
		||||
                                 wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
 | 
			
		||||
 | 
			
		||||
                    DdeGetData(hData, (LPBYTE)data, len, 0);
 | 
			
		||||
 | 
			
		||||
                    DdeFreeDataHandle(hData);
 | 
			
		||||
 | 
			
		||||
                    // We always get data in CF_TEXT format, but it could
 | 
			
		||||
                    // actually be UTF-8, so try recovering the original format
 | 
			
		||||
                    // if possible.
 | 
			
		||||
                    if ( wFmt != CF_TEXT )
 | 
			
		||||
                    {
 | 
			
		||||
                        wxLogDebug("Unexpected format %02x in XTYP_ADVDATA", wFmt);
 | 
			
		||||
                        return (DDERETURN)DDE_FNOTPROCESSED;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    wxIPCFormat format;
 | 
			
		||||
                    if ( wxConvUTF8.ToWChar(NULL, 0, data, len) != wxCONV_FAILED )
 | 
			
		||||
                        format = wxIPC_UTF8TEXT;
 | 
			
		||||
                    else
 | 
			
		||||
                        format = wxIPC_TEXT;
 | 
			
		||||
 | 
			
		||||
                    if ( connection->OnAdvise(connection->m_topicName,
 | 
			
		||||
                                              item_name,
 | 
			
		||||
                                              data,
 | 
			
		||||
                                              (int)len,
 | 
			
		||||
                                              (wxIPCFormat) wFmt) )
 | 
			
		||||
                                              format) )
 | 
			
		||||
                    {
 | 
			
		||||
                        return (DDERETURN)(DWORD)DDE_FACK;
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user