[wx-dev] IPC issues

Brian Vanderburg II BrianVanderburg2 at aim.com
Sat Dec 1 17:03:51 PST 2007


Vadim Zeitlin wrote:
> On Sat, 01 Dec 2007 09:38:39 -0500 Brian Vanderburg II <BrianVanderburg2@=
aim.com> wrote:
>
> BVI> wxString GetDataAsText(const void* data, size_t size, wxIPCFormat fo=
rmat)
> BVI> {
> BVI>     assert(format is valid)
> BVI> =

> BVI>     #if wxUSE_DDE_FOR_IPC
> BVI>        // the received data in GetDdeData is always in the format th=
e =

> BVI> program is in
> BVI>        wxUnusedVar(format)
> BVI>        #if wxUSE_UNICODE
> BVI>           return wxString((wchar_t*)data, size);
> BVI>        #else
> BVI>           return wxString((char*)data, size);
> BVI>        #endif
> BVI>     #else
> BVI>        if(format =3D=3D wxIPC_TEXT)
> BVI>           return wxString((char*)data, wxConvLibc);
> BVI>        else if(format =3D=3D wxIPC_UTF8TEXT)
> BVI>          return wxString((char*)data, wxConvUTF8);
> BVI>       else
> BVI>          return wxString((wchar_t*)data);
> BVI>     #endif
> BVI> }
>
>  In fact thinking more about it (and looking at the code) it seems that it
> should be enough to set the format for DDE correctly, shouldn't it? So I'm
> afraid I'm back to not understanding why exactly doesn't this work
> currently, could you please reexplain? Thanks!
>   =

The code that was patched last makes it where DDE will send in the =

correct format when doing DdeClientTransaction and when receiving, it =

will call OnExecute passing the correct format based on the build.  But =

still, the code in MyConnection::OnExecute can't reliably do if(format =

!=3D wxIPC_TEXT) return false, this is because with DDE in a unicode =

build, it is wxIPC_UNICODETEXT, and in ANSI it is wxIPC_TEXT.  Also =

there is the fact that the OnExecute may not be for DDE but for TCP (if =

the user derived from wxConnection instead of directly from =

wxDDEConnection) and here the format is sent as-is (no behind-the-scenes =

conversion the way Windows does with DDE),  GetTextFromData takes care =

of all of that automatically.

Actually, now that OnExecute does get the correct format in DDE, the =

code above does not need the #if wxUSE_DDE_FOR_IPC  conditional at all.  =

The function simply serves to simplify code so one can do this:

bool MyConnection::OnExecute(const wxString& topic, const void* data, =

size_t size, wxIPCFormat format)
{
    ....

    wxString txt =3D GetTextFromData(data, size, format);
}

Where one may normally have to do this:

bool MyConnection::OnExecute(...)
{  =

    if(format =3D=3D wxIPC_TEXT) // ANSI text (maybe ANSI compiled =

application using DDE or could also be TCPConnection and the client used =

wxIPC_TEXT
    {
    }
    else if(format =3D=3D wxIPC_UNICODETEXT) // Unicode compiled applicatio=
n =

using DDE, or TCP connection and client used wxIPC_UNICODETEXT
    {
    }
    else if(format =3D=3D wxIPC_UTF8TEXT)
    {
         // Sending application sent as wxIPC_UTF8TEXT
    }
}

wxDDEConnection::OnExecute will get data as wxIPC_TEXT in ansi and =

wxIPC_UNICODE_TEXT in unicode build
wxTCPConnection::OnExecute will get data in the format that it was sent =

as from the client, regardless of the build.

So for a derived connection class to be as portable as possible, without =

conditionals for testing, GetTextFromData can be used.

And it will work whether it is a DDE or TCP connection.

If it is wxDDEConnection, then format will always be wxIPC_UNICODETEXT =

in unicode and wxIPC_TEXT in ansi and the function will convert it =

accordingly.  If it is wxTCPConnection, it is possible to send any =

format since it is sent as is.  A client application built in unicode =

can do: Execute("Some action", size of some action), and it will be sent =

as wxIPC_TEXT and the server will get wxIPC_TEXT even it it is build in =

unicode, can use GetTextFromData still to convert it to wxString
> BVI> There is a minor problem with this code.  If an empty string is sent =

> BVI> then the return string IsEmpty should be true, but the size will inc=
lude =

> BVI> the null terminator and so wxString(data, size) will have the extra
> BVI> null that it should not have.  =

>
>  I don't understand this at all: size of empty string is 0 and wxString
> ctor from 0 length should create empty string. Do you say there is a bug =
in
> wxString here?
>   =

No it's not a bug.  When I do Execute("ABC"), it does strlen(data) + 1, =

which is 3 + 1 =3D 4.  Now when receiving it, wxString(data, size), will =

tell it that the size is 4, and will include the null terminator.  =

Simillarly, if I do Execute(""), it does strlen(data) + 1 =3D 0 + 1 =3D 1, =

so the if the server connection does wxString s(data, size), size will =

be 1 so the string will include the null terminator as part of the =

string (an embedded null), and so s.IsEmpty() will return false.
 =

I've attached a 'partial' patch of GetTextFromData

Brian Vanderburg II
-------------- next part --------------
Index: include/wx/ipcbase.h
=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
--- include/wx/ipcbase.h    (revision 50401)
+++ include/wx/ipcbase.h    (working copy)
@@ -166,6 +166,9 @@
   virtual bool OnDisconnect() { delete this; return true; }
 =

 =

+  // Convert passed data to a string
+  wxString GetTextFromData(const void* data, size_t size, wxIPCFormat form=
at);
+
   // return a buffer at least this size, reallocating buffer if needed
   // returns NULL if using an inadequate user buffer which can't be resized
   void *GetBufferAtLeast(size_t bytes);
Index: src/common/ipcbase.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/common/ipcbase.cpp  (revision 50401)
+++ src/common/ipcbase.cpp  (working copy)
@@ -65,6 +65,43 @@
     delete m_buffer;
 }
 =

+// The calls to Execute/Poke/Etc can automatically specify the format.
+// This function makes it so the callbacks can automatically get the
+// string without a bunch of if(format =3D=3D ...) else if(format =3D=3D .=
..)
+wxString wxConnectionBase::GetTextFromData(const void* data, size_t size, =
wxIPCFormat format)
+{
+    wxCHECK_MSG(format =3D=3D wxIPC_TEXT || format =3D=3D wxIPC_UNICODETEX=
T || format =3D=3D wxIPC_UTF8TEXT,
+            wxEmptyString, "wxConnectionBase::GetTextFromData() only suppo=
rted text formats.");
+
+    if(size =3D=3D 0)
+        return wxEmptyString;
+
+    // A small helper
+    #define GTFD_FixSize(fmt, str, len) \
+        { \
+        len /=3D sizeof(fmt); \
+        while(len > 0 && ((fmt*)str)[len - 1] =3D=3D 0) \
+            len--; \
+        }
+
+#if wxUSE_UNICODE_UTF8
+    if(format =3D=3D wxIPC_TEXT || format =3D=3D wxIPC_UTF8TEXT)
+    {
+        GTFD_FixSize(char, data, size);
+        return wxString((char*)data, size);
+    }
+    else
+    {
+        GTFD_FixSize(w_chart, data, size);
+        return wxString((wchar_t*)data, size);
+    }
+#elif wxUSE_UNICODE
+
+#else
+
+#endif
+}
+
 void *wxConnectionBase::GetBufferAtLeast( size_t bytes )
 {
   if ( m_buffersize >=3D bytes )


More information about the wx-dev mailing list