]> git.saurik.com Git - wxWidgets.git/commitdiff
Applied patch [ 600051 ] DDE and TCP improvements and fixes
authorJulian Smart <julian@anthemion.co.uk>
Sun, 1 Sep 2002 14:48:16 +0000 (14:48 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Sun, 1 Sep 2002 14:48:16 +0000 (14:48 +0000)
By Michael Fielding

As discussed on wx-dev. some fixes and improvements for Interprocess Communication (IPC), using DDE and TCP.

1. DDE buffers were using a global buffer
2. TCP buffers were allocated each time needed, and Request would have caused memory leaks had it been used.

Fixed these both by using a self-resizing buffer in wxConnectionBase. Changed samples and docs to reflect the improved (but backward compatible) internal buffer management. wxConnectionBase could (in future) use wxMemoryBuffer.

3. IPC sample had trouble closing, causing crash, when closing server using window X button.

Because it was (effectively) trying to delete a window in OnExit, when that window was already destroyed. Fixed by making IPCDialog and MyConnection remember if they'd destroyed each other. It's not elegant, but either the connection or the window could be deleted first.

4. Docs for wxDDE... and wxTCP... duplicated eachother, supposed to have same API. Some parts unclear.

Patch removes dde and tcp-specific files (including from tipc.tex and classes.tex), and explains how ipc.h selects for you which one to use based on platform. Some other misc clarifications.

6. Client sample was suffering apparent memory leak because of not deleting connection object, and had a hack in there to do that.

In fact this was due to the derived OnDisconnect not deleting itself, as it does in base class. Mentioned need to do it in docs, fixed sample so that it does.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16907 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

16 files changed:
docs/changes.txt
docs/latex/wx/app.tex
docs/latex/wx/category.tex
docs/latex/wx/classes.tex
docs/latex/wx/ddeclint.tex
docs/latex/wx/ddeconn.tex
docs/latex/wx/ddeservr.tex
docs/latex/wx/tipc.tex
docs/latex/wx/ttips.tex
include/wx/ipcbase.h
include/wx/sckipc.h
samples/ipc/client.cpp
samples/ipc/client.h
samples/ipc/server.cpp
samples/ipc/server.h
src/msw/dde.cpp

index c54f4eced2baf3bc6f72e2cd6c1275c1b5c3e596..216d413a037dc95177913a9610bd001954656f5f 100644 (file)
@@ -49,6 +49,8 @@ wxBase:
   must modify YourApp::OnAssert() signature if you were using it to override
   the default assert handling.
 
+- IPC classes improved and memory leaks fixed (Michael Fielding).
+  Global buffer removed, duplication in docs removed.
 
 All (GUI):
 
index ce7e8e44ca75509f1191ec5bef20a7cd5f1bc87e..080164f33c681ac154d1fa0bdb9d155eca5977d7 100644 (file)
@@ -633,3 +633,4 @@ Calling Yield() recursively is normally an error and an assert failure is
 raised in debug build if such situation is detected. However if the the 
 {\it onlyIfNeeded} parameter is {\tt TRUE}, the method will just silently
 return {\tt FALSE} instead.
+
index 22c8f7f5c25474008f1e5f985931c7a96bb21b00..85ddafa64c01de14546dd1b72b1f76f15ab27f24 100644 (file)
@@ -211,7 +211,7 @@ An event object contains information about a specific event. Event handlers
 \twocolitem{\helpref{wxDropFilesEvent}{wxdropfilesevent}}{A drop files event}
 \twocolitem{\helpref{wxEraseEvent}{wxeraseevent}}{An erase background event}
 \twocolitem{\helpref{wxEvent}{wxevent}}{The event base class}
-\twocolitem{\helpref{wxFindDialogEvent}{wxfinddialogevent}}{Event sent by 
+\twocolitem{\helpref{wxFindDialogEvent}{wxfinddialogevent}}{Event sent by
 \helpref{wxFindReplaceDialog}{wxfindreplacedialog}}
 \twocolitem{\helpref{wxFocusEvent}{wxfocusevent}}{A window focus event}
 \twocolitem{\helpref{wxKeyEvent}{wxkeyevent}}{A keypress event}
@@ -366,17 +366,14 @@ wxWindows provides its own classes for socket based networking.
 
 \overview{Overview}{ipcoverview}
 
-wxWindows provides simple interprocess communications facilities
-based on DDE.
+wxWindows provides simple interprocess communications facilities
+based on Windows DDE, but available on most platforms using TCP.
 
 \twocolwidtha{6cm}
 \begin{twocollist}\itemsep=0pt
-\twocolitem{\helpref{wxDDEClient}{wxddeclient}}{Represents a client}
-\twocolitem{\helpref{wxDDEConnection}{wxddeconnection}}{Represents the connection between a client and a server}
-\twocolitem{\helpref{wxDDEServer}{wxddeserver}}{Represents a server}
-\twocolitem{\helpref{wxTCPClient}{wxtcpclient}}{Represents a client}
-\twocolitem{\helpref{wxTCPConnection}{wxtcpconnection}}{Represents the connection between a client and a server}
-\twocolitem{\helpref{wxTCPServer}{wxtcpserver}}{Represents a server}
+\twocolitem{\helpref{wxClient}{wxddeclient}}{Represents a client}
+\twocolitem{\helpref{wxConnection}{wxddeconnection}}{Represents the connection between a client and a server}
+\twocolitem{\helpref{wxServer}{wxddeserver}}{Represents a server}
 %\twocolitem{\helpref{wxSocketHandler}{wxsockethandler}}{Represents a socket handler}
 \end{twocollist}
 
@@ -623,4 +620,3 @@ using any of them in new programs:
 \twocolitem{\helpref{wxQuantize}{wxquantize}}{Class to perform quantization, or colour reduction}
 \twocolitem{\helpref{wxSingleInstanceChecker}{wxsingleinstancechecker}}{Check that only single program instance is running}
 \end{twocollist}
-
index cceb0de09d527ec898594dcb2eaddd367e667aea..6e6487a91f2d2956ddb96b1e38f48cfbfabb701f 100644 (file)
@@ -29,6 +29,7 @@
 \input checklst.tex
 \input choice.tex
 \input clasinfo.tex
+\input ipcclint.tex
 \input clientdc.tex
 \input clientdat.tex
 \input clipbrd.tex
@@ -42,6 +43,7 @@
 \input cmdproc.tex
 \input conditn.tex
 \input config.tex
+\input ipcconn.tex
 \input cshelp.tex
 \input control.tex
 \input countstr.tex
@@ -62,9 +64,6 @@
 \input datetime.tex
 \input db.tex
 \input dc.tex
-\input ddeclint.tex
-\input ddeconn.tex
-\input ddeservr.tex
 \input debugcxt.tex
 \input dialog.tex
 \input dialevt.tex
 \input scrolevt.tex
 \input scrlwevt.tex
 \input semaphor.tex
+\input ipcservr.tex
 \input hprovsmp.tex
 \input sngchdlg.tex
 \input snglinst.tex
 \input tabctrl.tex
 \input tabevent.tex
 \input taskbar.tex
-\input tcpclint.tex
-\input tcpconn.tex
-\input tcpservr.tex
 \input tempfile.tex
 \input text.tex
 \input txtdatob.tex
 \input xmlresh.tex
 \input zipstrm.tex
 \input strmzlib.tex
-
index 2f5fc7a858af3b02a7d52289c2ccacaa52a3d027..81f7508d3dd4cfe7fc3c1354c1a8061c6e0e6b65 100644 (file)
@@ -69,4 +69,3 @@ store application-specific data in instances of the new class.
 Returns TRUE if this is a valid host name, FALSE otherwise. This always
 returns TRUE under MS Windows.
 
-
index 0be17834bcf5997be9dbc424d5b4790ee3a6f79d..1436df1220bf3a1df516f62fcfceba22e2ea66fc 100644 (file)
@@ -199,4 +199,3 @@ Called by the client application to ask if an advise loop can be
 stopped. Causes the server connection's \helpref{wxDDEConnection::OnStopAdvise}{wxddeconnectiononstopadvise} member
 to be called. Returns TRUE if the server okays it, FALSE otherwise.
 
-
index 700632f3c37c1236b7cb2a7b95d9e954829d4bbb..73aefdf50aa84f32f769b079acacb67ba531e41f 100644 (file)
@@ -49,4 +49,3 @@ Under UNIX, when a server is created the OnAcceptConnection message is
 always sent for standard input and output, but in the context of DDE
 messages it doesn't make a lot of sense.
 
-
index 6ad9d56b77bc8e2ff63c29976099263fa96c2e99..4360c0d7ea8e85ec25c58afb53070da65583c973 100644 (file)
 \section{Interprocess communication overview}\label{ipcoverview}
 
-Classes: \helpref{wxDDEServer}{wxddeserver}, \helpref{wxDDEConnection}{wxddeconnection}, 
-\helpref{wxDDEClient}{wxddeclient}, 
-\helpref{wxTCPServer}{wxtcpserver}, \helpref{wxTCPConnection}{wxtcpconnection}, 
-\helpref{wxTCPClient}{wxtcpclient}
+Classes: \helpref{wxServer}{wxddeserver},
+\helpref{wxConnection}{wxddeconnection},
+\helpref{wxClient}{wxddeclient}
+%\helpref{wxTCPServer}{wxtcpserver}, \helpref{wxTCPConnection}{wxtcpconnection},
+%\helpref{wxTCPClient}{wxtcpclient}
 
-wxWindows has a number of different classes to help with interprocess communication
-and network programming. This section only discusses one family of classes - the DDE-like
-protocol - but here's a list of other useful classes:
+wxWindows has a number of different classes to help with
+interprocess communication and network programming. This section
+only discusses one family of classes -- the DDE-like protocol --
+but here's a list of other useful classes:
 
 \begin{itemize}\itemsep=0pt
-\item \helpref{wxSocketEvent}{wxsocketevent}, 
-\helpref{wxSocketBase}{wxsocketbase}, 
-\helpref{wxSocketClient}{wxsocketclient}, 
+\item \helpref{wxSocketEvent}{wxsocketevent},
+\helpref{wxSocketBase}{wxsocketbase},
+\helpref{wxSocketClient}{wxsocketclient},
 \helpref{wxSocketServer}{wxsocketserver}: classes for the low-level TCP/IP API.
-\item \helpref{wxProtocol}{wxprotocol}, \helpref{wxURL}{wxurl}, \helpref{wxFTP}{wxftp}, wxHTTP: classes
+\item \helpref{wxProtocol}{wxprotocol}, \helpref{wxURL}{wxurl}, \helpref{wxFTP}{wxftp}, \helpref{wxHTTP}{wxhttp}: classes
 for programming popular Internet protocols.
 \end{itemize}
 
-Further information on these classes will be available in due course.
+wxWindows' DDE-like protocol is a high-level protocol based on
+Windows DDE. There are two implementations of this DDE-like
+protocol: one using real DDE running on Windows only, and another
+using TCP/IP (sockets) that runs on most platforms. Since the API
+and virtually all of the behaviour is the same apart from the
+names of the classes, you should find it easy to switch between
+the two implementations.
 
-Notice that by including {\tt <wx/ipc.h>} you may define convnient synonyms for
-the IPC classes: {\tt wxServer} for either {\tt wxDDEServer} or 
-{\tt wxTCPServer} depending on whether DDE-based or socket-based implementation
-is used and the same thing for {\tt wxClient} and {\tt wxConnection}. By
-default, DDE implementation is used under Windows. If you want to use IPC
-between the different workstations you should define {\tt wxUSE\_DDE\_FOR\_IPC}
-as $0$ before including this header -- this will force using TCP/IP
-implementation even under Windows.
+Notice that by including {\tt <wx/ipc.h>} you may define
+convenient synonyms for the IPC classes: {\tt wxServer} for either
+{\tt wxDDEServer} or {\tt wxTCPServer} depending on whether
+DDE-based or socket-based implementation is used and the same
+thing for {\tt wxClient} and {\tt wxConnection}.
 
+By default, DDE implementation is used under Windows. DDE works
+only within one computer. If you want to use IPC between
+different workstations you should define {\tt
+wxUSE\_DDE\_FOR\_IPC} as $0$ before including this header -- this
+will force using TCP/IP implementation even under Windows.
 
-wxWindows has a high-level protocol based on Windows DDE.
-There are two implementations of this DDE-like protocol:
-one using real DDE running on Windows only, and another using TCP/IP (sockets) that runs
-on most platforms. Since the API is the same apart from the names of the classes, you
-should find it easy to switch between the two implementations.
+The following description refers to wx... but remember that the
+equivalent wxTCP... and wxDDE... classes can be used in much the
+same way.
 
-The following description refers to 'DDE' but remember that the equivalent wxTCP... classes
-can be used in much the same way.
-
-Three classes are central to the DDE API:
+Three classes are central to the DDE-like API:
 
 \begin{enumerate}\itemsep=0pt
-\item wxDDEClient. This represents the client application, and is used
+\item wxClient. This represents the client application, and is used
 only within a client program.
-\item wxDDEServer. This represents the server application, and is used
+\item wxServer. This represents the server application, and is used
 only within a server program.
-\item wxDDEConnection. This represents the connection from the current
-client or server to the other application (server or client), and can be used
-in both server and client programs. Most DDE
-transactions operate on this object.
+\item wxConnection. This represents the connection from the
+client to the server - both the client and the server use an
+instance of this class, one per connection. Most DDE transactions
+operate on this object.
 \end{enumerate}
 
-Messages between applications are usually identified by three variables:
-connection object, topic name and item name.  A data string is a fourth
-element of some messages. To create a connection (a conversation in
-Windows parlance), the client application sends the message
-MakeConnection to the client object, with a string service name to
-identify the server and a topic name to identify the topic for the
-duration of the connection. Under Unix, the service name may be either an
-integer port identifier in which case an Internet domain socket will be used
-for the communications or a valid file name (which shouldn't exist and will be
-deleted afterwards) in which case a Unix domain socket is created.
+Messages between applications are usually identified by three
+variables: connection object, topic name and item name.  A data
+string is a fourth element of some messages. To create a
+connection (a conversation in Windows parlance), the client
+application uses wxClient::MakeConnection to send a message to the
+server object, with a string service name to identify the server
+and a topic name to identify the topic for the duration of the
+connection. Under Unix, the service name may be either an integer
+port identifier in which case an Internet domain socket will be
+used for the communications or a valid file name (which shouldn't
+exist and will be deleted afterwards) in which case a Unix domain
+socket is created.
 
 {\bf SECURITY NOTE:} Using Internet domain sockets if extremely insecure for
 IPC as there is absolutely no access control for them, use Unix domain sockets
 whenever possible!
 
-The server then responds and either vetoes the connection or allows it.
-If allowed, a connection object is created which persists until the
-connection is closed.  The connection object is then used for subsequent
-messages between client and server.
+The server then responds and either vetoes the connection or
+allows it. If allowed, both the server and client objects create
+wxConnection objects which persist until the connection is
+closed. The connection object is then used for sending and
+receiving subsequent messages between client and server -
+overriding virtual functions in your class derived from
+wxConnection allows you to handle the DDE messages.
 
 To create a working server, the programmer must:
 
 \begin{enumerate}\itemsep=0pt
-\item Derive a class from wxDDEServer.
-\item Override the handler OnAcceptConnection for accepting or rejecting a connection,
-on the basis of the topic argument. This member must create and return a connection
-object if the connection is accepted.
-\item Create an instance of your server object, and call Create to
+\item Derive a class from wxConnection, providing handlers for various messages sent to the server
+side of a wxConnection (e.g. OnExecute, OnRequest, OnPoke). Only
+the handlers actually required by the application need to be
+overridden.
+\item Derive a class from wxServer, overriding OnAcceptConnection
+to accept or reject a connection on the basis of the topic
+argument. This member must create and return an instance of the
+derived connection class if the connection is accepted.
+\item Create an instance of your server object and call Create to
 activate it, giving it a service name.
-\item Derive a class from wxDDEConnection.
-\item Provide handlers for various messages that are sent to the server
-side of a wxDDEConnection.
 \end{enumerate}
 
 To create a working client, the programmer must:
 
 \begin{enumerate}\itemsep=0pt
-\item Derive a class from wxDDEClient.
-\item Override the handler OnMakeConnection to create and return
-an appropriate connection object.
+\item Derive a class from wxConnection, providing handlers for various
+messages sent to the client side of a wxConnection (e.g.
+OnAdvise). Only the handlers actually required by the application
+need to be overridden.
+\item Derive a class from wxClient, overriding OnMakeConnection to
+create and return an instance of the derived connection class.
 \item Create an instance of your client object.
-\item Derive a class from wxDDEConnection.
-\item Provide handlers for various messages that are sent to the client
-side of a wxDDEConnection.
-\item When appropriate, create a new connection by sending a MakeConnection
-message to the client object, with arguments host name (processed in Unix only),
-service name, and topic name for this connection. The client object will call OnMakeConnection
-to create a connection object of the desired type.
-\item Use the wxDDEConnection member functions to send messages to the server.
+\item When appropriate, create a new connection using
+\helpref{wxClient::MakeConnection}{wxddeclientmakeconnection},
+with arguments host name (processed in Unix only, use `localhost'
+for local computer), service name, and topic name for this
+connection. The client object will call
+\helpref{OnMakeConnection}{wxddeclientonmakeconnection} to create
+a connection object of the derived class if the connection is
+successful.
+\item Use the wxConnection member functions to send messages to the server.
 \end{enumerate}
 
 \subsection{Data transfer}
 
-These are the ways that data can be transferred from one application to
-another.
+These are the ways that data can be transferred from one
+application to another. These are methods of wxConnection.
 
 \begin{itemize}\itemsep=0pt
 \item {\bf Execute:} the client calls the server with a data string representing
@@ -140,31 +155,31 @@ that item to be highlighted in the client list box.
 
 \subsection{More DDE details}
 
-A wxDDEClient object represents the client part of a client-server DDE
-(Dynamic Data Exchange) conversation (available in both
+A wxClient object initiates the client part of a client-server
+DDE-like (Dynamic Data Exchange) conversation (available in both
 Windows and Unix).
 
 To create a client which can communicate with a suitable server,
-you need to derive a class from wxDDEConnection and another from wxDDEClient.
-The custom wxDDEConnection class will intercept communications in
-a `conversation' with a server, and the custom wxDDEServer is required
-so that a user-overridden \helpref{wxDDEClient::OnMakeConnection}{wxddeclientonmakeconnection} member can return
-a wxDDEConnection of the required class, when a connection is made.
+you need to derive a class from wxConnection and another from
+wxClient. The custom wxConnection class will receive
+communications in a `conversation' with a server.  and the custom
+wxServer is required so that a user-overridden
+\helpref{wxDDEClient::OnMakeConnection}{wxddeclientonmakeconnection}
+member can return a wxDDEConnection of the required class, when a
+connection is made.
 
 For example:
 
 \begin{verbatim}
-class MyConnection: public wxDDEConnection
-{
+class MyConnection: public wxConnection {
  public:
-  MyConnection(void)::wxDDEConnection(ipc_buffer, 3999) {}
+  MyConnection(void)::wxConnection() {}
   ~MyConnection(void) { }
   bool OnAdvise(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format)
   { wxMessageBox(topic, data); }
 };
 
-class MyClient: public wxDDEClient
-{
+class MyClient: public wxClient {
  public:
   MyClient(void) {}
   wxConnectionBase *OnMakeConnection(void) { return new MyConnection; }
@@ -172,15 +187,20 @@ class MyClient: public wxDDEClient
 
 \end{verbatim}
 
-Here, {\bf MyConnection} will respond to \helpref{OnAdvise}{wxddeconnectiononadvise} messages sent
-by the server.
-
-When the client application starts, it must create an instance of the derived wxDDEClient. In the following, command line
-arguments are used to pass the host name (the name of the machine the server is running
-on) and the server name (identifying the server process). Calling \helpref{wxDDEClient::MakeConnection}{wxddeclientmakeconnection}\rtfsp
-implicitly creates an instance of {\bf MyConnection} if the request for a
-connection is accepted, and the client then requests an {\it Advise} loop
-from the server, where the server calls the client when data has changed.
+Here, {\bf MyConnection} will respond to
+\helpref{OnAdvise}{wxddeconnectiononadvise} messages sent by the
+server by displaying a message box.
+
+When the client application starts, it must create an instance of
+the derived wxClient. In the following, command line arguments
+are used to pass the host name (the name of the machine the
+server is running on) and the server name (identifying the server
+process). Calling
+\helpref{wxDDEClient::MakeConnection}{wxddeclientmakeconnection}\rtfsp
+implicitly creates an instance of {\bf MyConnection} if the
+request for a connection is accepted, and the client then
+requests an {\it Advise} loop from the server (an Advise loop is
+where the server calls the client when data has changed).
 
 \begin{verbatim}
   wxString server = "4242";
index 5dac6dd9113f39e01f89f2a6e8f86c2b61c5c4b0..3548a7d56a973cc0d241bd7b614ccceda75040ee 100644 (file)
@@ -48,10 +48,12 @@ skipped.
 You can easily add runtime-translation capacity by placing each line of the 
 tips.txt file inside the usual translation macro. For example, your tips.txt 
 file would look like this:
+
 \begin{verbatim}
 _("This is my first tip")
 _("This is my second tip")
 \end{verbatim}
+
 Now add your tips.txt file into the list of files that gettext searches 
 for translatable strings. The tips will thus get included into your 
 generated .po file catalog and be translated at runtime along with the rest of 
@@ -64,3 +66,4 @@ a backslash-doublequote.
 
 See the dialogs program in your samples folder for a working example inside a 
 program.
+
index 819c6f50cf5f7213353683a2633c52fea01cc2a8..61a0c283d8a16de38a41e396f369a05089f300f7 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     4/1/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:    wxWindows license
+// Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
 #ifndef _WX_IPCBASEH__
@@ -50,8 +50,13 @@ class WXDLLEXPORT wxConnectionBase: public wxObject
   DECLARE_CLASS(wxConnectionBase)
 
 public:
-  inline wxConnectionBase(void) {}
-  inline ~wxConnectionBase(void) {}
+  wxConnectionBase(wxChar *buffer, int size); // use external buffer
+  wxConnectionBase(); // use internal, adaptive buffer
+  wxConnectionBase(wxConnectionBase& copy);
+  ~wxConnectionBase(void);
+
+  void SetConnected( bool c ) { m_connected = c; }
+  bool GetConnected() { return m_connected; }
 
   // Calls that CLIENT can make
   virtual bool Execute(const wxChar *data, int size = -1, wxIPCFormat format = wxIPC_TEXT ) = 0;
@@ -106,8 +111,20 @@ public:
   // Callbacks to BOTH - override at will
   // Default behaviour is to delete connection and return TRUE
   virtual bool OnDisconnect(void) = 0;
+
+  // return a buffer at least this size, reallocating buffer if needed
+  // returns NULL if using an inadequate user buffer - it can't be resized
+  wxChar *      GetBufferAtLeast( size_t bytes );
+
+protected:
+  bool          m_connected;
+private:
+  wxChar *      m_buffer;
+  size_t        m_buffersize;
+  bool          m_deletebufferwhendone;
 };
 
+
 class WXDLLEXPORT wxServerBase: public wxObject
 {
   DECLARE_CLASS(wxServerBase)
index 50e4c18494035023ad89a52e2a51f955e8a83b6a..548d0723d332c62e1cbe2be0b34689e31b16fca2 100644 (file)
@@ -61,7 +61,7 @@ class WXDLLEXPORT wxTCPConnection: public wxConnectionBase
   DECLARE_DYNAMIC_CLASS(wxTCPConnection)
 
 public:
-  wxTCPConnection(char *buffer, int size);
+  wxTCPConnection(wxChar *buffer, int size);
   wxTCPConnection();
   virtual ~wxTCPConnection();
 
index f4d1711fe519180db35495ed0048943e74a37ccd..be407db5abe34fdc71d1bc24258058c24076ca28 100644 (file)
@@ -30,7 +30,6 @@
 
 // Settings common to both executables: determines whether
 // we're using TCP/IP or real DDE.
-
 #include "ddesetup.h"
 
 #if defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) || defined(__WXMAC__)
@@ -56,7 +55,6 @@ END_EVENT_TABLE()
 // globals
 // ----------------------------------------------------------------------------
 
-char ipc_buffer[4000];
 wxListBox *the_list = NULL;
 
 MyConnection *the_connection = NULL;
@@ -119,16 +117,11 @@ bool MyApp::OnInit()
 
 int MyApp::OnExit()
 {
-    if (the_connection)
-    {
-        the_connection->Disconnect();
-        delete the_connection;
-        the_connection = NULL;
-    }
-
     // will delete the connection too
     // Update: Seems it didn't delete the_connection, because there's a leak.
     // Deletion is now explicitly done a few lines up.
+    // another Update: in fact it's because OnDisconnect should delete it, but
+    // it wasn't
     delete my_client;
 
 
@@ -203,11 +196,6 @@ wxConnectionBase *MyClient::OnMakeConnection()
     return new MyConnection;
 }
 
-MyConnection::MyConnection()
-            : wxConnection(ipc_buffer, WXSIZEOF(ipc_buffer))
-{
-}
-
 bool MyConnection::OnAdvise(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format)
 {
     if (the_list)
@@ -221,10 +209,13 @@ bool MyConnection::OnAdvise(const wxString& topic, const wxString& item, char *d
 
 bool MyConnection::OnDisconnect()
 {
+    // when connection is terminated, quit whole program
     wxWindow *win = wxTheApp->GetTopWindow();
     if ( win )
         win->Destroy();
 
-    return TRUE;
+    // delete self
+    the_connection = NULL;
+    return wxConnection::OnDisconnect();
 }
 
index aae6609c419e391d657e70a830845937b50df901..5131e1ca4545e6d3256410ea44f55f4dab6d919b 100644 (file)
@@ -37,8 +37,6 @@ private:
 class MyConnection: public wxConnection
 {
 public:
-    MyConnection();
-
     bool OnAdvise(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format);
     bool OnDisconnect();
 };
index 0c91c8df457136295b81d0182662f380ab759c18..1f4a3b63fe3666983758489081177625d8629fe2 100644 (file)
@@ -57,7 +57,6 @@ END_EVENT_TABLE()
 // global variables
 // ----------------------------------------------------------------------------
 
-char ipc_buffer[4000];
 MyConnection *the_connection = NULL;
 
 // ============================================================================
@@ -134,6 +133,9 @@ void MyFrame::OnListBoxClick(wxCommandEvent& WXUNUSED(event))
     if (listBox)
     {
         wxString value = listBox->GetStringSelection();
+
+        /* Because the_connection only holds one connection, in this sample only
+           one connection can receive advise messages */
         if (the_connection)
         {
             the_connection->Advise(IPC_ADVISE_NAME, (wxChar *)value.c_str());
@@ -161,6 +163,14 @@ IPCDialogBox::IPCDialogBox(wxWindow *parent, const wxString& title,
     Fit();
 }
 
+IPCDialogBox::~IPCDialogBox( )
+{
+    // wxWindows exit code destroys dialog before destroying the connection in
+    // OnExit, so make sure connection won't try to delete the dialog later.
+    if (m_connection)
+        m_connection->dialog = NULL;
+}
+
 void IPCDialogBox::OnQuit(wxCommandEvent& event)
 {
     m_connection->Disconnect();
@@ -174,7 +184,7 @@ void IPCDialogBox::OnQuit(wxCommandEvent& event)
 wxConnectionBase *MyServer::OnAcceptConnection(const wxString& topic)
 {
     if ( topic == IPC_TOPIC )
-        return new MyConnection(ipc_buffer, WXSIZEOF(ipc_buffer));
+        return new MyConnection();
 
     // unknown topic
     return NULL;
@@ -184,8 +194,8 @@ wxConnectionBase *MyServer::OnAcceptConnection(const wxString& topic)
 // MyConnection
 // ----------------------------------------------------------------------------
 
-MyConnection::MyConnection(char *buf, int size)
-            : wxConnection(buf, size)
+MyConnection::MyConnection()
+            : wxConnection()
 {
     dialog = new IPCDialogBox(wxTheApp->GetTopWindow(), "Connection",
                               wxPoint(100, 100), wxSize(500, 500), this);
@@ -197,7 +207,11 @@ MyConnection::~MyConnection()
 {
     if (the_connection)
     {
-        dialog->Destroy();
+        if (dialog)
+        {
+            dialog->m_connection = NULL;
+            dialog->Destroy();
+        }
         the_connection = NULL;
     }
 }
index ac85cd4b0d1969c4fcd332d220f3f2907245f469..93de320cc30a8ec70a590ab3f8c7a1fd676731e2 100644 (file)
@@ -42,7 +42,7 @@ class IPCDialogBox;
 class MyConnection : public wxConnection
 {
 public:
-    MyConnection(char *buf, int size);
+    MyConnection();
     ~MyConnection();
 
     bool OnExecute(const wxString& topic, char *data, int size, wxIPCFormat format);
@@ -50,7 +50,6 @@ public:
     bool OnPoke(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format);
     bool OnStartAdvise(const wxString& topic, const wxString& item);
 
-private:
     IPCDialogBox *dialog;
 };
 
@@ -68,10 +67,10 @@ public:
                  const wxPoint& pos,
                  const wxSize& size,
                  MyConnection *the_connection);
+    ~IPCDialogBox( );
 
     void OnQuit(wxCommandEvent& event);
 
-private:
     MyConnection *m_connection;
 
     DECLARE_EVENT_TABLE()
index 063a74b067c7240f9e395a807caa5e1d484dd955..0787b6d5400aa911ce1be96859e1d16810d440e7 100644 (file)
@@ -133,8 +133,6 @@ static wxList wxAtomTable(wxKEY_STRING);
 static wxList wxDDEClientObjects;
 static wxList wxDDEServerObjects;
 
-char *DDEDefaultIPCBuffer = NULL;
-int DDEDefaultIPCBufferSize = 0;
 static bool DDEInitialized = FALSE;
 
 // ----------------------------------------------------------------------------
@@ -198,8 +196,6 @@ void wxDDECleanUp()
         DdeUninitialize(DDEIdInst);
         DDEIdInst = 0;
     }
-
-    delete [] DDEDefaultIPCBuffer;
 }
 
 // ----------------------------------------------------------------------------
@@ -314,6 +310,7 @@ wxDDEServer::~wxDDEServer()
     {
         wxDDEConnection *connection = (wxDDEConnection *)node->Data();
         wxNode *next = node->Next();
+        connection->SetConnected(false);
         connection->OnDisconnect(); // May delete the node implicitly
         node = next;
     }
@@ -463,20 +460,8 @@ bool wxDDEClient::DeleteConnection(WXHCONV conv)
 // ----------------------------------------------------------------------------
 
 wxDDEConnection::wxDDEConnection(char *buffer, int size)
+     : wxConnectionBase(buffer, size)
 {
-    if (buffer == NULL)
-    {
-        if (DDEDefaultIPCBuffer == NULL)
-            DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
-        m_bufPtr = DDEDefaultIPCBuffer;
-        m_bufSize = DDEDefaultIPCBufferSize;
-    }
-    else
-    {
-        m_bufPtr = buffer;
-        m_bufSize = size;
-    }
-
     m_client = NULL;
     m_server = NULL;
 
@@ -485,20 +470,17 @@ wxDDEConnection::wxDDEConnection(char *buffer, int size)
 }
 
 wxDDEConnection::wxDDEConnection()
+     : wxConnectionBase()
 {
     m_hConv = 0;
     m_sendingData = NULL;
     m_server = NULL;
     m_client = NULL;
-    if (DDEDefaultIPCBuffer == NULL)
-        DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize];
-
-    m_bufPtr = DDEDefaultIPCBuffer;
-    m_bufSize = DDEDefaultIPCBufferSize;
 }
 
 wxDDEConnection::~wxDDEConnection()
 {
+    Disconnect();
     if (m_server)
         m_server->GetConnections().DeleteObject(this);
     else
@@ -508,6 +490,9 @@ wxDDEConnection::~wxDDEConnection()
 // Calls that CLIENT can make
 bool wxDDEConnection::Disconnect()
 {
+    if ( !GetConnected() )
+        return true;
+
     DDEDeleteConnection(GetHConv());
 
     bool ok = DdeDisconnect(GetHConv()) != 0;
@@ -516,6 +501,8 @@ bool wxDDEConnection::Disconnect()
         DDELogError(_T("Failed to disconnect from DDE server gracefully"));
     }
 
+    SetConnected( false );  // so we don't try and disconnect again
+
     return ok;
 }
 
@@ -546,6 +533,7 @@ bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
 char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format)
 {
     DWORD result;
+
     HSZ atom = DDEGetAtom(item);
 
     HDDEDATA returned_data = DdeClientTransaction(NULL, 0,
@@ -561,14 +549,19 @@ char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat form
         return NULL;
     }
 
-    DWORD len = DdeGetData(returned_data, (LPBYTE)m_bufPtr, m_bufSize, 0);
+    DWORD len = DdeGetData(returned_data, NULL, 0, 0);
+
+    wxChar *data = GetBufferAtLeast( len );
+    wxASSERT_MSG(data != NULL,
+                 _T("Buffer too small in wxDDEConnection::Request") );
+    DdeGetData(returned_data, (LPBYTE)data, len, 0);
 
     DdeFreeDataHandle(returned_data);
 
     if (size)
         *size = (int)len;
 
-    return m_bufPtr;
+    return data;
 }
 
 bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format)
@@ -645,7 +638,7 @@ bool wxDDEConnection::Advise(const wxString& item,
 
     HSZ item_atom = DDEGetAtom(item);
     HSZ topic_atom = DDEGetAtom(m_topicName);
-    m_sendingData = data;
+    m_sendingData = data;  // mrf: potential for scope problems here?
     m_dataSize = size;
     m_dataType = format;
 
@@ -718,10 +711,14 @@ _DDECallback(WORD wType,
         case XTYP_DISCONNECT:
             {
                 wxDDEConnection *connection = DDEFindConnection(hConv);
-                if (connection && connection->OnDisconnect())
+                if (connection)
                 {
-                    DDEDeleteConnection(hConv);  // Delete mapping: hConv => connection
-                    return (DDERETURN)(DWORD)TRUE;
+                    connection->SetConnected( false );
+                    if (connection->OnDisconnect())
+                    {
+                        DDEDeleteConnection(hConv);  // Delete mapping: hConv => connection
+                        return (DDERETURN)(DWORD)TRUE;
+                    }
                 }
                 break;
             }
@@ -732,13 +729,18 @@ _DDECallback(WORD wType,
 
                 if (connection)
                 {
-                    DWORD len = DdeGetData(hData,
-                                           (LPBYTE)connection->m_bufPtr,
-                                           connection->m_bufSize,
-                                           0);
+                    DWORD len = DdeGetData(hData, NULL, 0, 0);
+
+                    wxChar *data = connection->GetBufferAtLeast( len );
+                    wxASSERT_MSG(data != NULL,
+                                 _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") );
+
+                    DdeGetData(hData, (LPBYTE)data, len, 0);
+
                     DdeFreeDataHandle(hData);
+
                     if ( connection->OnExecute(connection->m_topicName,
-                                               connection->m_bufPtr,
+                                               data,
                                                (int)len,
                                                (wxIPCFormat) wFmt) )
                     {
@@ -788,15 +790,19 @@ _DDECallback(WORD wType,
                 {
                     wxString item_name = DDEStringFromAtom(hsz2);
 
-                    DWORD len = DdeGetData(hData,
-                                           (LPBYTE)connection->m_bufPtr,
-                                           connection->m_bufSize,
-                                           0);
+                    DWORD len = DdeGetData(hData, NULL, 0, 0);
+
+                    wxChar *data = connection->GetBufferAtLeast( len );
+                    wxASSERT_MSG(data != NULL,
+                                 _T("Buffer too small in _DDECallback (XTYP_EXECUTE)") );
+
+                    DdeGetData(hData, (LPBYTE)data, len, 0);
+
                     DdeFreeDataHandle(hData);
 
                     connection->OnPoke(connection->m_topicName,
                                        item_name,
-                                       (wxChar*)connection->m_bufPtr,
+                                       data,
                                        (int)len,
                                        (wxIPCFormat) wFmt);
 
@@ -871,14 +877,18 @@ _DDECallback(WORD wType,
                 {
                     wxString item_name = DDEStringFromAtom(hsz2);
 
-                    DWORD len = DdeGetData(hData,
-                                           (LPBYTE)connection->m_bufPtr,
-                                           connection->m_bufSize,
-                                           0);
+                    DWORD len = DdeGetData(hData, NULL, 0, 0);
+
+                    wxChar *data = connection->GetBufferAtLeast( len );
+                    wxASSERT_MSG(data != NULL,
+                                 _T("Buffer too small in _DDECallback (XTYP_ADVDATA)") );
+
+                    DdeGetData(hData, (LPBYTE)data, len, 0);
+
                     DdeFreeDataHandle(hData);
                     if ( connection->OnAdvise(connection->m_topicName,
                                               item_name,
-                                              connection->m_bufPtr,
+                                              data,
                                               (int)len,
                                               (wxIPCFormat) wFmt) )
                     {