35
35
36
36
#define CLOSING_PROP L" CLOSING"
37
37
38
+ #define FIRST_INSTANCE_MUTEX_NAME (APP_NAME L" .Shell.Instance" )
39
+ #define ID_WM_COPYDATA_SENDOPENFILECOMMAND (WM_USER+1001 )
40
+
38
41
// Global Variables:
39
42
DWORD g_appStartupTime;
40
43
HINSTANCE hInst; // current instance
@@ -142,6 +145,32 @@ std::wstring GetFilenamesFromCommandLine() {
142
145
return result;
143
146
}
144
147
148
+ // EnumWindowsProc callback function
149
+ // - searches for an already running Brackets application window
150
+ BOOL CALLBACK FindSuitableBracketsInstance (HWND hwnd, LPARAM lParam)
151
+ {
152
+ ASSERT (lParam != NULL ); // must be passed an HWND pointer to return, if found
153
+
154
+ // check for the Brackets application window by class name and title
155
+ WCHAR cName[MAX_PATH+1 ] = {0 }, cTitle[MAX_PATH+1 ] = {0 };
156
+ ::GetClassName (hwnd, cName, MAX_PATH);
157
+ ::GetWindowText (hwnd, cTitle, MAX_PATH);
158
+ if ((wcscmp (cName, szWindowClass) == 0 ) && (wcsstr (cTitle, APP_NAME) != 0 )) {
159
+ // found an already running instance of Brackets. Now, check that that window
160
+ // isn't currently disabled (eg. modal dialog). If it is keep searching.
161
+ if ((::GetWindowLong (hwnd, GWL_STYLE) & WS_DISABLED) == 0 ) {
162
+ // return the window handle and stop searching
163
+ *(HWND*)lParam = hwnd;
164
+ return FALSE ;
165
+ }
166
+ }
167
+
168
+ return TRUE ; // otherwise, continue searching
169
+ }
170
+
171
+ // forward declaration; implemented in appshell_extensions_win.cpp
172
+ void ConvertToUnixPath (ExtensionString& filename);
173
+
145
174
// Program entry point function.
146
175
int APIENTRY wWinMain (HINSTANCE hInstance,
147
176
HINSTANCE hPrevInstance,
@@ -167,6 +196,43 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
167
196
// Parse command line arguments. The passed in values are ignored on Windows.
168
197
AppInitCommandLine (0 , NULL );
169
198
199
+ // Initialize global strings
200
+ LoadString (hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
201
+ LoadString (hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
202
+
203
+ // Determine if we should use an already running instance of Brackets.
204
+ HANDLE hMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE , FIRST_INSTANCE_MUTEX_NAME);
205
+ if ((hMutex != NULL ) && AppGetCommandLine ()->HasArguments () && (lpCmdLine != NULL )) {
206
+ // for subsequent instances, re-use an already running instance if we're being called to
207
+ // open an existing file on the command-line (eg. Open With.. from Windows Explorer)
208
+ HWND hFirstInstanceWnd = NULL ;
209
+ ::EnumWindows (FindSuitableBracketsInstance, (LPARAM)&hFirstInstanceWnd);
210
+ if (hFirstInstanceWnd != NULL ) {
211
+ ::SetForegroundWindow (hFirstInstanceWnd);
212
+ if (::IsIconic (hFirstInstanceWnd))
213
+ ::ShowWindow (hFirstInstanceWnd, SW_RESTORE);
214
+
215
+ // message the other Brackets instance to actually open the given filename
216
+ std::wstring wstrFilename = lpCmdLine;
217
+ ConvertToUnixPath (wstrFilename);
218
+ // note: WM_COPYDATA will manage passing the string across process space
219
+ COPYDATASTRUCT data;
220
+ data.dwData = ID_WM_COPYDATA_SENDOPENFILECOMMAND;
221
+ data.cbData = (wstrFilename.length () + 1 ) * sizeof (WCHAR);
222
+ data.lpData = (LPVOID)wstrFilename.c_str ();
223
+ ::SendMessage (hFirstInstanceWnd, WM_COPYDATA, (WPARAM)(HWND)hFirstInstanceWnd, (LPARAM)(LPVOID)&data);
224
+
225
+ // exit this instance
226
+ return 0 ;
227
+ }
228
+ // otherwise, fall thru and launch a new instance
229
+ }
230
+
231
+ if (hMutex == NULL ) {
232
+ // first instance of this app, so create the mutex and continue execution of this instance.
233
+ hMutex = ::CreateMutex (NULL , FALSE , FIRST_INSTANCE_MUTEX_NAME);
234
+ }
235
+
170
236
CefSettings settings;
171
237
172
238
// Populate the settings based on command line arguments.
@@ -180,9 +246,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
180
246
// Initialize CEF.
181
247
CefInitialize (main_args, settings, app.get ());
182
248
183
- // Initialize global strings
184
- LoadString (hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
185
- LoadString (hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
249
+ // Register window class
186
250
MyRegisterClass (hInstance, *(app->GetCurrentLanguage ().GetStruct ()));
187
251
188
252
CefRefPtr<CefCommandLine> cmdLine = AppGetCommandLine ();
@@ -272,6 +336,10 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
272
336
// Shut down CEF.
273
337
CefShutdown ();
274
338
339
+ // release the first instance mutex
340
+ if (hMutex != NULL )
341
+ ReleaseMutex (hMutex);
342
+
275
343
return result;
276
344
}
277
345
@@ -867,6 +935,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
867
935
PostQuitMessage (0 );
868
936
return 0 ;
869
937
938
+ case WM_COPYDATA:
939
+ // handle the interprocess communication request from another Brackets running instance
940
+ if (lParam != NULL ) {
941
+ PCOPYDATASTRUCT data = (PCOPYDATASTRUCT)lParam;
942
+ if ((data->dwData == ID_WM_COPYDATA_SENDOPENFILECOMMAND) && (data->cbData > 0 )) {
943
+ // another Brackets instance requests that we open the given filename
944
+ std::wstring wstrFilename = (LPCWSTR)data->lpData ;
945
+ // Windows Explorer might enclose the filename in double-quotes. We need to strip these off.
946
+ if ((wstrFilename.front () == ' \" ' ) && wstrFilename.back () == ' \" ' )
947
+ wstrFilename = wstrFilename.substr (1 , wstrFilename.length () - 2 );
948
+ ASSERT (g_handler != NULL );
949
+ CefRefPtr<CefBrowser> browser = g_handler->GetBrowser ();
950
+ // call into Javascript code to handle the open file command
951
+ ASSERT (browser != NULL );
952
+ g_handler->SendOpenFileCommand (browser, CefString (wstrFilename.c_str ()));
953
+ }
954
+ }
955
+ break ;
956
+
870
957
case WM_INITMENUPOPUP:
871
958
// Notify before popping up
872
959
g_handler->SendJSCommand (g_handler->GetBrowser (), APP_BEFORE_MENUPOPUP);
0 commit comments