The MFC of VC ++ wraps the latest file so that you can implement the menu of the latest file without writing any code. However, this method is also flawed:
① A user program must use a document and view structure and can only use the documents provided by it to open and save files. If you use a self-compiled function to open and save files, your program bypasses its documents, the latest file will not be available.
② This kind of recent file is stored in the registry, which is difficult to clear and easily forms garbage in the registry, and does not provide the user's right to clear the recent file, which is not conducive to the protection of user privacy.
Using the INI file to implement recent files can solve the above problems, and using programming to control MRU is more flexible, and more functions can be provided.
I. Structure and access method of the INI File
The INI file is a plain text file, which can be accessed programmatically or opened by any text editing software. For example, a RAV. ini file is opened as follows:
[INSTALLED]
FWBASE2K = 1
FWBASENT = 1
ToInstall =
CodePage = 936
Closed =
[Setup]
ShowBgBmp = 0
[Skin]
Current = 1
Path = D:/Program Files/Rising/Rav/Skin/Skin1/Skin. xml
[RAVMON]
MongoDB status = 255
The [] clause is called a segment, and each part below the segment is called an item. You can access the value of a specified item by using the segment name or item name. We can use API functions to directly read and write INI files.
(I) read the item value in the INI File
① Read the integer:
Uint getprivateprofileint (lpappname, lptstr lpkeyname, int ndefault, lpstr lpfilename );
Lpappname is the segment name, lpkeyname is the item name, ndefault is the default value returned when the item cannot be found, and lpfilename is the INI File Name
Return Value: If successful, the integer after the specified item is returned. If this item does not exist, the ndefault value is returned.
For example, read the value of the fwbase2k entry in the [installed] segment in the rav. ini file.
Int fwbbase2k =: getprivateprofileint ("installed", "fwbase2k", 0, "rav. ini ");
If the fwbase2k entry in the [installed] segment exists, the value of fwbbase2k is the read value. If it does not exist, it is the value 0 specified in the function call.
② Read string:
DWORD getprivateprofilestring (lpappname, lptstr lpkeyname, lptstr lpdefault, lptstr lpreturnedstring, DWORD nsize, lptstr lpfilename );
Lpappname is the segment name, lpkeyname is the item name, lpdefault is the default value returned when this item cannot be found, lpreturnedstring points to the string buffer of the received result, nsize is the buffer length, lpfilename is the INI File Name
Execution result: if the operation is successful, the value in the string indicated by lpreturnedstring is the value of the read item. If the value does not exist, the value in lpreturnedstring is the value of lpdefault.
For example, read the value of the path entry in the [skin] segment of the rav. ini file.
Cstring pathname; // variable of the receiving string
: GetPrivateProfileString ("Skin", "Path", "", PathName. GetBuffer (MAX_PATH), MAX_PATH, "RAV. ini ");
PathName. ReleaseBuffer (); // release extra space
MAX_PATH is a predefined constant. Its value may be 255.
(Ii) write data into the INI File
No integer function is written at the time of writing, only the function that writes the string
BOOL WritePrivateProfileString (lpAppName, lptstr lpKeyName, lptstr lpString, lptstr lpFileName );
LpAppName is the segment name, lpKeyName is the item name, lpString is the Written string, and lpFileName is the ini File Name
Return Value: true if the operation is successful; otherwise, false is returned.
If the INI file does not exist at the time of writing, the function automatically creates the file and creates the corresponding segments and items.
For example, set the value of the FWBASE2K entry in the [INSTALLED] segment in the RAV. ini file to 2. Because this is an integer, convert it to a string before writing it.
CString str;
Str. Format ("% d", 2); // converts the written integer to a string
: WritePrivateProfileString ("INSTALLED", "FWBASE2K", str, "RAV. ini"); // write the ini File
Note: in practice, the ini file name should use an absolute path name. Otherwise, the ini file to be read/written may not be found.
Ii. Use the INI file to implement the MRU of the latest file
I designed an ini file MruFile. ini to save the most recent file. Its structure is as follows:
[MRU file]
Filenum = number of current files
1 = Path 1
2 = Path 2
3 = Path 3
4 = Path 4
[MRU file] is the segment name, the item filenum is the current number of MRU files, and items 1, 2, 3, and 4 are placed with each MRU file name. Only four recent files are designed here, which can be added as needed during the application.
Use classwizard to add a new class without a base class. The class name is cmrufile, which is used as the MRU file management class and is defined as follows in its header file:
# Define maxnum 4 // maximum number of MRU files
Cstring m_inifilename; // INI File Name
Cstring m_pathname [maxnum]; // path name of the MRU File
Int m_curnum; // number of recent files
Define the following functions in mrufile. cpp:
① Read the most recent file in the INI File
Void cmrufile: readmru ()
{
M_CurNum =: GetPrivateProfileInt ("Mru File", "FileNum", 0, m_IniFileName); // read the current File count
CString no;
For (int I = 0; I <m_CurNum; I ++)
{
No. Format ("% d", I + 1); // calculate the item name
: GetPrivateProfileString ("Mru File", no, "", m_PathName [I]. GetBuffer (MAX_PATH ),
MAX_PATH, m_IniFileName); // read the path name
M_PathName [I]. ReleaseBuffer ();
}
SetMruMenu (); // modify the MRU menu
}
This function is executed at the beginning of the program. It is used to read the most recent file name in the INI file into the string array m_PathName, and then modify the menu of the most recent file so that they can be opened by the menu of the most recent file.
② Write the latest file into the INI File
Void CMruFile: WriteMru ()
{
CString no;
No. Format ("% d", m_CurNum );
: WritePrivateProfileString ("Mru File", "FileNum", no, m_IniFileName); // number of current files written
For (int I = 0; I <MAXNUM; I ++)
{
No. Format ("% d", I + 1 );
: WritePrivateProfileString ("Mru File", no, m_PathName [I], m_IniFileName); // write the path name
}
}
This function is executed when you open a file to update the Mru list in the INI file.
③ Add the latest file
Design Concept: When the opened file name nPathName already exists in the m_PathName [] list, it is promoted to the header. If it does not exist, it is added to the header, if the table is full (up to four file names can be added in this example), delete the elements at the end of the table.
Void CMruFile: AddMru (CString nPathName)
{
Int I;
CString str1, str2;
If (m_CurNum)
{
If (nPathName. CompareNoCase (m_PathName [0]) = 0) // if nPathName is already in the header, end
Return;
}
Str1 = nPathName;
I = 0;
While (I <m_CurNum & nPathName. CompareNoCase (m_PathName [I])! = 0) // search in the table. If the elements are not equal, move them down.
{
Str2 = m_PathName [I];
M_PathName [I] = str1;
Str1 = str2;
I ++;
}
If (I <m_CurNum)
M_PathName [I] = str1; // nPathName already exists
Else if (m_CurNum <MAXNUM)
{
M_PathName [m_CurNum] = str1; // The table is not full.
M_CurNum ++;
}
SetMruMenu (); // modify the MRU menu
Writemru (); // write the latest file to the INI File
}
This function is also executed when the user opens a file and before the writemru () function, used to update the MRU list saved with the array m_pathname.
④ Clear the latest file
Void cmrufile: clearmru ()
{
M_curnum = 0; // clears the number of recent files
For (INT I = 0; I <maxnum; I ++)
M_pathname [I]. Empty (); // clear the MRU list
Setmrumenu (); // clear the MRU menu
Writemru (); // clear the MRU list in the INI File
}
The MRU menu contains the "clear recent files" option. When you click this menu item, run this function. This helps protect user privacy.
⑤ Modify the menu of the latest file
Void cmrufile: setmrumenu ()
{
CMenu * pMenu = AfxGetMainWnd ()-> GetMenu (); // Main Menu pointer
CMenu * pFileMenu = pMenu-> GetSubMenu (0); // "file" menu pointer
CMenu * pMruMenu = pFileMenu-> GetSubMenu (5); // "recent file" menu pointer (5 is the position of the recent file menu item in the File menu)
PMruMenu-> RemoveMenu (ID_MRU1, MF_BYCOMMAND); // Delete menu items
PMruMenu-> RemoveMenu (ID_MRU2, MF_BYCOMMAND );
PMruMenu-> RemoveMenu (ID_MRU3, MF_BYCOMMAND );
PMruMenu-> RemoveMenu (ID_MRU4, MF_BYCOMMAND );
If (m_CurNum> 0) // re-Insert menu items
PMruMenu-> InsertMenu (ID_MRU_CLR, MF_BYCOMMAND,
ID_MRU1, m_PathName [0]);
If (m_CurNum> 1)
PMruMenu-> InsertMenu (ID_MRU_CLR, MF_BYCOMMAND,
ID_MRU2, m_PathName [1]);
If (m_CurNum> 2)
PMruMenu-> InsertMenu (ID_MRU_CLR, MF_BYCOMMAND,
ID_MRU3, m_PathName [2]);
If (m_CurNum> 3)
PMruMenu-> InsertMenu (ID_MRU_CLR, MF_BYCOMMAND,
ID_MRU4, m_PathName [3]);
}
This function is called when the Mru file list changes. The Mru menu is a dynamic menu that can be modified. The number of menu items varies with the number of Mru files, and the menu content also changes with the content of the Mru list.
Here ID_MRU1 ~ ID_MRU4 and ID_MRU_CLR are the IDs of each menu item. They must be defined in the resource string table in advance.
In this way, a recent file class for INI file management is ready. During use, the OnFileOpen () function in the program's open file and the OnFileSaveAs () function can call related functions of this class to manage recent files.