]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/wxsocket/client.cpp
wxLongLongWx::Assign(double) works - thanks Guillermo
[wxWidgets.git] / samples / wxsocket / client.cpp
index e2bfdf6201b442f6b8d9e474fcf64b6c26a26b5c..2dba5c91b393b96851e3fc5608618d2c8f4d0c2d 100644 (file)
-/*
- * File:       client.cpp
- * Purpose:    wxSocket: client demo
- * Author:     LAVAUX Guilhem (from minimal.cc)
- * Created:    June 1997
- * Updated:    
- * Copyright:  (c) 1993, AIAI, University of Edinburgh
- *             (C) 1997, LAVAUX Guilhem
- */
+/////////////////////////////////////////////////////////////////////////////
+// Name:        client.cpp
+// Purpose:     Client for wxSocket demo
+// Author:      Guillermo Rodriguez Garcia <guille@iies.es>
+// Modified by:
+// Created:     1999/09/19
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 Guillermo Rodriguez Garcia
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ==========================================================================
+// declarations
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// headers
+// --------------------------------------------------------------------------
+
 #ifdef __GNUG__
-#pragma implementation
-#pragma interface
+#  pragma implementation "client.cpp"
+#  pragma interface "client.cpp"
 #endif
 
-// For compilers that support precompilation, includes "wx.h".
+// For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+#  pragma hdrstop
 #endif
 
+// for all others, include the necessary headers 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+#  include "wx/wx.h"
 #endif
-#include "wx/socket.h"
-#include "wx/url.h"
-#include "wx/protocol/http.h"
-
-// Define a new application type
-class MyApp: public wxApp
-{ public:
-    virtual bool OnInit(void);
-};
 
-class MyClient;
+#  include "wx/socket.h"
+#  include "wx/url.h"
+#  include "wx/protocol/http.h"
+#  include "wx/progdlg.h"
 
-// Define a new frame type
-class MyFrame: public wxFrame
-{ 
-  DECLARE_CLASS(MyFrame)
-public:
-  MyClient *sock;
-
-  MyFrame(void);
-  virtual ~MyFrame();
-  void OnCloseTest(wxCommandEvent& evt);
-  void OnExecTest1(wxCommandEvent& evt);
-  void OnExecUrlTest(wxCommandEvent& evt);
-  void OnQuitApp(wxCommandEvent& evt);
-  void OnExecOpenConnection(wxCommandEvent& evt);
-  void OnExecCloseConnection(wxCommandEvent& evt);
-  void UpdateStatus();
-
-  DECLARE_EVENT_TABLE()
-};
+// --------------------------------------------------------------------------
+// resources
+// --------------------------------------------------------------------------
 
+// the application icon
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+#  include "mondrian.xpm"
+#endif
 
-IMPLEMENT_CLASS(MyFrame, wxFrame)
+// --------------------------------------------------------------------------
+// classes
+// --------------------------------------------------------------------------
 
-/*
- * Define a new derived SocketClient
- */
-class MyClient: public wxSocketClient
+// Define a new application type
+class MyApp : public wxApp
 {
 public:
-  MyFrame *frame;
+  virtual bool OnInit();
+};
 
-  void OnNotify(wxRequestNotify WXUNUSED(flags)) { frame->UpdateStatus(); }
+// Define a new frame type: this is going to be our main frame
+class MyFrame : public wxFrame
+{
+public:
+  MyFrame();
+  ~MyFrame();
+
+  // event handlers (these functions should _not_ be virtual)
+  void OnQuit(wxCommandEvent& event);
+  void OnAbout(wxCommandEvent& event);
+  void OnOpenConnection(wxCommandEvent& event);
+  void OnTest1(wxCommandEvent& event);
+  void OnTest2(wxCommandEvent& event);
+  void OnTest3(wxCommandEvent& event);
+  void OnCloseConnection(wxCommandEvent& event);
+  void OnSocketEvent(wxSocketEvent& event);
+
+  // convenience functions
+  void UpdateStatusBar();
+
+private:
+  wxSocketClient *m_sock;
+  wxPanel        *m_panel;
+  wxTextCtrl     *m_text;
+  wxMenu         *m_menuFile;
+  wxMenu         *m_menuSocket;
+  wxMenuBar      *m_menuBar;
+  bool            m_busy;
+
+  // any class wishing to process wxWindows events must use this macro
+  DECLARE_EVENT_TABLE()
 };
 
-// ID for the menu quit command
-const SKDEMO_QUIT    = 101;
-const SKDEMO_CONNECT = 102;
-const SKDEMO_TEST1   = 103;
-const SKDEMO_TEST2   = 104;
-const SKDEMO_CLOSE   = 105;
-const SKDEMO_TEST3   = 106;
-const ID_TEST_CLOSE  = 107;
+// --------------------------------------------------------------------------
+// constants
+// --------------------------------------------------------------------------
 
-IMPLEMENT_APP(MyApp)
-
-/*
- * `Main program' equivalent, creating windows and returning main app frame
- */
-bool MyApp::OnInit(void)
+// IDs for the controls and the menu commands
+enum
 {
-  // Create the main frame window
-  MyFrame *frame = new MyFrame();
-
-  // Give it an icon
-#ifdef wx_msw
-  frame->SetIcon(new wxIcon("mondrian"));
-#endif
-#ifdef wx_x
-  frame->SetIcon(new wxIcon("mondrian.xbm"));
-#endif
+  // menu items
+  CLIENT_QUIT = 1000,
+  CLIENT_ABOUT,
+  CLIENT_OPEN,
+  CLIENT_TEST1,
+  CLIENT_TEST2,
+  CLIENT_TEST3,
+  CLIENT_CLOSE,
+
+  // id for socket
+  SOCKET_ID
+};
 
-  // Make a menubar
-  wxMenu *file_menu = new wxMenu();
+// --------------------------------------------------------------------------
+// event tables and other macros for wxWindows
+// --------------------------------------------------------------------------
 
-  file_menu->Append(SKDEMO_QUIT, "Exit");
-  wxMenuBar *menu_bar = new wxMenuBar;
-  menu_bar->Append(file_menu, "File");
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+  EVT_MENU(CLIENT_QUIT,  MyFrame::OnQuit)
+  EVT_MENU(CLIENT_ABOUT, MyFrame::OnAbout)
+  EVT_MENU(CLIENT_OPEN,  MyFrame::OnOpenConnection)
+  EVT_MENU(CLIENT_TEST1, MyFrame::OnTest1)
+  EVT_MENU(CLIENT_TEST2, MyFrame::OnTest2)
+  EVT_MENU(CLIENT_TEST3, MyFrame::OnTest3)
+  EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection)
+  EVT_SOCKET(SOCKET_ID,  MyFrame::OnSocketEvent)
+END_EVENT_TABLE()
 
-  wxMenu *socket_menu = new wxMenu();
-  socket_menu->Append(SKDEMO_CONNECT, "Open session");
-  socket_menu->AppendSeparator();
-  socket_menu->Append(SKDEMO_TEST1, "Start test 1");
-  socket_menu->Append(SKDEMO_TEST2, "Start test 2");
-  socket_menu->AppendSeparator();
-  socket_menu->Append(SKDEMO_CLOSE, "Close session");
-  socket_menu->AppendSeparator();
-  socket_menu->Append(SKDEMO_TEST3, "Start URL test");
+IMPLEMENT_APP(MyApp)
 
-  menu_bar->Append(socket_menu, "Socket");
+// ==========================================================================
+// implementation
+// ==========================================================================
 
-  frame->SetMenuBar(menu_bar);
+// --------------------------------------------------------------------------
+// the application class
+// --------------------------------------------------------------------------
 
-  // Make a panel with a message
-  (void)new wxPanel(frame, 0, 0, 300, 100);
+bool MyApp::OnInit()
+{
+  // Create the main application window
+  MyFrame *frame = new MyFrame();
 
-  // Show the frame
+  // Show it and tell the application that it's our main window
   frame->Show(TRUE);
-  
-  // Return the main frame window
+  SetTopWindow(frame);
+
+  // success
   return TRUE;
 }
 
-/*
- * MyFrame Constructor
- */
-MyFrame::MyFrame():
-  wxFrame(NULL, -1, "wxSocket client demo",
-          wxDefaultPosition, wxSize(300, 200), wxDEFAULT_FRAME_STYLE)
+// --------------------------------------------------------------------------
+// main frame
+// --------------------------------------------------------------------------
+
+// frame constructor
+MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1,
+                             _T("wxSocket demo: Client"),
+                             wxDefaultPosition, wxSize(300, 200))
 {
-  // Init all
-  wxSocketHandler::Master();
-
-  sock = new MyClient();
-  sock->SetFlags(wxSocketBase::WAITALL);
-  wxSocketHandler::Master().Register(sock);
-  sock->frame = this;
-  sock->SetNotify(wxSocketBase::REQ_LOST);
+  // Give the frame an icon
+  SetIcon(wxICON(mondrian));
+
+  // Make menus
+  m_menuFile = new wxMenu();
+  m_menuFile->Append(CLIENT_ABOUT, _T("&About...\tCtrl-A"), _T("Show about dialog"));
+  m_menuFile->AppendSeparator();
+  m_menuFile->Append(CLIENT_QUIT, _T("E&xit\tAlt-X"), _T("Quit client"));
+
+  m_menuSocket = new wxMenu();
+  m_menuSocket->Append(CLIENT_OPEN, _T("&Open session"), _T("Connect to server"));
+  m_menuSocket->AppendSeparator();
+  m_menuSocket->Append(CLIENT_TEST1, _T("Test &1"), _T("Test basic functionality"));
+  m_menuSocket->Append(CLIENT_TEST2, _T("Test &2"), _T("Test ReadMsg and WriteMsg"));
+  m_menuSocket->Append(CLIENT_TEST3, _T("Test &3"), _T("Test large data transfer"));
+  m_menuSocket->AppendSeparator();
+  m_menuSocket->Append(CLIENT_CLOSE, _T("&Close session"), _T("Close connection"));
+
+  // Append menus to the menubar
+  m_menuBar = new wxMenuBar();
+  m_menuBar->Append(m_menuFile, _T("&File"));
+  m_menuBar->Append(m_menuSocket, _T("&Socket"));
+  SetMenuBar(m_menuBar);
+
+  // Status bar
   CreateStatusBar(2);
-  UpdateStatus();
+
+  // Make a panel with a textctrl in it
+  m_panel = new wxPanel(this, -1, wxPoint(0, 0), GetClientSize());
+  m_text  = new wxTextCtrl(m_panel, -1,
+                           _T("Welcome to wxSocket demo: Client\n")
+                           _T("Client ready\n\n"),
+                           wxPoint(0, 0), m_panel->GetClientSize(),
+                           wxTE_MULTILINE | wxTE_READONLY);
+
+  // Create the socket
+  m_sock = new wxSocketClient();
+  m_sock->SetEventHandler(*this, SOCKET_ID);
+  m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG |
+                    wxSOCKET_INPUT_FLAG |
+                    wxSOCKET_LOST_FLAG);
+  m_sock->Notify(TRUE);
+
+  m_busy = FALSE;
+  UpdateStatusBar();
 }
 
 MyFrame::~MyFrame()
 {
-  delete sock;
+  delete m_sock;
 }
 
-void MyFrame::OnQuitApp(wxCommandEvent& WXUNUSED(evt))
+// event handlers
+
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
+  // TRUE is to force the frame to close
   Close(TRUE);
 }
 
-void MyFrame::OnExecOpenConnection(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+  wxMessageBox(_T("wxSocket demo: Client\n")
+               _T("(c) 1999 Guillermo Rodriguez Garcia\n"),
+               _T("About Client"),
+               wxOK | wxICON_INFORMATION, this);
+}
+
+void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
 {
   wxIPV4address addr;
-    
-  if (sock->IsConnected())
-    sock->Close();
 
-  wxString hname = wxGetTextFromUser("Enter the address of the wxSocket Sample Server", 
-                                  "Connect ...", "localhost");
-  addr.Hostname(hname);
+  m_menuSocket->Enable(CLIENT_OPEN, FALSE);
+  m_menuSocket->Enable(CLIENT_CLOSE, FALSE);
+
+  // Ask server address
+  wxString hostname = wxGetTextFromUser(
+    _T("Enter the address of the wxSocket demo server:"),
+    _T("Connect ..."),
+    _T("localhost"));
+
+  addr.Hostname(hostname);
   addr.Service(3000);
-  sock->SetNotify(0);
-  sock->Connect(addr, TRUE);
-  if (!sock->IsConnected())
-    wxMessageBox("Can't connect to the specified host", "Alert !");
 
-  UpdateStatus();
+  // Non-blocking connect
+  m_text->AppendText(_T("Trying to connect (timeout = 10 sec) ...\n"));
+  m_sock->Connect(addr, FALSE);
+  m_sock->WaitOnConnect(10);
+
+  if (m_sock->IsConnected())
+    m_text->AppendText(_T("Succeeded ! Connection established\n"));
+  else
+  {
+    m_sock->Close();
+    m_text->AppendText(_T("Failed ! Unable to connect\n"));
+    wxMessageBox(_T("Can't connect to the specified host"), _T("Alert !"));
+  }
+  
+  UpdateStatusBar();
 }
 
-void MyFrame::OnExecCloseConnection(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
 {
-  if (sock)
-    sock->Close();
-  UpdateStatus();
-}
+  char *buf1, *buf2;
+  char len;
+
+  // Disable socket menu entries (exception: Close Session)
+  m_busy = TRUE;
+  UpdateStatusBar();
+
+  m_text->AppendText(_T("\n=== Test 1 begins ===\n"));
+
+  // Tell the server which test we are running
+  char c = 0xBE;
+  m_sock->Write(&c, 1);
+
+  // Send some data and read it back. We know the size of the
+  // buffer, so we can specify the exact number of bytes to be
+  // sent or received and use the WAITALL flag. Also, we have
+  // disabled menu entries which could interfere with the test,
+  // so we can safely avoid the BLOCK (formerly SPEED) flag.
+  //
+  // First we send a byte with the length of the string, then
+  // we send the string itself (do NOT try to send any integral
+  // value larger than a byte "as is" acrosss the network, or
+  // you might be in trouble! Ever heard about big and little
+  // endian computers?)
+  //
+  m_sock->SetFlags(wxSOCKET_WAITALL);
+
+  buf1 = _T("Test string (less than 127 chars!)");
+  len  = wxStrlen(buf1) + 1;
+  buf2 = new char[len];
+
+  m_text->AppendText(_T("Sending a test buffer to the server ..."));
+  m_sock->Write(&len, 1);
+  m_sock->Write(buf1, len);
+  m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+
+  m_text->AppendText(_T("Receiving the buffer back from server ..."));
+  m_sock->Read(buf2, len);
+  m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+
+  m_text->AppendText(_T("Comparing the two buffers ..."));
+  if (memcmp(buf1, buf2, len) != 0)
+  {
+    m_text->AppendText(_T("failed!\n"));
+    m_text->AppendText(_T("Test 1 failed !\n"));
+  }
+  else
+  {
+    m_text->AppendText(_T("done\n"));
+    m_text->AppendText(_T("Test 1 passed !\n"));
+  }
+  m_text->AppendText(_T("=== Test 1 ends ===\n"));
 
-BEGIN_EVENT_TABLE(MyFrame, wxFrame)
-  EVT_BUTTON(ID_TEST_CLOSE, MyFrame::OnCloseTest)
-  EVT_MENU(SKDEMO_TEST1, MyFrame::OnExecTest1)
-  EVT_MENU(SKDEMO_TEST3, MyFrame::OnExecUrlTest)
-  EVT_MENU(SKDEMO_QUIT, MyFrame::OnQuitApp)
-  EVT_MENU(SKDEMO_CONNECT, MyFrame::OnExecOpenConnection)
-  EVT_MENU(SKDEMO_CLOSE, MyFrame::OnExecCloseConnection)
-END_EVENT_TABLE()
+  delete[] buf2;
+  m_busy = FALSE;
+  UpdateStatusBar();
+}
 
-void MyFrame::OnCloseTest(wxCommandEvent& evt)
+void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
 {
-  wxButton *button = (wxButton *)evt.GetEventObject();
-  wxDialog *dlg = (wxDialog *)button->GetParent();
+  char *msg1;
+  char *msg2;
+  size_t len;
+
+  // Disable socket menu entries (exception: Close Session)
+  m_busy = TRUE;
+  UpdateStatusBar();
+
+  m_text->AppendText(_T("\n=== Test 2 begins ===\n"));
+
+  // Tell the server which test we are running
+  char c = 0xCE;
+  m_sock->Write(&c, 1);
+
+  // Here we use ReadMsg and WriteMsg to send messages with
+  // a header with size information. Also, the reception is
+  // event triggered, so we test input events as well.
+  //
+  // We need to set no flags here (ReadMsg and WriteMsg are
+  // not affected by flags)
+  //
+  m_sock->SetFlags(wxSOCKET_WAITALL);
+
+  wxString s = wxGetTextFromUser(
+    _T("Enter an arbitrary string to send to the server:"),
+    _T("Test 2 ..."),
+    _T("Yes I like wxWindows!"));
+
+  msg1 = (char *)s.c_str();
+  len  = wxStrlen(msg1) + 1;
+  msg2 = (char *)malloc(len);
+
+  m_text->AppendText(_T("Sending the string with WriteMsg ..."));
+  m_sock->WriteMsg(msg1, len);
+  m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+  m_text->AppendText(_T("Waiting for an event (timeout = 2 sec)\n"));
+
+  // Wait until data available (will also return if the connection is lost)
+  m_sock->WaitForRead(2);
+
+  if (m_sock->IsData())
+  {
+    m_text->AppendText(_T("Reading the string back with ReadMsg ..."));
+    m_sock->ReadMsg(msg2, len);
+    m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+    m_text->AppendText(_T("Comparing the two buffers ..."));
+    if (memcmp(msg1, msg2, len) != 0)
+    {
+      m_text->AppendText(_T("failed!\n"));  
+      m_text->AppendText(_T("Test 2 failed !\n"));
+    }
+    else
+    {
+      m_text->AppendText(_T("done\n"));
+      m_text->AppendText(_T("Test 2 passed !\n"));
+    }
+  }
+  else
+    m_text->AppendText(_T("Timeout ! Test 2 failed.\n"));
+
+  m_text->AppendText(_T("=== Test 2 ends ===\n"));
 
-  dlg->EndModal(0);
+  free(msg2);
+  m_busy = FALSE;
+  UpdateStatusBar();
 }
 
-void MyFrame::UpdateStatus()
+void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
 {
-  if (!sock->IsConnected()) {
-    SetStatusText("Not connected", 0);
-    SetStatusText("", 1);
-  } else {
-    wxIPV4address addr;
-    char s[100];
-
-    sock->GetPeer(addr);
-    sprintf(s, "Connected to %s", (const char *)addr.Hostname());
-    SetStatusText(s, 0);
-    sprintf(s, "Service: %d", addr.Service());
-    SetStatusText(s, 1);
-  } 
+  m_text->AppendText(_T("\n=== Test 3 begins ===\n"));
+  m_text->AppendText(_T("Test 3 not implemented\n"));
+  m_text->AppendText(_T("=== Test 3 ends ===\n"));
 }
 
-void MyFrame::OnExecTest1(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
 {
-  if (!sock->IsConnected())
-    return;
-
-  wxDialog *dlgbox = new wxDialog(this, -1, "Test 1", wxDefaultPosition, wxSize(410, 270));
-  wxTextCtrl *text_win = new wxTextCtrl(dlgbox, -1, "",
-                                        wxPoint(0, 0), wxSize(400, 200),
-                                       wxTE_MULTILINE);
-  (void)new wxButton(dlgbox, ID_TEST_CLOSE, "Close",
-                     wxPoint(100, 210), wxSize(100, 40));
-  char *buf, *buf2;
+  m_sock->Close();
+  UpdateStatusBar();
+}
 
-  dlgbox->Layout();
-  dlgbox->Show(TRUE);
+void MyFrame::OnSocketEvent(wxSocketEvent& event)
+{
+  wxString s = _T("OnSocketEvent: ");
+
+  switch(event.SocketEvent())
+  {
+    case wxSOCKET_INPUT      : s.Append(_T("wxSOCKET_INPUT\n")); break;
+    case wxSOCKET_LOST       : s.Append(_T("wxSOCKET_LOST\n")); break;
+    case wxSOCKET_CONNECTION : s.Append(_T("wxSOCKET_CONNECTION\n")); break;
+    default                  : s.Append(_T("Unexpected event !\n")); break;
+  }
 
-  text_win->WriteText("Initializing test 1 ...\n");
-  
-  /* Init */
-  buf = copystring("Salut ! Salut ! Salut ! Salut Toto\n");
-  buf2 = new char[strlen(buf)+1];
-  char c = 0xbe;
-  sock->WriteMsg(&c, 1);
-
-  /* No 1 */
-  text_win->WriteText("Sending some byte to the server ...");
-  sock->Write(buf, strlen(buf)+1);
-  text_win->WriteText("done\n");
-  text_win->WriteText("Receiving some byte from the server ...");
-  sock->Read(buf2, strlen(buf)+1);
-  text_win->WriteText("done\n");
-  
-  text_win->WriteText("Comparing the two buffers ...");
-  if (memcmp(buf, buf2, strlen(buf)+1) != 0) {
-    text_win->WriteText("Fail\n");
-    sock->Close();
-    UpdateStatus();
-  } else
-    text_win->WriteText("done\nTest 1 passed !\n");
-
-  dlgbox->Layout();
-  dlgbox->ShowModal();
-
-  delete [] buf;
-  delete [] buf2;
-  delete text_win;
-  delete dlgbox;
+  m_text->AppendText(s);
+  UpdateStatusBar();
 }
 
-void MyFrame::OnExecUrlTest(wxCommandEvent& WXUNUSED(evt))
+// convenience functions
+
+void MyFrame::UpdateStatusBar()
 {
-  wxString urlname = wxGetTextFromUser("Enter the address of the wxSocket Sample Server",
-                                     "Connect ...", "localhost");
+  wxString s;
 
-  wxURL url(urlname);
-  wxInputStream *datas = url.GetInputStream();
+  if (!m_sock->IsConnected())
+  {
+    s.Printf(_T("Not connected"));
+  }
+  else
+  {
+    wxIPV4address addr;
 
-  if (!datas)
-    wxMessageBox("Error in getting data from the URL.", "Alert !");
-  else {
-    wxMessageBox("Success !!", "OK !");
-    delete datas;
+    m_sock->GetPeer(addr);
+    s.Printf(_T("%s : %d"), (addr.Hostname()).c_str(), addr.Service());
   }
+
+  SetStatusText(s, 1);
+
+  m_menuSocket->Enable(CLIENT_OPEN, !m_sock->IsConnected() && !m_busy);
+  m_menuSocket->Enable(CLIENT_TEST1, m_sock->IsConnected() && !m_busy);
+  m_menuSocket->Enable(CLIENT_TEST2, m_sock->IsConnected() && !m_busy);
+  m_menuSocket->Enable(CLIENT_TEST3, m_sock->IsConnected() && !m_busy);
+  m_menuSocket->Enable(CLIENT_CLOSE, m_sock->IsConnected());
 }