A Vc++ Mfc Example: Preserve Sdi Window Size and State

Updated on August 23, 2018
sirama profile image

I am a software engineer. I have been working with C++, MFC, and .net technologies for 15 years. I like video games and reading books.

1. The Goal of Preserving the Window Size and Position

When we work on windows-based applications, we look at lot of window's elements like a menu, toolbar, status bar. The position and arrangement of one or more toolbars depends on the size of the window. Furthermore, one can also arrange the toolbar vertical or horizontal.

Let us say we arranged 7 of the toolbars in two rows on top of the window and in addition one toolbar in the left side. When we close and return to the application, all the toolbar states are gone. To avoid this, we have to preserve the windows position and size along with toolbar state while closing the application.

In this example, we will preserve the window size and its position relative to the desktop window using the WINDOWPLACEMENT structure. We will also use the SaveBarState function of CFrameWnd class to save the toolbar state.

2. The Default Behavior of the Application

First, create an SDI MFC application by accepting all the defaults in wizard. Run it, and drag the toolbar so that it appears in the left of the window. Then, resize the window and leave it towards the bottom left corner of the desktop. The window now looks as shown below:

Resized SDI Window
Resized SDI Window | Source

When we reopen the application, the toolbar stays below the menu horizontally, and window does not stay near the start menu as shown above. Additionally, we will not see our resized window and by all means the customization that we did is lost. This is the default behavior of the MFC SDI application. OK, let us start the code change. We are going the write WINDOWPLACEMENT structure in the registry while closing the application. And when we open it again we read the registry to remember out last customization.

Video 1: Default behaviour of SDI Application – Does not preserve window position

3. Saving SDI Window State

3.1 Set an Application Key in the Registry

We are using the SetRegistryKey function of the CWinApp to create a Key Root for our example. In our case, we are creating HubPages as the Key. Now, have a look at the below code which is written in the InitInstance of CWinApp:

//Sample 01: Change registry key as HubPages
//SetRegistryKey(
//_T("Local AppWizard-Generated Applications"));
SetRegistryKey(_T("Hubpages"));

We are passing the HubPages as a string to the function SetRegistryKey and this will create a Key for us in the windows registry. The path is: HKEY_CURRENT_USER\Software\HubPages.

3.2 Save Toolbar and Window Position

We have our Registry entry ready. Now, we will save the Toolbar and window position into the registry under the sub-keys of HubPages. The correct time to preserve the window state to a registry is application closure. Add a handler for WM_CLOSE Message in the CMainFrame and this is where we will write our code to save the window state. In the below we show how to create OnClose Handler for the WM_CLOSE message.

Video 2: Adding WM_CLOSE Handler for CMainFrame

The empty handler added by the Visual Studio IDE is below:

void CMainFrame::OnClose()
{
	// TODO: Add your message handler code 
// here and/or call default
	CFrameWnd::OnClose();
}

3.2.1 Declaration required for Registry access

We need to declare some variables to access the registry. We declared Registry_Key as an HKEY or in simple terms a Registry Handle which tells key location in the registry for which we need access. The WINDOWPLACEMENT is C++ structure which we will write into the Registry. The code is below:

//Sample 02: Required Declarations
LONG Ret;
HKEY Registry_Key;
DWORD disposition;
WINDOWPLACEMENT sWindow_Position;

3.2.2 Save the Toolbar State

The function SaveBarState will create one or more sub-key under the "HubPages". In our example, we are creating "MainToolBar" as sub-key for storing the toolbar state. The code is below:

//Sample 03: Save the toolbar state with existing mainframe 
//functionality
SaveBarState(_T("MainToolBar"));

At this stage closing the application will create registry entries for string the Toolbar states. The Registry entries are shown in the below picture.

Application Key in Registry
Application Key in Registry | Source

Do not get confused about the "PreservedWindowsPos" key as we will write code for that soon. The screenshot is taken after that code is executed once.

3.2.3 Save Window position

To save window position, first we need to create a registry key. From the previous section, we know that the Parent key in the Registry is HubPages. Now, we will create a sub-key called PreservedWindowPos and inside this key we will write our Window Position. The below code first checks the Registry entry and when it doesn’t find one, it will create a new Registry entry for Window Size and Window Position. Below is the code:

//Sample 04: Open the Registry and check for 
//key existence
Ret = RegOpenKeyEx(
	HKEY_CURRENT_USER, 
	_T("Software\\Hubpages\\PreservedWindowPos"),
	NULL,
	KEY_WRITE,
	&Registry_Key);

//Sample 05: The key will not exists for the very 
//first time and hence create
if (Ret != ERROR_SUCCESS)
{
	RegCreateKeyEx(
		HKEY_CURRENT_USER,
		_T("Software\\Hubpages\\PreservedWindowPos"),
		NULL, 
		NULL,
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		&Registry_Key,
		&disposition);
}

Once, we have a valid Registry Key; we capture the Windows Size and Position in a structure called WINDOWPLACEMENT. The GetWindowPlacement Function will retrieve this information and it takes the WINDOWPLACEMENT structure as a parameter. After the call, we take the WINDOWPLACEMENT structure and writes that to the Registry. Below is the code:

//Sample 06: Get WindowSize and its position
GetWindowPlacement(&sWindow_Position);

//Sample 07: Write this Structure to Registry
RegSetValueEx(
	Registry_Key, 
	_T("PosAndSize"), 
	NULL, 
	REG_BINARY, 
	(BYTE *) &sWindow_Position, 
	sizeof(WINDOWPLACEMENT));
RegCloseKey(Registry_Key);

Note that while we close the window, its size and position are persevered into the registry. In the coming section, we will read this registry entry, create the structure for window placement and restore the window exactly as it was.

4. Loading Window Position and Size

Now, we have our window position and size in the registry. In this section, we will load those registry values and position the window in the same location while it was closed along with the preserved size.

1) In the below code, we are first restoring the toolbar state. The LoadBarState will load the toolbar settings from the registry and arranges the toolbar in the mainframe window. We added this code to the OnCreate Handler of the WM_CREATE Message.

// Now load the saved toolbar state
//Sample 08: Load the Toolbar State saved 
//in the OnClose Handler
this->LoadBarState(_T("MainToolBar"));

2) In the application’s InitInstance, we declare the variables required to read the registry and load the WINDOWPLACEMENT structure. Below is the code:

//9.1 Declarations
LONG Ret;
HKEY RegistryKey;
DWORD type = REG_BINARY;
WINDOWPLACEMENT sWP;
DWORD sizewp = sizeof(WINDOWPLACEMENT);

3) While closing the application, we stored the WINDOWPLACEMENT structure in the registry key called PreservedWindowPos and now we open that key by calling RegOpenKeyEx. The handle to this registry key is stored in HKEY variable RegistryKey. We use this handle to query the Window placement information written as a structure in binary format.

//Sample 9.2 Check Key Exits
Ret = RegOpenKeyEx(
	HKEY_CURRENT_USER, 
	_T("Software\\Hubpages\\PreservedWindowPos"), 
	0, 
	KEY_READ, 
	&RegistryKey);

//Sample 9.3: Read the Window Placement Structure
if (Ret == ERROR_SUCCESS )
	Ret = ::RegQueryValueEx(RegistryKey, 
	_T("PosAndSize"), 
	0, 
	&type, 
	(LPBYTE) &sWP, 
	&sizewp);

4) At this moment, we have the registry information read into the structure called "sWP" and we can use this to restore our window to the previous state. Note that when the registry read is a success, we call SetWindowPlacement by supplying the structure we read from the registry. Below is the code for it:

//Sample 9.4 Now show the window from preserved state
if(Ret != ERROR_SUCCESS)
	m_pMainWnd->ShowWindow(SW_SHOW);
else
	m_pMainWnd->SetWindowPlacement(&sWP);

You can look at the video below which shows how Windows is restored to it previous state between application sessions.

Video 3: Testing the Window Placement from Registry

Questions & Answers

    © 2018 sirama

    Comments

      0 of 8192 characters used
      Post Comment

      No comments yet.

      working

      This website uses cookies

      As a user in the EEA, your approval is needed on a few things. To provide a better website experience, owlcation.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

      For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://owlcation.com/privacy-policy#gdpr

      Show Details
      Necessary
      HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
      LoginThis is necessary to sign in to the HubPages Service.
      Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
      AkismetThis is used to detect comment spam. (Privacy Policy)
      HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
      HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
      Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
      CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
      Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
      Features
      Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
      Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
      Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
      Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
      Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
      VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
      PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
      Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
      MavenThis supports the Maven widget and search functionality. (Privacy Policy)
      Marketing
      Google AdSenseThis is an ad network. (Privacy Policy)
      Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
      Index ExchangeThis is an ad network. (Privacy Policy)
      SovrnThis is an ad network. (Privacy Policy)
      Facebook AdsThis is an ad network. (Privacy Policy)
      Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
      AppNexusThis is an ad network. (Privacy Policy)
      OpenxThis is an ad network. (Privacy Policy)
      Rubicon ProjectThis is an ad network. (Privacy Policy)
      TripleLiftThis is an ad network. (Privacy Policy)
      Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
      Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
      Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
      Statistics
      Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
      ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
      Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
      ClickscoThis is a data management platform studying reader behavior (Privacy Policy)