@@ -55,6 +55,30 @@ extern CefRefPtr<ClientHandler> g_handler;
55
55
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length)
56
56
#endif
57
57
58
+ // Registry access functions
59
+ void EnsureTrailingSeparator (LPWSTR pRet);
60
+ void GetKey (LPCWSTR pBase, LPCWSTR pGroup, LPCWSTR pApp, LPCWSTR pFolder, LPWSTR pRet);
61
+ bool GetRegistryInt (LPCWSTR pFolder, LPCWSTR pEntry, int * pDefault, int & ret);
62
+ bool WriteRegistryInt (LPCWSTR pFolder, LPCWSTR pEntry, int val);
63
+
64
+ // Registry key strings
65
+ #define PREF_APPSHELL_BASE L" Software"
66
+ #define PREF_WINPOS_FOLDER L" Window Position"
67
+ #define PREF_LEFT L" Left"
68
+ #define PREF_TOP L" Top"
69
+ #define PREF_WIDTH L" Width"
70
+ #define PREF_HEIGHT L" Height"
71
+ #define PREF_RESTORE_LEFT L" Restore Left"
72
+ #define PREF_RESTORE_TOP L" Restore Top"
73
+ #define PREF_RESTORE_RIGHT L" Restore Right"
74
+ #define PREF_RESTORE_BOTTOM L" Restore Bottom"
75
+ #define PREF_SHOWSTATE L" Show State"
76
+
77
+ // Window state functions
78
+ void SaveWindowRect (HWND hWnd);
79
+ void RestoreWindowRect (int & left, int & top, int & width, int & height, int & showCmd);
80
+ void RestoreWindowPlacement (HWND hWnd, int showCmd);
81
+
58
82
// Program entry point function.
59
83
int APIENTRY wWinMain (HINSTANCE hInstance,
60
84
HINSTANCE hPrevInstance,
@@ -190,6 +214,193 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
190
214
return result;
191
215
}
192
216
217
+ // Add trailing separator, if necessary
218
+ void EnsureTrailingSeparator (LPWSTR pRet)
219
+ {
220
+ if (!pRet)
221
+ return ;
222
+
223
+ int len = wcslen (pRet);
224
+ if (len > 0 && wcscmp (&(pRet[len-1 ]), L" \\ " ) != 0 )
225
+ {
226
+ wcscat (pRet, L" \\ " );
227
+ }
228
+ }
229
+
230
+ // Helper method to build Registry Key string
231
+ void GetKey (LPCWSTR pBase, LPCWSTR pGroup, LPCWSTR pApp, LPCWSTR pFolder, LPWSTR pRet)
232
+ {
233
+ // Check for required params
234
+ ASSERT (pBase && pApp && pRet);
235
+ if (!pBase || !pApp || !pRet)
236
+ return ;
237
+
238
+ // Base
239
+ wcscpy (pRet, pBase);
240
+
241
+ // Group (optional)
242
+ if (pGroup && (pGroup[0 ] != ' \0 ' ))
243
+ {
244
+ EnsureTrailingSeparator (pRet);
245
+ wcscat (pRet, pGroup);
246
+ }
247
+
248
+ // App name
249
+ EnsureTrailingSeparator (pRet);
250
+ wcscat (pRet, pApp);
251
+
252
+ // Folder (optional)
253
+ if (pFolder && (pFolder[0 ] != ' \0 ' ))
254
+ {
255
+ EnsureTrailingSeparator (pRet);
256
+ wcscat (pRet, pFolder);
257
+ }
258
+ }
259
+
260
+ // get integer value from registry key
261
+ // caller can either use return value to determine success/fail, or pass a default to be used on fail
262
+ bool GetRegistryInt (LPCWSTR pFolder, LPCWSTR pEntry, int * pDefault, int & ret)
263
+ {
264
+ HKEY hKey;
265
+ bool result = false ;
266
+
267
+ wchar_t key[MAX_PATH];
268
+ key[0 ] = ' \0 ' ;
269
+ GetKey (PREF_APPSHELL_BASE, GROUP_NAME, APP_NAME, pFolder, (LPWSTR)&key);
270
+
271
+ if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_CURRENT_USER, (LPCWSTR)key, 0 , KEY_READ, &hKey))
272
+ {
273
+ DWORD dwValue = 0 ;
274
+ DWORD dwType = 0 ;
275
+ DWORD dwCount = sizeof (DWORD);
276
+ if (ERROR_SUCCESS == RegQueryValueEx (hKey, pEntry, NULL , &dwType, (LPBYTE)&dwValue, &dwCount))
277
+ {
278
+ result = true ;
279
+ ASSERT (dwType == REG_DWORD);
280
+ ASSERT (dwCount == sizeof (dwValue));
281
+ ret = (int )dwValue;
282
+ }
283
+ RegCloseKey (hKey);
284
+ }
285
+
286
+ if (!result)
287
+ {
288
+ // couldn't read value, so use default, if specified
289
+ if (pDefault)
290
+ ret = *pDefault;
291
+ }
292
+
293
+ return result;
294
+ }
295
+
296
+ // write integer value to registry key
297
+ bool WriteRegistryInt (LPCWSTR pFolder, LPCWSTR pEntry, int val)
298
+ {
299
+ HKEY hKey;
300
+ bool result = false ;
301
+
302
+ wchar_t key[MAX_PATH];
303
+ key[0 ] = ' \0 ' ;
304
+ GetKey (PREF_APPSHELL_BASE, GROUP_NAME, APP_NAME, pFolder, (LPWSTR)&key);
305
+
306
+ if (ERROR_SUCCESS == RegCreateKeyEx (HKEY_CURRENT_USER, (LPCWSTR)key, 0 , NULL , REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL , &hKey, NULL ))
307
+ {
308
+ DWORD dwCount = sizeof (int );
309
+ if (ERROR_SUCCESS == RegSetValueEx (hKey, pEntry, 0 , REG_DWORD, (LPBYTE)&val, dwCount))
310
+ result = true ;
311
+ RegCloseKey (hKey);
312
+ }
313
+
314
+ return result;
315
+ }
316
+
317
+ void SaveWindowRect (HWND hWnd)
318
+ {
319
+ // Save position of active window
320
+ if (!hWnd)
321
+ return ;
322
+
323
+ WINDOWPLACEMENT wp;
324
+ memset (&wp, 0 , sizeof (WINDOWPLACEMENT));
325
+ wp.length = sizeof (WINDOWPLACEMENT);
326
+
327
+ if (GetWindowPlacement (hWnd, &wp))
328
+ {
329
+ // Only save window positions for "restored" and "maximized" states.
330
+ // If window is closed while "minimized", we don't want it to open minimized
331
+ // for next session, so don't update registry so it opens in previous state.
332
+ if (wp.showCmd == SW_SHOWNORMAL || wp.showCmd == SW_SHOW || wp.showCmd == SW_MAXIMIZE)
333
+ {
334
+ RECT rect;
335
+ if (GetWindowRect (hWnd, &rect))
336
+ {
337
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_LEFT, rect.left );
338
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_TOP, rect.top );
339
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_WIDTH, rect.right - rect.left );
340
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_HEIGHT, rect.bottom - rect.top );
341
+ }
342
+
343
+ if (wp.showCmd == SW_MAXIMIZE)
344
+ {
345
+ // When window is maximized, we also store the "restore" size
346
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, wp.rcNormalPosition .left );
347
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, wp.rcNormalPosition .top );
348
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, wp.rcNormalPosition .right );
349
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, wp.rcNormalPosition .bottom );
350
+ }
351
+
352
+ // Maximize is the only special case we handle
353
+ WriteRegistryInt (PREF_WINPOS_FOLDER, PREF_SHOWSTATE,
354
+ (wp.showCmd == SW_MAXIMIZE) ? SW_MAXIMIZE : SW_SHOW);
355
+ }
356
+ }
357
+ }
358
+
359
+ void RestoreWindowRect (int & left, int & top, int & width, int & height, int & showCmd)
360
+ {
361
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_LEFT, NULL , left);
362
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_TOP, NULL , top);
363
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_WIDTH, NULL , width);
364
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_HEIGHT, NULL , height);
365
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_SHOWSTATE, NULL , showCmd);
366
+ }
367
+
368
+ void RestoreWindowPlacement (HWND hWnd, int showCmd)
369
+ {
370
+ if (!hWnd)
371
+ return ;
372
+
373
+ // If window is maximized, set the "restore" window position
374
+ if (showCmd == SW_MAXIMIZE)
375
+ {
376
+ WINDOWPLACEMENT wp;
377
+ wp.length = sizeof (WINDOWPLACEMENT);
378
+
379
+ wp.flags = 0 ;
380
+ wp.showCmd = SW_MAXIMIZE;
381
+ wp.ptMinPosition .x = -1 ;
382
+ wp.ptMinPosition .y = -1 ;
383
+ wp.ptMaxPosition .x = -1 ;
384
+ wp.ptMaxPosition .y = -1 ;
385
+
386
+ wp.rcNormalPosition .left = CW_USEDEFAULT;
387
+ wp.rcNormalPosition .top = CW_USEDEFAULT;
388
+ wp.rcNormalPosition .right = CW_USEDEFAULT;
389
+ wp.rcNormalPosition .bottom = CW_USEDEFAULT;
390
+
391
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, NULL , (int &)wp.rcNormalPosition .left );
392
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, NULL , (int &)wp.rcNormalPosition .top );
393
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, NULL , (int &)wp.rcNormalPosition .right );
394
+ GetRegistryInt (PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, NULL , (int &)wp.rcNormalPosition .bottom );
395
+
396
+ // This returns an error code, but not sure what we could do on an error
397
+ SetWindowPlacement (hWnd, &wp);
398
+ }
399
+
400
+ ShowWindow (hWnd, showCmd);
401
+ }
402
+
403
+
193
404
//
194
405
// FUNCTION: MyRegisterClass()
195
406
//
@@ -247,14 +458,26 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
247
458
248
459
hInst = hInstance; // Store instance handle in our global variable
249
460
250
- hWnd = CreateWindow (szWindowClass, szTitle,
251
- WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0 ,
252
- CW_USEDEFAULT, 0 , NULL , NULL , hInstance, NULL );
461
+ // TODO: test this cases:
462
+ // - window in secondary monitor when shutdown, disconnect secondary monitor, restart
463
+
464
+ int left = CW_USEDEFAULT;
465
+ int top = CW_USEDEFAULT;
466
+ int width = CW_USEDEFAULT;
467
+ int height = CW_USEDEFAULT;
468
+ int showCmd = SW_SHOW;
469
+ RestoreWindowRect (left, top, width, height, showCmd);
470
+
471
+ DWORD styles = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
472
+ if (showCmd == SW_MAXIMIZE)
473
+ styles |= WS_MAXIMIZE;
474
+ hWnd = CreateWindow (szWindowClass, szTitle, styles,
475
+ left, top, width, height, NULL , NULL , hInstance, NULL );
253
476
254
477
if (!hWnd)
255
478
return FALSE ;
256
479
257
- ShowWindow (hWnd, nCmdShow );
480
+ RestoreWindowPlacement (hWnd, showCmd );
258
481
UpdateWindow (hWnd);
259
482
260
483
return TRUE ;
@@ -511,6 +734,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
511
734
512
735
case WM_CLOSE:
513
736
if (g_handler.get ()) {
737
+
738
+ HWND hWnd = GetActiveWindow ();
739
+ SaveWindowRect (hWnd);
740
+
514
741
// If we already initiated the browser closing, then let default window proc handle it.
515
742
HWND browserHwnd = g_handler->GetBrowser ()->GetHost ()->GetWindowHandle ();
516
743
HANDLE closing = GetProp (browserHwnd, CLOSING_PROP);
@@ -568,4 +795,4 @@ CefString AppGetCachePath() {
568
795
cachePath += L" \\ " GROUP_NAME APP_NAME L" \\ cef_data" ;
569
796
570
797
return CefString (cachePath);
571
- }
798
+ }
0 commit comments