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