]>
Commit | Line | Data |
---|---|---|
68a602fc VZ |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: msw/snglinst.cpp | |
3 | // Purpose: implements wxSingleInstanceChecker class for Win32 using | |
4 | // named mutexes | |
5 | // Author: Vadim Zeitlin | |
6 | // Modified by: | |
7 | // Created: 08.06.01 | |
8 | // RCS-ID: $Id$ | |
9 | // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> | |
10 | // License: wxWindows license | |
11 | /////////////////////////////////////////////////////////////////////////////// | |
12 | ||
13 | // ============================================================================ | |
14 | // declarations | |
15 | // ============================================================================ | |
16 | ||
17 | // ---------------------------------------------------------------------------- | |
18 | // headers | |
19 | // ---------------------------------------------------------------------------- | |
20 | ||
21 | #ifdef __GNUG__ | |
22 | #pragma implementation "snglinst.h" | |
23 | #endif | |
24 | ||
25 | // For compilers that support precompilation, includes "wx.h". | |
26 | #include "wx/wxprec.h" | |
27 | ||
28 | #ifdef __BORLANDC__ | |
29 | #pragma hdrstop | |
30 | #endif | |
31 | ||
32 | #if wxUSE_SNGLINST_CHECKER && defined(__WIN32__) | |
33 | ||
34 | #ifndef WX_PRECOMP | |
35 | #include "wx/string.h" | |
36 | #include "wx/log.h" | |
37 | #endif //WX_PRECOMP | |
38 | ||
39 | #include "wx/snglinst.h" | |
40 | ||
41 | #include "wx/msw/private.h" | |
42 | ||
d08d71a8 CE |
43 | //variables held in common by the callback and wxSingleInstanceCheckerImpl |
44 | static HWND FirsthWnd; | |
45 | static wxString s_Title; | |
46 | ||
47 | // callback to look for windows whose titles include the search string | |
48 | // BCC (at least) does not like the callback to be part of the class :-(( | |
49 | bool CALLBACK EnumWindowsProc ( HWND hwnd, LPARAM lParam ) | |
50 | { | |
51 | // Get the title of this window | |
52 | int iTitleLen = ::GetWindowTextLength(hwnd); | |
53 | // possible UNICODE/ANSI bug here, see SDK documentation, | |
54 | // so allow extra space | |
55 | char * cTitle = new char [iTitleLen*2+10] ; | |
56 | ::GetWindowText(hwnd, cTitle, iTitleLen*2+10); | |
57 | ||
58 | bool bSuccess = wxString(cTitle).Contains(s_Title) ; | |
59 | delete [] cTitle ; | |
60 | ||
61 | if (bSuccess) | |
62 | { | |
63 | FirsthWnd = hwnd ; | |
64 | return FALSE ; | |
65 | } | |
66 | else | |
67 | { | |
68 | //not this window | |
69 | return TRUE; | |
70 | } | |
71 | ||
72 | } | |
73 | ||
68a602fc VZ |
74 | // ---------------------------------------------------------------------------- |
75 | // wxSingleInstanceCheckerImpl: the real implementation class | |
76 | // ---------------------------------------------------------------------------- | |
77 | ||
78 | class WXDLLEXPORT wxSingleInstanceCheckerImpl | |
79 | { | |
80 | public: | |
81 | wxSingleInstanceCheckerImpl() | |
82 | { | |
83 | // we don't care about m_wasOpened, it can't be accessed before being | |
84 | // initialized | |
85 | m_hMutex = NULL; | |
86 | } | |
87 | ||
88 | bool Create(const wxString& name) | |
89 | { | |
90 | m_hMutex = ::CreateMutex(NULL, FALSE, name); | |
91 | if ( !m_hMutex ) | |
92 | { | |
93 | wxLogLastError(_T("CreateMutex")); | |
94 | ||
95 | return FALSE; | |
96 | } | |
97 | ||
98 | // mutex was either created or opened - see what really happened | |
99 | m_wasOpened = ::GetLastError() == ERROR_ALREADY_EXISTS; | |
100 | ||
101 | return TRUE; | |
102 | } | |
103 | ||
104 | bool WasOpened() const | |
105 | { | |
106 | wxCHECK_MSG( m_hMutex, FALSE, | |
107 | _T("can't be called if mutex creation failed") ); | |
108 | ||
109 | return m_wasOpened; | |
d08d71a8 CE |
110 | }; |
111 | ||
112 | ||
113 | ||
114 | // Activates Previous Instance if a window matching Title is found | |
115 | bool ActivatePrevInstance(const wxString & sSearch) | |
116 | { | |
117 | //store search text and window handle for use by callback | |
118 | s_Title = sSearch ; | |
119 | FirsthWnd = 0; | |
120 | ||
121 | EnumWindows (WNDENUMPROC(&EnumWindowsProc), 0L); | |
122 | if (FirsthWnd == 0) | |
123 | { | |
124 | //no matching window found | |
125 | return FALSE; | |
126 | } | |
127 | ||
128 | if (::IsIconic(FirsthWnd)) | |
129 | { | |
130 | ::ShowWindow(FirsthWnd, SW_SHOWDEFAULT); | |
131 | } | |
132 | ::SetForegroundWindow(FirsthWnd); | |
133 | ||
134 | // now try to deal with any active children | |
135 | // Handles to child of previous instance | |
136 | HWND FirstChildhWnd; | |
137 | ||
138 | FirstChildhWnd = ::GetLastActivePopup(FirsthWnd); | |
139 | if (FirsthWnd != FirstChildhWnd) | |
140 | { | |
141 | // A pop-up is active so bring it to the top too. | |
142 | ::BringWindowToTop(FirstChildhWnd); | |
143 | } | |
144 | return TRUE; | |
145 | } | |
146 | ||
147 | // Activates Previous Instance and passes CommandLine to wxCommandLineEvent | |
148 | // if a window matching Title is found | |
149 | bool PassCommandLineToPrevInstance(const wxString & sTitle, const wxString & sCmdLine) | |
150 | { | |
151 | // this stores a string of up to 255 bytes | |
152 | //ATOM myAtom = GlobalAddAtom ( sCmdLine ); | |
153 | ||
154 | // this would create a call to wxWindow::OnCommandLine(wxCommandLineEvent & event) | |
155 | // which should retrieve the commandline, and then delete the atom, GlobalDeleteAtom( myAtom ); | |
156 | //::SendMessage (FirsthWnd, wxCOMMANDLINE_MESSAGE, 0, myAtom) ; | |
157 | return FALSE; | |
68a602fc VZ |
158 | } |
159 | ||
160 | ~wxSingleInstanceCheckerImpl() | |
161 | { | |
162 | if ( m_hMutex ) | |
163 | { | |
164 | if ( !::CloseHandle(m_hMutex) ) | |
165 | { | |
166 | wxLogLastError(_T("CloseHandle(mutex)")); | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | private: | |
172 | // the result of the CreateMutex() call | |
173 | bool m_wasOpened; | |
174 | ||
175 | // the mutex handle, may be NULL | |
176 | HANDLE m_hMutex; | |
d08d71a8 | 177 | |
68a602fc VZ |
178 | }; |
179 | ||
180 | // ============================================================================ | |
181 | // wxSingleInstanceChecker implementation | |
182 | // ============================================================================ | |
183 | ||
184 | bool wxSingleInstanceChecker::Create(const wxString& name, | |
d699f48b | 185 | const wxString& WXUNUSED(path)) |
68a602fc VZ |
186 | { |
187 | wxASSERT_MSG( !m_impl, | |
188 | _T("calling wxSingleInstanceChecker::Create() twice?") ); | |
189 | ||
190 | // creating unnamed mutex doesn't have the same semantics! | |
191 | wxASSERT_MSG( !name.empty(), _T("mutex name can't be empty") ); | |
192 | ||
193 | m_impl = new wxSingleInstanceCheckerImpl; | |
194 | ||
195 | return m_impl->Create(name); | |
196 | } | |
197 | ||
198 | bool wxSingleInstanceChecker::IsAnotherRunning() const | |
199 | { | |
200 | wxCHECK_MSG( m_impl, FALSE, _T("must call Create() first") ); | |
201 | ||
202 | // if the mutex had been opened, another instance is running - otherwise we | |
203 | // would have created it | |
204 | return m_impl->WasOpened(); | |
205 | } | |
206 | ||
d08d71a8 CE |
207 | // Activates Previous Instance if a window whose Title contains the search string is found |
208 | bool wxSingleInstanceChecker::ActivatePrevInstance(const wxString & sSearch) | |
209 | { | |
210 | if (!IsAnotherRunning()) | |
211 | { | |
212 | return FALSE; | |
213 | } | |
214 | return m_impl->ActivatePrevInstance(sSearch) ; | |
215 | } | |
216 | ||
217 | // Activates Previous Instance and passes CommandLine to wxCommandLineEvent | |
218 | // if a window matching Title is found | |
219 | bool wxSingleInstanceChecker::PassCommandLineToPrevInstance(const wxString & sSearch, const wxString & sCmdLine) | |
220 | { | |
221 | if (!ActivatePrevInstance(sSearch)) | |
222 | { | |
223 | return FALSE; | |
224 | } | |
225 | return m_impl->PassCommandLineToPrevInstance(sSearch, sCmdLine); | |
226 | } | |
227 | ||
68a602fc VZ |
228 | wxSingleInstanceChecker::~wxSingleInstanceChecker() |
229 | { | |
230 | delete m_impl; | |
231 | } | |
232 | ||
233 | #endif // wxUSE_SNGLINST_CHECKER |