1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // wxFormBuilder - A Visual Dialog Editor for wxWidgets.
4 // Copyright (C) 2005 José Antonio Hurtado
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 //
20 // Written by
21 //   Ryan Mulder - rjmyst3@gmail.com
22 //
23 ///////////////////////////////////////////////////////////////////////////////
24 #include "wx/wxprec.h"
25 
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29 
30 #ifndef WX_PRECOMP
31 #include "wx/wx.h"
32 #endif
33 
34 #include "wxfbipc.h"
35 #include <wx/filename.h>
36 #include "utils/debug.h"
37 
VerifySingleInstance(const wxString & file,bool switchTo)38 bool wxFBIPC::VerifySingleInstance( const wxString& file, bool switchTo )
39 {
40 	// Possible send a message to the running instance through this string later, for now it is left empty
41 	wxString expression = wxEmptyString;
42 
43 	// Make path absolute
44 	wxFileName path( file );
45 	if ( !path.IsOk() )
46 	{
47 		wxLogError( wxT("This path is invalid: %s"), file.c_str() );
48 		return false;
49 	}
50 
51 	if ( !path.IsAbsolute() )
52 	{
53 		if ( !path.MakeAbsolute() )
54 		{
55 			wxLogError( wxT("Could not make path absolute: %s"), file.c_str() );
56 			return false;
57 		}
58 	}
59 
60 	// Check for single instance
61 
62 	// Create lockfile/mutex name
63 	wxString name = wxString::Format( wxT("wxFormBuilder-%s-%s"), wxGetUserId().c_str(), path.GetFullPath().c_str() );
64 
65 	// Get forbidden characters
66 	wxString forbidden = wxFileName::GetForbiddenChars();
67 
68 	// Repace forbidded characters
69 	for ( size_t c = 0; c < forbidden.Length(); ++c )
70 	{
71 		wxString bad( forbidden.GetChar( c ) );
72 		name.Replace( bad.c_str(), wxT("_") );
73 	}
74 
75 	// Paths are not case sensitive in windows
76 	#ifdef __WXMSW__
77 	name = name.MakeLower();
78 	#endif
79 
80 	// GetForbiddenChars is missing "/" in unix. Prepend '.' to make lockfiles hidden
81 	#ifndef __WXMSW__
82 	name.Replace( wxT("/"), wxT("_") );
83 	name.Prepend( wxT(".") );
84 	#endif
85 
86 	// Check to see if I already have a server with this name - if so, no need to make another!
87 	if ( m_server.get() )
88 	{
89 		if ( m_server->m_name == name )
90 		{
91 			return true;
92 		}
93 	}
94 
95     std::auto_ptr< wxSingleInstanceChecker > checker;
96     {
97         // Suspend logging, because error messages here are not useful
98         #ifndef __WXFB_DEBUG__
99         wxLogNull stopLogging;
100         #endif
101         checker.reset( new wxSingleInstanceChecker( name ) );
102     }
103 
104     if ( !checker->IsAnotherRunning() )
105 	{
106 		// This is the first instance of this project, so setup a server and save the single instance checker
107 		if ( CreateServer( name ) )
108 		{
109 			m_checker = checker;
110 			return true;
111 		}
112 		else
113 		{
114 			return false;
115 		}
116 	}
117 	else if ( switchTo )
118     {
119 		// Suspend logging, because error messages here are not useful
120 		#ifndef __WXFB_DEBUG__
121 		wxLogNull stopLogging;
122 		#endif
123 
124 		// There is another app, so connect and send the expression
125 
126 		// Cannot have a client and a server at the same time, due to the implementation of wxTCPServer and wxTCPClient,
127 		// so temporarily drop the server if there is one
128 		bool hadServer = false;
129 		wxString oldName;
130 		if ( m_server.get() != NULL )
131 		{
132 			oldName = m_server->m_name;
133 			m_server.reset();
134 			hadServer = true;
135 		}
136 
137 		// Create the client
138 		std::auto_ptr< AppClient > client( new AppClient );
139 
140 		// Create the connection
141 		std::auto_ptr< wxConnectionBase > connection;
142 		#ifdef __WXMSW__
143 			connection.reset( client->MakeConnection( wxT("localhost"), name, name ) );
144 		#else
145 			bool connected = false;
146 			for ( int i = m_port; i < m_port + 20; ++i )
147 			{
148             #if wxVERSION_NUMBER < 2900
149 				wxString nameWithPort = wxString::Format( wxT("%i%s"), i, name.c_str() );
150 				connection.reset( client->MakeConnection( wxT("127.0.0.1"), nameWithPort, name ) );
151             #else
152                 wxString sPort = wxString::Format( "%i", i );
153                 connection.reset( client->MakeConnection( "localhost", sPort, name ) );
154             #endif
155 				if ( NULL != connection.get() )
156 				{
157 					connected = true;
158 					wxChar* pid = (wxChar*)connection->Request( wxT("PID"), NULL );
159 					if ( NULL != pid )
160 					{
161 						wxLogStatus( wxT("%s already open in process %s"), file.c_str(), pid );
162 					}
163 					break;
164 				}
165 			}
166 			if ( !connected )
167 			{
168 				wxLogError( wxT("There is a lockfile named '%s', but unable to make a connection to that instance."), name.c_str() );
169 			}
170 		#endif
171 
172 		// Drop the connection and client
173 		connection.reset();
174 		client.reset();
175 
176 		// Create the server again, if necessary
177 		if ( hadServer )
178 		{
179 			CreateServer( oldName );
180 		}
181     }
182     return false;
183 }
184 
CreateServer(const wxString & name)185 bool wxFBIPC::CreateServer( const wxString& name )
186 {
187 	// Suspend logging, because error messages here are not useful
188 	#ifndef __WXFB_DEBUG__
189 	wxLogNull stopLogging;
190 	#endif
191 
192 	std::auto_ptr< AppServer > server( new AppServer( name ) );
193 
194 	#ifdef __WXMSW__
195 		if ( server->Create( name ) )
196 		{
197 			m_server = server;
198 			return true;
199 		}
200 	#else
201 	{
202 		for ( int i = m_port; i < m_port + 20; ++i )
203 		{
204 			wxString nameWithPort = wxString::Format( wxT("%i%s"), i, name.c_str() );
205 			if( server->Create( nameWithPort ) )
206 			{
207 				m_server = server;
208 				return true;
209 			}
210 			else
211 			{
212 #if wxVERSION_NUMBER < 2900
213 				LogDebug( wxT("Server Creation Failed. %s"), nameWithPort.c_str() );
214 #else
215 				LogDebug( "Server Creation Failed. " + nameWithPort );
216 #endif
217 			}
218 		}
219 	}
220 	#endif
221 
222 	wxLogError( wxT("Failed to create an IPC service with name %s"), name.c_str() );
223 	return false;
224 }
225 
Reset()226 void wxFBIPC::Reset()
227 {
228 	m_server.reset();
229 	m_checker.reset();
230 }
231 
OnAcceptConnection(const wxString & topic)232 wxConnectionBase* AppServer::OnAcceptConnection( const wxString& topic )
233 {
234 	if ( topic == m_name )
235 	{
236 		wxFrame* frame = wxDynamicCast( wxTheApp->GetTopWindow(), wxFrame );
237 		if ( !frame )
238 		{
239 			return NULL;
240 		}
241 		frame->Enable();
242 
243 		if ( frame->IsIconized() )
244 		{
245 			frame->Iconize( false );
246 		}
247 
248 		frame->Raise();
249 
250 		return new AppConnection;
251 	}
252 
253 	return NULL;
254 }
255 
OnMakeConnection()256 wxConnectionBase* AppClient::OnMakeConnection()
257 {
258 	return new AppConnection;
259 }
260 
261 #if wxVERSION_NUMBER < 2900
OnRequest(const wxString &,const wxString &,int * size,wxIPCFormat)262 wxChar* AppConnection::OnRequest( const wxString& /*topic*/, const wxString& /*item*/, int* size, wxIPCFormat /*format*/ )
263 {
264 	unsigned long pid = ::wxGetProcessId();
265 	if ( 0 == pid )
266 	{
267 		if ( NULL != size )
268 		{
269 			*size = 0;
270 		}
271 		return NULL;
272 	}
273 	else
274 	{
275 		int length = m_data.Printf( wxT("%lu"), pid );
276 		if ( NULL != size )
277 		{
278 			*size = (length + 1) * sizeof(wxChar);
279 		}
280 		return const_cast< wxChar* >( m_data.c_str() );
281 	}
282 }
283 #endif
284