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
|
- Allow changing tooltip text for button allowing to enter a new string
|
||||||
in wxPGArrayEditorDialog.
|
in wxPGArrayEditorDialog.
|
||||||
|
|
||||||
|
wxMSW:
|
||||||
|
|
||||||
|
- Fix passing Unicode strings via wxIPC when using DDE.
|
||||||
|
|
||||||
|
|
||||||
3.1.2: (released 2018-12-10)
|
3.1.2: (released 2018-12-10)
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@@ -70,7 +70,6 @@ public:
|
|||||||
WXHCONV m_hConv;
|
WXHCONV m_hConv;
|
||||||
const void* m_sendingData;
|
const void* m_sendingData;
|
||||||
int m_dataSize;
|
int m_dataSize;
|
||||||
wxIPCFormat m_dataType;
|
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxDDEConnection);
|
wxDECLARE_NO_COPY_CLASS(wxDDEConnection);
|
||||||
wxDECLARE_DYNAMIC_CLASS(wxDDEConnection);
|
wxDECLARE_DYNAMIC_CLASS(wxDDEConnection);
|
||||||
|
@@ -268,8 +268,15 @@ void MyServer::Advise()
|
|||||||
{
|
{
|
||||||
const wxDateTime now = wxDateTime::Now();
|
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();
|
const wxString s = now.FormatTime() + " " + now.FormatDate();
|
||||||
m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN);
|
m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN);
|
||||||
|
|
||||||
|
@@ -742,6 +742,14 @@ bool wxDDEConnection::StopAdvise(const wxString& item)
|
|||||||
return ok;
|
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
|
// Calls that SERVER can make
|
||||||
bool wxDDEConnection::DoAdvise(const wxString& item,
|
bool wxDDEConnection::DoAdvise(const wxString& item,
|
||||||
const void *data,
|
const void *data,
|
||||||
@@ -750,10 +758,55 @@ bool wxDDEConnection::DoAdvise(const wxString& item,
|
|||||||
{
|
{
|
||||||
HSZ item_atom = DDEGetAtom(item);
|
HSZ item_atom = DDEGetAtom(item);
|
||||||
HSZ topic_atom = DDEGetAtom(m_topicName);
|
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;
|
m_dataSize = size;
|
||||||
// wxIPC_PRIVATE does not succeed, so use text instead
|
break;
|
||||||
m_dataType = format == wxIPC_PRIVATE ? wxIPC_TEXT : format;
|
|
||||||
|
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;
|
bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0;
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
@@ -986,7 +1039,7 @@ _DDECallback(UINT wType,
|
|||||||
connection->m_dataSize,
|
connection->m_dataSize,
|
||||||
0,
|
0,
|
||||||
hsz2,
|
hsz2,
|
||||||
connection->m_dataType,
|
wFmt,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1008,18 +1061,34 @@ _DDECallback(UINT wType,
|
|||||||
|
|
||||||
DWORD len = DdeGetData(hData, NULL, 0, 0);
|
DWORD len = DdeGetData(hData, NULL, 0, 0);
|
||||||
|
|
||||||
void *data = connection->GetBufferAtLeast(len);
|
char* const data = (char *)connection->GetBufferAtLeast(len);
|
||||||
wxASSERT_MSG(data != NULL,
|
wxASSERT_MSG(data != NULL,
|
||||||
wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
|
wxT("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
|
||||||
|
|
||||||
DdeGetData(hData, (LPBYTE)data, len, 0);
|
DdeGetData(hData, (LPBYTE)data, len, 0);
|
||||||
|
|
||||||
DdeFreeDataHandle(hData);
|
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,
|
if ( connection->OnAdvise(connection->m_topicName,
|
||||||
item_name,
|
item_name,
|
||||||
data,
|
data,
|
||||||
(int)len,
|
(int)len,
|
||||||
(wxIPCFormat) wFmt) )
|
format) )
|
||||||
{
|
{
|
||||||
return (DDERETURN)(DWORD)DDE_FACK;
|
return (DDERETURN)(DWORD)DDE_FACK;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user