@@ -55,6 +55,30 @@ extern CefRefPtr<ClientHandler> g_handler;
5555#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length)
5656#endif
5757
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+
5882// Program entry point function.
5983int APIENTRY wWinMain (HINSTANCE hInstance,
6084 HINSTANCE hPrevInstance,
@@ -190,6 +214,193 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
190214 return result;
191215}
192216
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+
193404//
194405// FUNCTION: MyRegisterClass()
195406//
@@ -247,14 +458,26 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
247458
248459 hInst = hInstance; // Store instance handle in our global variable
249460
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 );
253476
254477 if (!hWnd)
255478 return FALSE ;
256479
257- ShowWindow (hWnd, nCmdShow );
480+ RestoreWindowPlacement (hWnd, showCmd );
258481 UpdateWindow (hWnd);
259482
260483 return TRUE ;
@@ -511,6 +734,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
511734
512735 case WM_CLOSE:
513736 if (g_handler.get ()) {
737+
738+ HWND hWnd = GetActiveWindow ();
739+ SaveWindowRect (hWnd);
740+
514741 // If we already initiated the browser closing, then let default window proc handle it.
515742 HWND browserHwnd = g_handler->GetBrowser ()->GetHost ()->GetWindowHandle ();
516743 HANDLE closing = GetProp (browserHwnd, CLOSING_PROP);
@@ -568,4 +795,4 @@ CefString AppGetCachePath() {
568795 cachePath += L" \\ " GROUP_NAME APP_NAME L" \\ cef_data" ;
569796
570797 return CefString (cachePath);
571- }
798+ }
0 commit comments