IPC using DDE bug fix and changes
Brian Vanderburg II
BrianVanderburg2 at aim.com
Sat Dec 1 05:47:23 PST 2007
I've attached a patch that makes some changes to how DDE work on =
windows, just for review and suggestions before I submit it to the =
tracker. Also, before I start on it, there is a bug in 'buffer.h' as =
well, wxUTF8Buf should be 'char*' in unicode-utf8 and wxCharBuffer =
otherwise. Without this change, Execute(wxString) didn't seem to work =
right, so I directly implemented wxCharBuffer b =3D s.utf8_str(), =
Execute(b, strlen(b) + 1, wxIPC_UTF8TEXT) and then it works. Then I =
changed buffer.h and it worked directly as Execute(s). Also that is the =
return value of utf8_str from wxString.
Now to the patch. Users of IPC should consider wxIPC_TEXT to mean ANSI =
text, wxIPC_UNICODE_TEXT to mean unicode, and wxIPC_UTF8TEXT to be utf8 =
encoded text. This is no problem for TCPServer because it transfers =
data as-is along with the format, so the format can always be =
determined. Also, for the most part, it seems that this should be no =
problem with DDE since the format is passed, but this is not the case =
for Execute, where the format is not used by XTYP_EXECUTE..
In the current code OnExecute always gets called with wxIPC_TEXT. But =
in a unicode build, the data received by DdeGetData with XTYP_EXECUTE is =
always unicode (even if the sending application sent it as ansi) so this =
would cause a problem if the user says if(format =3D=3D wxIPC_TEXT) do =
something with ansi text (else if format =3D=3D wxIPC_UNICODE_TEXT) do =
soemthing with unicode text from inside OnExecute
The change for that part was quite simple, pass wxIPC_TEXT in ansi =
builds and wxIPC_UNICODETEXT in unicode builds to the OnExecute function.
As mentioned, the data alway gets converted to unicode (for a unicode =
build) in XTYP_EXECUTE, even if the sending app is ANSI or sending =
ANSI. Sometimes there seems to be minor problems in this conversion if =
the input to DdeClientTransaction is ANSI when building in unicode =
(probably since the wFmt must always be 0 for XTYP_EXECUTE). Somewhere =
between DdeClientTransaction in the client and DdeGetData in the server =
it seems to try to detect that the source data was ansi and that the =
dest is unicode an tries to convert it, but sometimes with problems. It =
seems to fail all together if passing a utf8 string with non-ansi =
characters in it. What the patch does is, in DoExecute, takes the value =
of format and uses it to convert the data to the correct format for =
DdeClientTransaction. In unicode, it will convert wxIPC_TEXT and =
wxIPC_UTF8TEXT to wide character and pass it.
Summed-up this patch does 2 things:
1. Ensures that the correct format value is passed to OnExecute. This =
way, saying:
if(format =3D=3D wxIPC_TEXT) { ... }
else if(format =3D=3D wxIPC_UNICODETEXT) { ... }
else if(format =3D=3D wxIPC_UTF8TEXT) { ... }
works as expected for ansi,unicode,utf8 text.
2. Converts text to the needed format from DoExecute This way, saying:
Execute("An ansi string");
or
Execute("A utf-8 string with \u1234\u5678 special characters");
Will work even if the client and/or server is build in unicode. The =
downside is that this causes conversion of the format which does not =
happen with TCP server, but this is a small downside as it seems that =
windows already tries converts the data in Execute to the format the =
destination program is expecting, so this just helps it out.
p.s.
Execute(wxString("abc")) didn't work, but making the change =
mentioned above in buffer.h and the recompiling worked.
Brian Vanderburg II
-------------- next part --------------
Index: src/msw/dde.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/msw/dde.cpp (revision 50395)
+++ src/msw/dde.cpp (working copy)
@@ -35,12 +35,15 @@
=
#include "wx/dde.h"
#include "wx/intl.h"
+#include "wx/buffer.h"
+#include "wx/strconv.h"
=
#include "wx/msw/private.h"
=
#include <string.h>
#include <ddeml.h>
=
+
// -----------------------------------------------------------------------=
-----
// macros and constants
// -----------------------------------------------------------------------=
-----
@@ -545,12 +548,97 @@
return ok;
}
=
-bool wxDDEConnection::DoExecute(const void *data, size_t size, wxIPCFormat=
WXUNUSED(format))
+bool wxDDEConnection::DoExecute(const void *data, size_t size, wxIPCFormat=
format)
{
DWORD result;
+ =
+ // Windows will 'try' to convert the data if it is
+ // not in the right format, but can not convert
+ // utf8 correctly so convert to the format before
+ // sending
+ wxCHECK_MSG(format =3D=3D wxIPC_TEXT || format =3D=3D wxIPC_UNICODETEX=
T || format =3D=3D wxIPC_UTF8TEXT,
+ false, "Only pass text to wxDDEServer::Execute");
+ =
+ wxMemoryBuffer buffer;
+ LPBYTE realData;
+ size_t realSize;
+ wxMBConv* conv;
+ =
+#if wxUSE_UNICODE
+ do
+ {
+ if(format =3D=3D wxIPC_TEXT)
+ {
+ conv =3D &wxConvLibc;
+ }
+ else if(format =3D=3D wxIPC_UTF8TEXT)
+ {
+ conv =3D &wxConvUTF8;
+ }
+ else
+ {
+ realData =3D (LPBYTE)data;
+ realSize =3D size;
+ break;
+ }
+ =
+ // Do the conversion
+ realSize =3D conv->ToWChar(NULL, 0, (const char*)data, size / size=
of(char));
+ if(realSize =3D=3D wxCONV_FAILED)
+ return false;
=
- bool ok =3D DdeClientTransaction((LPBYTE)data,
- size,
+ realData =3D (LPBYTE)buffer.GetWriteBuf(realSize * sizeof(wchar_t)=
);
+ if(realData =3D=3D NULL)
+ return false;
+ =
+ realSize =3D conv->ToWChar((wchar_t*)realData, realSize, (const ch=
ar*)data, size / sizeof(char));
+ if(realSize =3D=3D wxCONV_FAILED)
+ return false;
+ =
+ buffer.UngetWriteBuf(realSize * sizeof(wchar_t));
+
+ realData =3D (LPBYTE)buffer.GetData();
+ realSize =3D buffer.GetDataLen();
+ =
+ } while(false);
+#else
+ do
+ {
+ if(format =3D=3D wxIPC_UNICODETEXT)
+ {
+ conv =3D &wxConvLibc;
+ }
+ else // Perhaps UTF8 should be excluded
+ {
+ realData =3D (LPBYTE)data;
+ realSize =3D size;
+ break;
+ }
+
+ // Do the conversion
+ realSize =3D conv->FromWChar(NULL, 0, (const wchar_t*)data, size /=
sizeof(wchar_t));
+ if(realSize =3D=3D wxCONV_FAILED)
+ return false;
+
+ realData =3D (LPBYTE)buffer.GetWriteBuf(realSize * sizeof(char));
+ if(realData =3D=3D NULL)
+ return false;
+
+ realSize =3D conv->ToWChar((char*)realData, realSize, (const wchar=
_t*)data, size / sizeof(wchar_t));
+ if(realSize =3D=3D wxCONV_FAILED)
+ return false;
+
+ buffer.UngetWriteBuf(realSize * sizeof(char));
+
+ realData =3D (LPBYTE)buffer.GetData();
+ realSize =3D buffer.GetDataLen();
+
+ } while(false);
+
+#endif
+
+ bool ok =3D DdeClientTransaction(realData,
+ realSize,
GetHConv(),
NULL,
// If the transaction specified by the wType parameter does not pass data =
or is XTYP_EXECUTE,
@@ -765,10 +853,18 @@
DdeFreeDataHandle(hData);
=
// XTYP_EXECUTE cannot be used for arbitrary data, but only for text
+// Windows 'tries' to convert the data to unicode if the program
+// is unicode so pass the correct format to OnExecute
+ #if wxUSE_UNICODE
+ wFmt =3D wxIPC_UNICODETEXT;
+ #else
+ wFmt =3D wxIPC_TEXT
+ #endif
+
if ( connection->OnExecute(connection->m_topicName,
data,
(int)len,
- wxIPC_TEXT ) )
+ (wxIPCFormat)wFmt ) )
{
return (DDERETURN)(DWORD)DDE_FACK;
}
More information about the wx-dev
mailing list