手动
Win+R输入Recent
如果最近文件夹中的数量少于n,那就可以断定这台主机大概率是沙箱。
代码
MFC框架中对最近文件列表的支持
MFC建立的标准框架程序中有记录最近操作文件的能力,这些最近文件的路径被记录到注册表,在程序运行时,又将添加到文件菜单中。
在CWinApp中有个 CRecentFileList* m_pRecentFileList;指针管理这些信息。
以下对此过程进行分析,采用类似的方法,可以保存其他一些固定条数的最近数据。
CRecentFileList对象的建立,记录读入、记录保存、对象销毁。
①建立与记录的读入
如果在CWinApp派生类中InitInstance()中调用了LoadStdProfileSettings,则CRecentFileList被建立,于是程序具有管理最近文件列表的能力。
同时,从注册表中读入以前的记录。
void CWinApp::LoadStdProfileSettings(UINT nMaxMRU) //缺省为4
{
...
if (nMaxMRU != 0)
{
//建立CRecentFileList对象,初始化为管理nMaxMRU条文件信息
m_pRecentFileList = new CRecentFileList(0, _afxFileSection, _afxFileEntry,nMaxMRU);
//读入记录
m_pRecentFileList-> ReadList();
}
...
}
CRecentFileList对象中的主要数据成员
CRecentFileList包含一个CString指针 CString* m_arrNames; ,它用来指向一个CString对象数组,正是这个数组记录了最近的文件名。
另外,成员 int m_nSize 指出了记录的个数。
在对象创建时,构造函数完成初始化,包括CString数组的建立等。
②记录的保存、CRecentFileList的销毁。
ExitInstance()中将调用SaveStdProfileSettings(),SaveStdProfileSettings()中有m_pRecentFileList->WriteList();操作,完成记录的保存。
在CWinApp析构时将delete m_pRecentFileList;销毁对象。
CRecentFileList::CRecentFileList(UINT nStart, LPCTSTR lpszSection,
LPCTSTR lpszEntryFormat, int nSize, int nMaxDispLen)
{
ASSERT(nSize != 0);
m_arrNames = new CString[nSize]; //建立CString数组。
m_nSize = nSize; m_nStart = nStart;
m_strSectionName = lpszSection;
m_strEntryFormat = lpszEntryFormat;
m_nMaxDisplayLength = nMaxDispLen;
}
记录的添加
文档保存时,将调用SetPathName(..),SetPathName(..)中将调用应用程序类中的AddToRecentFileList
AddToRecentFileList中执行m_pRecentFileList->Add(lpszPathName)将文件名添加到字符串数组
void CRecentFileList::Add(LPCTSTR lpszPathName)
{
ASSERT(m_arrNames != NULL);
ASSERT(lpszPathName != NULL);
ASSERT(AfxIsValidString(lpszPathName)); // fully qualify the path name
TCHAR szTemp[_MAX_PATH];
AfxFullPath(szTemp, lpszPathName); //得到文件全路径 // 查找,看是否已经有此文件名
for (int iMRU = 0; iMRU < m_nSize-1; iMRU++)
{
if (AfxComparePath(m_arrNames[iMRU], szTemp))
break; // iMRU will point to matching entry
}
// 其前面的各项后移
for (; iMRU > 0; iMRU--)
{
ASSERT(iMRU > 0);
ASSERT(iMRU < m_nSize);
m_arrNames[iMRU] = m_arrNames[iMRU-1];
}
//添加到起始位置
m_arrNames[0] = szTemp;
}
记录的删除
如果用户从菜单中选择打开某记录对应的文件,单该文件已经不存在,则将删除该无效记录。
void CRecentFileList::Remove(int nIndex)
{
ASSERT(nIndex >= 0);
ASSERT(nIndex < m_nSize); m_arrNames[nIndex].Empty();
for (int iMRU = nIndex; iMRU < m_nSize-1; iMRU++)
m_arrNames[iMRU] = m_arrNames[iMRU+1]; //其后各项前移 ASSERT(iMRU < m_nSize);
m_arrNames[iMRU].Empty();
}
记录数据的保存
void CRecentFileList::WriteList()
{
ASSERT(m_arrNames != NULL);
ASSERT(!m_strSectionName.IsEmpty()); // m_strSectionName : _T("Recent File List")
ASSERT(!m_strEntryFormat.IsEmpty()); // m_strEntryFormat : _T("File%d")
LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
CWinApp* pApp = AfxGetApp();
pApp-> WriteProfileString(m_strSectionName, NULL, NULL); //写入Recent File List键
for (int iMRU = 0; iMRU < m_nSize; iMRU++)
{
wsprintf(pszEntry, m_strEntryFormat, iMRU + 1); //得到号吗字符串
if (!m_arrNames[iMRU].IsEmpty())
{
pApp-> WriteProfileString(m_strSectionName, pszEntry, //在写值名pszEntry,对应值为文件名。
m_arrNames[iMRU]);
}
}
delete[] pszEntry;
}
记录数据的读取
void CRecentFileList::ReadList()
{
ASSERT(m_arrNames != NULL);
ASSERT(!m_strSectionName.IsEmpty());
ASSERT(!m_strEntryFormat.IsEmpty());
LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
CWinApp* pApp = AfxGetApp();
for (int iMRU = 0; iMRU < m_nSize; iMRU++)
{
wsprintf(pszEntry, m_strEntryFormat, iMRU + 1); //得到值名字符串
m_arrNames[iMRU] = pApp-> GetProfileString( //取值名下的值,此即个记录,若值不存在,则为NULL
m_strSectionName, pszEntry, &afxChNil);
}
delete[] pszEntry;
}
将记录添加到菜单项
菜单资源中文件菜单下有ID为ID_FILE_MRU_FILE1的菜单项,用于在此处添加最近文件菜单项。
命令更新机制根据ON_UPDATE_COMMAND_UI(ID_FILE_MRU_FILE1, OnUpdateRecentFileMenu)将经常调用到
CWinApp::OnUpdateRecentFileMenu(..)
OnUpdateRecentFileMenu中调用void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI)
void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI)
{
ASSERT(m_arrNames != NULL); CMenu* pMenu = pCmdUI-> m_pMenu; //由pCmdUI直接找到菜单
if (m_strOriginal.IsEmpty() && pMenu != NULL)
pMenu-> GetMenuString(pCmdUI-> m_nID, m_strOriginal, MF_BYCOMMAND); if (m_arrNames[0].IsEmpty())
{
// no MRU files
if (!m_strOriginal.IsEmpty())
pCmdUI-> SetText(m_strOriginal);
pCmdUI-> Enable(FALSE);
return;
} if (pCmdUI-> m_pMenu == NULL)
return; for (int iMRU = 0; iMRU < m_nSize; iMRU++) //删除所有最新文件菜单项
pCmdUI-> m_pMenu-> DeleteMenu(pCmdUI-> m_nID + iMRU, MF_BYCOMMAND); TCHAR szCurDir[_MAX_PATH];
GetCurrentDirectory(_MAX_PATH, szCurDir);
int nCurDir = lstrlen(szCurDir);
ASSERT(nCurDir >= 0);
szCurDir[nCurDir] = '\\';
szCurDir[++nCurDir] = '\0'; CString strName;
CString strTemp;
for (iMRU = 0; iMRU < m_nSize; iMRU++)
{
if (!GetDisplayName(strName, iMRU, szCurDir, nCurDir))
break; // double up any '&' characters so they are not underlined
LPCTSTR lpszSrc = strName;
LPTSTR lpszDest = strTemp.GetBuffer(strName.GetLength()*2);
while (*lpszSrc != 0)
{
if (*lpszSrc == '&')
*lpszDest++ = '&';
if (_istlead(*lpszSrc))
*lpszDest++ = *lpszSrc++;
*lpszDest++ = *lpszSrc++;
}
*lpszDest = 0;
strTemp.ReleaseBuffer(); // insert mnemonic + the file name
TCHAR buf[10];
wsprintf(buf, _T("&%d "), (iMRU+1+m_nStart) % 10);
pCmdUI-> m_pMenu-> InsertMenu(pCmdUI-> m_nIndex++,
MF_STRING | MF_BYPOSITION, pCmdUI-> m_nID++,
CString(buf) + strTemp); //添加菜单项
} // update end menu count
pCmdUI-> m_nIndex--; // point to last menu added
pCmdUI-> m_nIndexMax = pCmdUI-> m_pMenu-> GetMenuItemCount(); pCmdUI-> m_bEnableChanged = TRUE; // all the added items are enabled
}
对最近文件菜单项的响应
系统通过消息映射 ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_FILE16, OnOpenRecentFile)
调用OnOpenRecentFile,命令ID作为参数传入
BOOL CWinApp::OnOpenRecentFile(UINT nID)
{
ASSERT_VALID(this);
ASSERT(m_pRecentFileList != NULL); ASSERT(nID >= ID_FILE_MRU_FILE1);
ASSERT(nID < ID_FILE_MRU_FILE1 + (UINT)m_pRecentFileList-> GetSize());
int nIndex = nID - ID_FILE_MRU_FILE1;
ASSERT((*m_pRecentFileList)[nIndex].GetLength() != 0); TRACE2("MRU: open file (%d) '%s'.\n", (nIndex) + 1,
(LPCTSTR)(*m_pRecentFileList)[nIndex]); if (OpenDocumentFile((*m_pRecentFileList)[nIndex]) == NULL)
m_pRecentFileList-> Remove(nIndex); return TRUE;