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