You can update the registry from within your application. This is most useful when saving application information that may change from session to session. For example, you may want your application to save the placement and size of the application window as well as options selected by the user.
MFC provides registry support through member functions of the CWinApp class. For more sophisticated manipulation of the registry, use API calls, as described below.
Registry Support in MFC
To programmatically work with data in the registry, the first step is to call CWinApp::SetRegistryKey. AppWizard will include a call to this function in your CWinApp-derived InitInstance function.
BOOL CMyApp::InitInstance()
{
//...
SetRegistryKey("_T("Local AppWizard-Generated Applications"));
//...
}
SetRegistryKey is used to select the "Company Name" key in the registry. You, as a developer, will change the AppWizard-generated string to the name of your company. If the key is not found when the call is made, one will be created in the registry. Under the company name key, the framework will also generate a subkey using the name of the application as the subkey name. It is under this key where reads and writes to the registry occur for your application. By default, MFC stores application-specific data under HKEY_CURRENT_USER\Software\<CompanyName>\<ApplicationName>\<SectionName>. "SectionName" is a string that you specify when reading or writing a particular key value; it can be used to organize the location of the saved values.
To create an .ini file that is compatible with 16-bit Windows applications, remove the call to SetRegistryKey. The framework will create the file using the application's name as the .ini file name and will place it in the WIndows directory.
CWinApp provides four functions for reading and writing key values. The following table describes them.
Function Name Description
CWinApp::WriteProfileString Writes a string value to a key in a given section. If the specified section or key does not exist, it is created. A NULL value for the string value will delete the key.
CWinApp::GetProfileString Reads a string value from a key in a given section. A default return value can be specified if the key is not found.
CWinApp::WriteProfileInt Writes an integer value to a key in a given section. If the specified section or key does not exist, it is created. A NULL value for the integer value will delete the key.
CWinApp::GetProfileInt Reads an integer value from a key in a given section. A default return value can be specified if the key is not found.
Use the integer functions for storing and retrieving integer-like values. Use the string functions for all other values. Functions such as CString::Format and sscanf can be used to do the conversion between the string and desired data type.
To see sample code that shows how to read from and write to the registry programmatically, click this icon.
// Class definition file
class CPhraseApp : public CWinApp
{
...
CString m_defaultPhrase;
CPoint m_defaultLocation;
COLORREF m_defaultColor;
...
}
// Class implementation file
// Phrase Initialization
BOOL CPhraseApp::InitInstance()
{
...
// Force all subsequent calls to "Profile" functions
// to read and write from the registry under the key
// HKEY_CURRENT_USER\Software\MasteringVisualC++\Phrase
SetRegistryKey("MasteringVisualC++");
// Call "Profile" functions for registry information
LoadPhraseDefaults();
...
}
void CPhraseApp::LoadPhraseDefaults()
{// Load information from the registry
CString msg;
msg.LoadString(IDS_WELCOME_MSG);
int r, g, b;
m_defaultPhrase =
GetProfileString ("Settings", "DefaultPhrase", msg);
m_defaultLocation.x =
GetProfileInt ("Settings", "X-location", 100);
m_defaultLocation.y =
GetProfileInt ("Settings", "Y-location", 100);
r = GetProfileInt ("Settings", "Red-intensity", 0);
g = GetProfileInt ("Settings", "Green-intensity", 0);
b = GetProfileInt ("Settings", "Blue-intensity", 0);
m_defaultColor = RGB(r,g,b);
}
int CPhraseApp::ExitInstance()
{// Save information to the registry
WriteProfileString ("Settings", "DefaultPhrase", m_defaultPhrase);
WriteProfileInt ("Settings", "X-location", m_defaultLocation.x);
WriteProfileInt ("Settings", "Y-location", m_defaultLocation.y);
WriteProfileInt ("Settings", "Red-intensity", GetRValue(m_defaultColor));
WriteProfileInt ("Settings", "Green-intensity", GetGValue(m_defaultColor));
WriteProfileInt ("Settings", "Blue-intensity", GetBValue(m_defaultColor));
return CWinApp::ExitInstance();
}
For information about registry support in the API, search for "RegCreateKeyEx," "RegDeleteKey," "RegEnumKey," "RegOpenKeyEx," and "RegQueryInfoKey" in Visual C++ Help.
Self-Check Questions 1. Which one of the following statements is true about the registry?
A. Like .ini files, the registry is a text-based storage for configuration information.
B. Text-based registry entry files that usually have the extension .reg can be used to update the registry.
C. There are four primary branches, called "keys," in the registry.
D. The registry editors supplied with Windows NT or Windows 95 make backup copies of changes and only commit these changes when you exit the editor.
2. Which one of the following statements is true about MFC's programmatic support of the registry?
A. You must override CWinApp::SetRegistryKey to cause the application settings to be stored in the registry instead of an .ini file.
B. MFC's registry functions can be used to manage any key in the registry.
C. Registry functions are typically used in the overridden CWinApp::InitInstance and CWinApp::ExitInstance functions.
D. Binary data is typically written to the registry by using CWinApp::WriteProfileString.
3. Which one of the following statements about MFC serialization is true?
A. Both SDI and MDI applications can use CDocument::OnNewDocument for per-document initialization, and CDocument::DeleteContents for per-document cleanup.
B. The information to be serialized can be located in any of the framework classes.
C. MFC serialization supports incremental transfers and random access to information.
D. CDocument::SetModified must be called before serialization writes can occur.
4. Which of the following types is supported by MFC's serialization operators, the archive insertion (<<), and extraction (>>) operators?
A. int
B. CObject
C. CObList
D. DWORD
5. Which of the following conditions or steps is not required to add support for serialization to a class?
A. The class must be publicly derived from CObject or a class derived from CObject.
B. The class declaration must declare both an overridden version of CObject::Serialize and invocation of the
DECLARE_SERIAL macro.
C. The class implementation file must contain the implementation for Serialize and an invocation of the IMPLEMENT_SERIAL macro.
D. Each class in an application must have different, sequentially numbered schema.
Lab 11.1: Persisting Data
In this lab, you will write the code to serialize document and state data for an application.Estimated time to complete this lab: 40 minutes
To complete the exercises in this lab, you must have the required software. For detailed information about the labs and setup for the labs, see Labs in this course.
Objectives
After completing this lab, you will be able to:
® Transfer data between a document's collection and a data file.
® Save and retrieve application state data in the registry.
Prerequisites
There are no prerequisites for this lab.
Exercises
The following exercises provide practice with the concepts and techniques covered in this chapter:
® Exercise 1: Implementing Serialization
In this exercise, you will implement serialization for an application's document, which consists of a single collection of polygon and text items. Here you will implement transferring data between the document's collection and a data file.
® Exercise 2: Saving State Data to the Registry
In this exercise, you will serialize application-state information. You will load the most recently used data file and the view on it, and you will recall the view options on that data file. In addition, you will add code to set your company's registry key in the user's registry.
The code that forms the basis for this exercise is in \Labs\Ch11\Lab01\Baseline. Copy these files to your working directory.
In this exercise, you will implement serialization for an application's document, which consists of a single collection of polygon and text items. Here you will implement transferring data between the document's collection and a data file.
Edit the Serialize function in CPolyEditDoc
— Replace the if/else code with a direct call to the collection's serialization function. This function will, in turn, call each of the collection members’ serialization functions.
// Serialize the items in the list.
m_items.Serialize(ar);
Edit the Serialize function in CItem
— Within the inner brackets, add code to check the direction flag and then either to store or load the variable.
CItem, the base class for polygons and text objects, maintains a position member variable for the object.
if (ar.IsStoring())
{
ar << m_pos;
}
else
{
ar >> m_pos;
}
Edit the Serialize function in CPolygon
— Within the inner brackets, add code to serialize the polygon's brush, border, and position data.
CPolygon is the class that represents polygons in the document. Each polygon object maintains its brush and border properties as well as an array of data points.
if (ar.IsStoring())
{
// Serialize brush properties
ar << m_styleBrush;
ar << m_colorBrush;
ar << m_hatchBrush;
// Serialize border properties
ar << m_colorLine;
ar << m_styleLine;
ar << m_thickLine;
int count= GetSize();
ar << count;
for (int idx=0; idx<count; idx++)
ar << m_pts[idx];
}
else
{
// Serialize brush properties
ar >> m_styleBrush;
ar >> m_colorBrush;
ar >> m_hatchBrush;
ar >> m_colorLine;
ar >> m_styleLine;
ar >> m_thickLine;
int count;
ar >> count;
for (int idx=0; idx<count; idx++)
{
CPoint pt;
ar >> pt;
m_pts.Add(pt);
}
}
Edit the Serialize function in CText
— Within the inner brackets, add code to serialize the text object's string, color, and font data.
CText is the class for representing text in the document. Each object contains a CString, a color, and a LOGFONT structure containing font information. Remember that the base class, CItem, maintains the positional information.
if (ar.IsStoring())
{
ar << m_string;
ar << m_color;
ar.Write(&m_lf, sizeof(m_lf));
}
else
{
ar >> m_string;
ar >> m_color;
ar.Read(&m_lf, sizeof(m_lf));
}
Edit NewPolygon in CPolyEditDoc
1. Before the call to UpdateAllViews, insert the following code. SetModifiedFlag informs the framework that document data has changed. This will serve to prompt the user to have the file saved before quitting. Search for other occurrences of this call in the project.
SetModifiedFlag();
2. Build and run the application.
3. Test this version of the application by creating a new document and adding several polygons and text objects. Save the document and then clear the current view by opening up a new document. Using the FileOpen menu, open the document you just saved.
You can find the code for this completed exercise in \Labs\Ch11\Lab01\Ex01.
Continue working with the files you created in Exercise 1, or you can find the code that forms the basis for this exercise in \Labs\Ch11\Lab01\Ex01.
In this exercise, you will serialize application-state information. In particular, you will load the most recently used data file and the view on it, and you will recall the view options on that data file. In addition, you will add code to set your company's registry key in the user's registry.
Edit InitInstance in CPolyEditApp
1. Search for the call to SetRegistryKey. Replace the existing call with the following:
SetRegistryKey(_T("Microsoft Mastering Series"));
2. In the same function and between the calls to ParseCommandLine and ProcessShellCommand, add the following code. This code will inform the framework that the most recently used file is to be loaded at startup of the application.
// check that the user did not specify filename on command line.
if (cmdInfo.m_strFileName == "")
{
CString lastFileUsed= GetProfileString("Recent File List", "File1",NULL);
if (lastFileUsed != "")
{
cmdInfo.m_strFileName = lastFileUsed;
cmdInfo.m_nShellCommand = CCommandLineInfo::FileOpen;
}
}
Edit CPolyEditView
1. Add the following code to the destructor to save the application view state and option selections upon quitting.
// View scale
CString strScale;
strScale.Format("%lg",m_scale);
AfxGetApp()->WriteProfileString("Settings", "Scale", strScale);
AfxGetApp()->WriteProfileInt("Settings", "CenterX", m_x);
AfxGetApp()->WriteProfileInt("Settings", "CenterY", m_y);
AfxGetApp()->WriteProfileInt("Settings", "ShowInnerBox", m_bShowInnerBox);
AfxGetApp()->WriteProfileInt("Settings", "ShowOrigin", m_bShowOrigin);
2. Edit the CPolyEditView constructor. Replace the code that initializes the view and options with the following code. This code will obtain the settings that were stored in the registry to initialize the view.
// View scale
CString strScale = AfxGetApp()->GetProfileString("Settings", "Scale", "1.0");
sscanf(strScale,"%lg", &m_scale);
m_x = AfxGetApp()->GetProfileInt("Settings", "CenterX", 0);
m_y = AfxGetApp()->GetProfileInt("Settings", "CenterY", 0);
int option;
option = AfxGetApp()->GetProfileInt("Settings", "ShowInnerBox", 1);
m_bShowInnerBox = option ? true : false;
option = AfxGetApp()->GetProfileInt("Settings", "ShowOrigin", 1);
m_bShowOrigin = option ? true : false;
3. Build and run the application.
4. Test it by creating a document and adjusting the zoom level and center values. Quit the application and then restart it. The view should contain the same document and view parameters.
You can find the code for this completed exercise in \Labs\Ch11\Lab01\Ex02.
No comments:
Post a Comment