This is a more hackish but more compatible solution to the problem of
data sent using wxIPC_UTF8TEXT format being simply lost when using DDE
for IPC classes. We must use CF_TEXT for the DDE to pass our data, but
we can try to decode it as UTF-8 in the client and assume it was sent in
this format if it worked. This obviously suffers from false positives as
any ASCII string will still be assumed to be UTF-8, but there shouldn't
be any real harm coming from this.
This change also makes sending data in wxIPC_UTF{16,32}TEXT formats work
as well by converting it to UTF-8.
Update the sample to call Advise() with both wxIPC_UTF{8,16}TEXT formats
and remove the now unnecessary wxDDEConnection::m_dataType member.
Closes #17900.
		
	
		
			
				
	
	
		
			392 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			392 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        server.cpp
 | |
| // Purpose:     IPC sample: server
 | |
| // Author:      Julian Smart
 | |
| // Modified by: Jurgen Doornik
 | |
| // Created:     25/01/99
 | |
| // Copyright:   (c) Julian Smart
 | |
| // Licence:     wxWindows licence
 | |
| /////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| // ============================================================================
 | |
| // declarations
 | |
| // ============================================================================
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // headers
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| // For compilers that support precompilation, includes "wx.h".
 | |
| #include "wx/wxprec.h"
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
|     #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #ifndef WX_PRECOMP
 | |
|     #include "wx/wx.h"
 | |
| #endif
 | |
| 
 | |
| // Settings common to both executables: determines whether
 | |
| // we're using TCP/IP or real DDE.
 | |
| #include "ipcsetup.h"
 | |
| 
 | |
| #ifndef wxHAS_IMAGES_IN_RESOURCES
 | |
|     #include "../sample.xpm"
 | |
| #endif
 | |
| 
 | |
| #include "server.h"
 | |
| #include "wx/textdlg.h"
 | |
| #include "wx/datetime.h"
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // wxWin macros
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| wxIMPLEMENT_APP(MyApp);
 | |
| 
 | |
| wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
 | |
|     EVT_CLOSE( MyFrame::OnClose )
 | |
| 
 | |
|     EVT_BUTTON( ID_START,          MyFrame::OnStart )
 | |
|     EVT_CHOICE( ID_SERVERNAME,     MyFrame::OnServerName )
 | |
|     EVT_BUTTON( ID_DISCONNECT,     MyFrame::OnDisconnect )
 | |
|     EVT_BUTTON( ID_ADVISE,         MyFrame::OnAdvise )
 | |
| wxEND_EVENT_TABLE()
 | |
| 
 | |
| 
 | |
| // ============================================================================
 | |
| // implementation
 | |
| // ============================================================================
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // MyApp
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| bool MyApp::OnInit()
 | |
| {
 | |
|     if ( !wxApp::OnInit() )
 | |
|         return false;
 | |
| 
 | |
|     // Create the main frame window
 | |
|     m_frame = new MyFrame(NULL, "Server");
 | |
|     m_frame->Show(true);
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // MyFrame
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| // Define my frame constructor
 | |
| MyFrame::MyFrame(wxFrame *frame, const wxString& title)
 | |
|        : wxFrame(frame, wxID_ANY, title, wxDefaultPosition, wxSize(400, 300))
 | |
| {
 | |
| #if wxUSE_STATUSBAR
 | |
|     CreateStatusBar();
 | |
| #endif // wxUSE_STATUSBAR
 | |
| 
 | |
|     SetIcon(wxICON(sample));
 | |
| 
 | |
|     m_server = NULL;
 | |
| 
 | |
|     wxPanel * const panel = new wxPanel(this);
 | |
| 
 | |
|     wxBoxSizer * const sizerMain = new wxBoxSizer( wxVERTICAL );
 | |
| 
 | |
|     wxFlexGridSizer * const sizerCmds = new wxFlexGridSizer( 2, 0, 0 );
 | |
|     sizerCmds->AddGrowableCol( 1 );
 | |
| 
 | |
|     wxButton *btn;
 | |
| 
 | |
|     btn = new wxButton(panel, ID_START, "&Start Server");
 | |
|     sizerCmds->Add(btn, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5);
 | |
| 
 | |
|     const wxString choices[] = { IPC_SERVICE, "..." };
 | |
|     wxChoice * const choice = new wxChoice
 | |
|                                   (
 | |
|                                     panel,
 | |
|                                     ID_SERVERNAME,
 | |
|                                     wxDefaultPosition, wxSize(100, -1),
 | |
|                                     WXSIZEOF(choices), choices
 | |
|                                   );
 | |
|     sizerCmds->Add(choice, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5);
 | |
| 
 | |
|     btn = new wxButton(panel, ID_DISCONNECT, "&Disconnect Client");
 | |
|     sizerCmds->Add(btn, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5);
 | |
|     sizerCmds->AddSpacer(20);
 | |
| 
 | |
|     btn = new wxButton( panel, ID_ADVISE, "&Advise");
 | |
|     sizerCmds->Add(btn, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5);
 | |
|     sizerCmds->AddSpacer(20);
 | |
| 
 | |
|     sizerMain->Add(sizerCmds, wxSizerFlags().Expand().Border(wxALL, 5));
 | |
| 
 | |
|     wxStaticBoxSizer * const
 | |
|         sizerLog = new wxStaticBoxSizer(wxVERTICAL, panel, "Server &log");
 | |
| 
 | |
|     wxTextCtrl * const textLog = new wxTextCtrl
 | |
|                                  (
 | |
|                                     panel,
 | |
|                                     wxID_ANY,
 | |
|                                     "",
 | |
|                                     wxDefaultPosition, wxSize(500, 140),
 | |
|                                     wxTE_MULTILINE
 | |
|                                  );
 | |
|     sizerLog->Add(textLog, wxSizerFlags(1).Expand().Border(wxALL, 5));
 | |
| 
 | |
|     sizerMain->Add(sizerLog, wxSizerFlags(1).Expand().Border(wxALL, 5));
 | |
| 
 | |
|     panel->SetSizer(sizerMain);
 | |
|     sizerMain->SetSizeHints(panel);
 | |
|     SetClientSize(panel->GetSize());
 | |
| 
 | |
|     GetServername()->SetSelection(0);
 | |
|     wxLogTextCtrl *logWindow = new wxLogTextCtrl(textLog);
 | |
|     delete wxLog::SetActiveTarget(logWindow);
 | |
|     wxLogMessage("Click on Start to start the server");
 | |
|     UpdateUI();
 | |
| }
 | |
| 
 | |
| void MyFrame::UpdateUI()
 | |
| {
 | |
|     GetStart()->Enable(m_server == NULL);
 | |
|     GetServername()->Enable(m_server == NULL);
 | |
|     GetAdvise()->Enable(m_server && m_server->CanAdvise());
 | |
|     GetDisconnect()->Enable(m_server && m_server->IsConnected());
 | |
| }
 | |
| 
 | |
| void MyFrame::OnClose(wxCloseEvent& event)
 | |
| {
 | |
|     wxDELETE(m_server);
 | |
|     event.Skip();
 | |
| }
 | |
| 
 | |
| void MyFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 | |
| {
 | |
|     // Create a new server
 | |
|     m_server = new MyServer;
 | |
|     wxString servername = GetServername()->GetStringSelection();
 | |
|     if (m_server->Create(servername))
 | |
|     {
 | |
|         wxLogMessage("Server %s started", servername);
 | |
|   #if wxUSE_DDE_FOR_IPC
 | |
|         wxLogMessage("Server uses DDE");
 | |
|   #else // !wxUSE_DDE_FOR_IPC
 | |
|         wxLogMessage("Server uses TCP");
 | |
|   #endif // wxUSE_DDE_FOR_IPC/!wxUSE_DDE_FOR_IPC
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         wxLogMessage("Server %s failed to start", servername);
 | |
|         wxDELETE(m_server);
 | |
|     }
 | |
|     UpdateUI();
 | |
| }
 | |
| 
 | |
| void MyFrame::OnServerName( wxCommandEvent& WXUNUSED(event) )
 | |
| {
 | |
|     if ( GetServername()->GetStringSelection() == "..." )
 | |
|     {
 | |
|         wxString s = wxGetTextFromUser
 | |
|                      (
 | |
|                         "Specify the name of the server",
 | |
|                         "Server Name",
 | |
|                         "",
 | |
|                         this
 | |
|                      );
 | |
| 
 | |
|         if ( !s.empty() && s != IPC_SERVICE )
 | |
|         {
 | |
|             GetServername()->Insert(s, 0);
 | |
|             GetServername()->SetSelection(0);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void MyFrame::Disconnect()
 | |
| {
 | |
|     m_server->Disconnect();
 | |
|     UpdateUI();
 | |
| }
 | |
| 
 | |
| void MyFrame::OnDisconnect(wxCommandEvent& WXUNUSED(event))
 | |
| {
 | |
|     Disconnect();
 | |
| }
 | |
| 
 | |
| void MyFrame::OnAdvise(wxCommandEvent& WXUNUSED(event))
 | |
| {
 | |
|     m_server->Advise();
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // MyServer
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| MyServer::MyServer() : wxServer()
 | |
| {
 | |
|     m_connection = NULL;
 | |
| }
 | |
| 
 | |
| MyServer::~MyServer()
 | |
| {
 | |
|     Disconnect();
 | |
| }
 | |
| 
 | |
| wxConnectionBase *MyServer::OnAcceptConnection(const wxString& topic)
 | |
| {
 | |
|     wxLogMessage("OnAcceptConnection(\"%s\")", topic);
 | |
| 
 | |
|     if ( topic == IPC_TOPIC )
 | |
|     {
 | |
|         m_connection = new MyConnection();
 | |
|         wxGetApp().GetFrame()->UpdateUI();
 | |
|         wxLogMessage("Connection accepted");
 | |
|         return m_connection;
 | |
|     }
 | |
|     //else: unknown topic
 | |
| 
 | |
|     wxLogMessage("Unknown topic, connection refused");
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| void MyServer::Disconnect()
 | |
| {
 | |
|     if ( m_connection )
 | |
|     {
 | |
|         wxDELETE(m_connection);
 | |
|         wxGetApp().GetFrame()->UpdateUI();
 | |
|         wxLogMessage("Disconnected client");
 | |
|     }
 | |
| }
 | |
| 
 | |
| void MyServer::Advise()
 | |
| {
 | |
|     if ( CanAdvise() )
 | |
|     {
 | |
|         const wxDateTime now = wxDateTime::Now();
 | |
| 
 | |
|         wxString str = wxString::FromUTF8("\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82");
 | |
|         m_connection->Advise(m_connection->m_advise, str + " (using UTF-8)");
 | |
| 
 | |
|         str += " (using wchar_t)";
 | |
|         m_connection->Advise(m_connection->m_advise,
 | |
|                              str.wc_str(), (str.length() + 1)*sizeof(wchar_t),
 | |
|                              wxIPC_UNICODETEXT);
 | |
| 
 | |
|         // This one uses wxIPC_TEXT by default.
 | |
|         const wxString s = now.FormatTime() + " " + now.FormatDate();
 | |
|         m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN);
 | |
| 
 | |
|         char bytes[3] = { '1', '2', '3' };
 | |
|         m_connection->Advise(m_connection->m_advise, bytes, 3, wxIPC_PRIVATE);
 | |
|     }
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // MyConnection
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| bool
 | |
| MyConnection::OnExecute(const wxString& topic,
 | |
|                         const void *data,
 | |
|                         size_t size,
 | |
|                         wxIPCFormat format)
 | |
| {
 | |
|     Log("OnExecute", topic, "", data, size, format);
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| MyConnection::OnPoke(const wxString& topic,
 | |
|                      const wxString& item,
 | |
|                      const void *data,
 | |
|                      size_t size,
 | |
|                      wxIPCFormat format)
 | |
| {
 | |
|     Log("OnPoke", topic, item, data, size, format);
 | |
|     return wxConnection::OnPoke(topic, item, data, size, format);
 | |
| }
 | |
| 
 | |
| const void *
 | |
| MyConnection::OnRequest(const wxString& topic,
 | |
|                         const wxString& item,
 | |
|                         size_t *size,
 | |
|                         wxIPCFormat format)
 | |
| {
 | |
|     *size = 0;
 | |
| 
 | |
|     wxString s,
 | |
|              afterDate;
 | |
|     if ( item.StartsWith("Date", &afterDate) )
 | |
|     {
 | |
|         const wxDateTime now = wxDateTime::Now();
 | |
| 
 | |
|         if ( afterDate.empty() )
 | |
|         {
 | |
|             s = now.Format();
 | |
|             *size = wxNO_LEN;
 | |
|         }
 | |
|         else if ( afterDate == "+len" )
 | |
|         {
 | |
|             s = now.FormatTime() + " " + now.FormatDate();
 | |
|             *size = strlen(s.mb_str()) + 1;
 | |
|         }
 | |
|     }
 | |
|     else if ( item == "bytes[3]" )
 | |
|     {
 | |
|         s = "123";
 | |
|         *size = 3;
 | |
|     }
 | |
| 
 | |
|     if ( !*size )
 | |
|     {
 | |
|         wxLogMessage("Unknown request for \"%s\"", item);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     // store the data pointer to which we return in a member variable to ensure
 | |
|     // that the pointer remains valid even after we return
 | |
|     m_requestData = s.mb_str();
 | |
|     const void * const data = m_requestData;
 | |
|     Log("OnRequest", topic, item, data, *size, format);
 | |
|     return data;
 | |
| }
 | |
| 
 | |
| bool MyConnection::OnStartAdvise(const wxString& topic, const wxString& item)
 | |
| {
 | |
|     wxLogMessage("OnStartAdvise(\"%s\", \"%s\")", topic, item);
 | |
|     wxLogMessage("Returning true");
 | |
|     m_advise = item;
 | |
|     wxGetApp().GetFrame()->UpdateUI();
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool MyConnection::OnStopAdvise(const wxString& topic, const wxString& item)
 | |
| {
 | |
|     wxLogMessage("OnStopAdvise(\"%s\",\"%s\")", topic, item);
 | |
|     wxLogMessage("Returning true");
 | |
|     m_advise.clear();
 | |
|     wxGetApp().GetFrame()->UpdateUI();
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| MyConnection::DoAdvise(const wxString& item,
 | |
|                        const void *data,
 | |
|                        size_t size,
 | |
|                        wxIPCFormat format)
 | |
| {
 | |
|     Log("Advise", "", item, data, size, format);
 | |
|     return wxConnection::DoAdvise(item, data, size, format);
 | |
| }
 | |
| 
 | |
| bool MyConnection::OnDisconnect()
 | |
| {
 | |
|     wxLogMessage("OnDisconnect()");
 | |
|     wxGetApp().GetFrame()->Disconnect();
 | |
|     return true;
 | |
| }
 |