C++/MFC 在新版的 Visual Studio 上真是多災多難啊,不曉得是不是因為微軟要推崇 .Net 的關係。最近我就碰到了這個問題,還好最後透過神奇的股溝大神,找到了個神秘的討論串,再經過奇妙的測試過程,終於搞定了這個莫名其妙的問題。

我需要的是,在 PocketPC 2003 Dialog based 的 MFC 程式上,裝上 menu bar。

可是 Visual Studio 2005 不讓我把 Menu 綁在 Dialog 上,找 Pocket PC Developer Network 得到這一篇文章:《QA: How can I insert menu in a dialog?》,說按照這一篇《QA: How can I use a command bar in a dialog?》的說法,MFC 在 CDialog 裡留了一個小尾巴,放了一個叫 m_pWndEmptyCB 的 protected member variable,將之強制 down cast 成 CCeCommandBar pointer,就可以以之在 OnInitDialog() 裡載入 menu 了。

這一招很明顯地是個 undocumented approach,所以不意外地,在 Visual Studio 2005 上就沒用了。翻看 CDialog 的 source,m_pWndEmptyCB 不見了。

理論上,在新版裡,將舊版裡必須得用 undocumented approach 的功能,轉變成可以直接使用 documented approach 的官方作法,也就是使用 CCommandBar 物件。但實際上,還是沒有用,可以 compile/link 但執行起來,menu bar 就是沒有出現。

花了兩個半天搜尋 Google,終於撈到一個討論串:《error with MFC in visual studio 2005》,裡面說,這是一個 Visual Studio 2005 Beta 2 的 bug。簡單講就是 menu 有一種以上,原來的 MFC code 會假設用某一種,但實際上 Visual Studio 做出來的是另外一種。所以若要修正,就是去 Resource 裡看一看,看 menu 是哪一種,然後修正之。

可是,實際上我用 final release 版測,還是不行。查 code 發現,修正用的那段程式已經在裡面了,但是程式就是跑不出 menu bar 來。最後只好直接用 API 來開刀,在呼叫 ::SHCreateMenuBar() 時,用上這個 SHCMBF_HMENU flag 如下:

BOOL CTestCeMenu6Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 設定此對話方塊的圖示。當應用程式的主視窗不是對話方塊時,
	// 框架會自動從事此作業
	SetIcon(m_hIcon, TRUE);			// 設定大圖示
	SetIcon(m_hIcon, FALSE);		// 設定小圖示

	// TODO: 在此加入額外的初始設定
	SHMENUBARINFO mbi;
	mbi.cbSize = sizeof(mbi);
	mbi.hwndParent = m_hWnd;
	mbi.dwFlags = SHCMBF_HMENU;
	mbi.nToolBarId = IDR_MENUBAR;
	mbi.hInstRes = ::AfxGetInstanceHandle();
	mbi.nBmpId = 0;
	mbi.cBmpImages = 0;
	::SHCreateMenuBar(&mbi);

	return TRUE;  // 傳回 TRUE,除非您對控制項設定焦點
}

終於,可愛的 menu bar 出現了。

2007-03-26 更新:Windows CE 的 menu bar 在下面喔。