Visual Studio 擁有「最近開啟的專案」與「最近開啟的檔案」兩組獨立 MRU 清單。MFC 預設僅支援單一 `CRecentFileList`(`m_pRecentFileList`)。本文示範如何在 `CWinApp` 衍生類別中**新增第二組 `CRecentFileList`**,依副檔名自動分流,選單資源定義獨立命令 ID 範圍,命令處理、UI 更新、讀寫登錄檔完整實作。
class CMyApp : public CWinApp
{
public:
CRecentFileList* m_pRecentFiles; // 預設清單(如 .doc)
CRecentFileList* m_pRecentProjects; // 新增清單(如 .prj)
// 命令處理
afx_msg void OnOpenRecentProject(UINT nID);
// UI 更新
afx_msg void OnUpdateRecentProjectMenu(CCmdUI* pCmdUI);
// 覆寫 AddToRecentFileList 分流
virtual void AddToRecentFileList(LPCTSTR lpszPathName);
DECLARE_MESSAGE_MAP()
};
BOOL CMyApp::InitInstance()
{
// ... 標準初始化 ...
// 1. 預設清單(MFC 自動管理 m_pRecentFileList)
// 若需自訂參數:
m_pRecentFiles = new CRecentFileList(10, _T("Recent Files"), _T("File%d"), 10);
m_pRecentFiles->ReadList();
// 2. 新增專案清單
m_pRecentProjects = new CRecentFileList(5, _T("Recent Projects"), _T("Project%d"), 15);
m_pRecentProjects->ReadList();
return TRUE;
}
int CMyApp::ExitInstance()
{
if (m_pRecentFiles) { m_pRecentFiles->WriteList(); delete m_pRecentFiles; }
if (m_pRecentProjects) { m_pRecentProjects->WriteList(); delete m_pRecentProjects; }
return CWinApp::ExitInstance();
}
// .rc 檔
IDR_MAINFRAME MENU ...
BEGIN
POPUP "&File"
BEGIN
// 預設 MRU:ID_FILE_MRU_FILE1 ~ ID_FILE_MRU_FILE10
MENUITEM "Recent &Files", ID_FILE_MRU_FILE1, GRAYED
MENUITEM SEPARATOR
// 新增 MRU:自訂 ID 範圍
MENUITEM "Recent &Projects", ID_FILE_MRU_PROJECT1, GRAYED
END
END
字串表需加入 `ID_FILE_MRU_PROJECT1` ~ `ID_FILE_MRU_PROJECT5`(或更多),內容可留空(由 `UpdateMenu` 填入)。
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_COMMAND_EX_RANGE(ID_FILE_MRU_PROJECT1, ID_FILE_MRU_PROJECT5, OnOpenRecentProject)
ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_MRU_PROJECT1, ID_FILE_MRU_PROJECT5, OnUpdateRecentProjectMenu)
END_MESSAGE_MAP()
void CMyApp::OnOpenRecentProject(UINT nID)
{
int nIndex = nID - ID_FILE_MRU_PROJECT1;
if (nIndex >= 0 && nIndex < m_pRecentProjects->GetSize())
{
CString strPath = (*m_pRecentProjects)[nIndex];
if (!OpenDocumentFile(strPath))
m_pRecentProjects->Remove(nIndex); // 檔案不存在則移除
}
}
void CMyApp::OnUpdateRecentProjectMenu(CCmdUI* pCmdUI)
{
m_pRecentProjects->UpdateMenu(pCmdUI); // 自動填入檔名、啟用/禁用、灰顯
}
void CMyApp::AddToRecentFileList(LPCTSTR lpszPathName)
{
CString strPath = lpszPathName;
int nPos = strPath.ReverseFind(_T('.'));
if (nPos != -1)
{
CString strExt = strPath.Mid(nPos + 1);
strExt.MakeUpper();
if (strExt == _T("PRJ") || strExt == _T("PROJ")) // 專案檔副檔名
{
if (m_pRecentProjects)
{
TCHAR szFull[_MAX_PATH];
AfxFullPath(szFull, lpszPathName);
m_pRecentProjects->Add(szFull);
}
return; // 不加入預設清單
}
}
// 其他副檔名走預設流程
CWinApp::AddToRecentFileList(lpszPathName);
}
關鍵點:多實例 `CRecentFileList` → 不同登錄區段 → 不同選單 ID 範圍 → `ON_COMMAND_EX_RANGE`/`ON_UPDATE_COMMAND_UI_RANGE` → 覆寫 `AddToRecentFileList` 分流。此架構可無限擴充(如最近資料庫連線、最近 FTP 站台),每組清單獨立持久化、獨立選單顯示、獨立命令處理,完美支援類 VS 多 MRU 需求。