技法和原理:如何找到你需要的菜單項?

2024年2月6日 23点热度 0人点赞

你一定碰到過查找某個菜單項的場景,通常我們會使用類似於 GetMenuItemInfo 這樣的菜單函數,
在這類函數中,有一個參數允許你指定要查找的菜單項目的信息:MF_BYPOSITION 或者 MF_BYCOMMAND。

至此,是不是很眼熟了。今天就來給大夥兒講講這個。

從字面意思來理解,MF_BYPOSITION 是根據菜單的位置來進行查找,而 MF_BYCOMMAND 是根據菜單的命令 ID 來進行查找。

根據菜單的位置進行查找是很容易理解的,我們指定一個從 0 開始的數字作為菜單的位置進行菜單項的查找。換句話說,索引 0 表示第一個菜單項,依次類推。

根據菜單命令進行查找,有些小復雜,請坐穩扶好:菜單管理器將會根據你指定的菜單命令對整個菜單進行遞歸式查找,包含子菜單。很有可能發生的情況是,有可能在整個菜單樹中會找到多個擁有同一個命令的菜單項,這個時候,函數將會從中任意選擇一個出來返回給你。

例如,在層次結構中查找意味著隻需傳遞根菜單(通常可以輕松訪問)和菜單命令即可刪除或禁用菜單項。
如果不搜索子菜單,那麼同步菜單狀態將是一件非常麻煩的事情。

但是,如果您的菜單有多個具有相同命令的項目怎麼辦?

好吧,簡短的回答是,”那就不要用MF_BYCOMMAND了。您仍然可以使用 MF_BYPOSITION 來訪問您的菜單項。”

但我對你的靈魂之問是:

為什麼首先要有多個具有相同命令的菜單項呢?

當用戶選擇菜單時,一條 WM_COMMAND 消息將發送到窗口,並將菜單命令作為其參數之一,而其他參數均不提供菜單句柄。如果您有多個具有相同命令的菜單項,您將無法分辨用戶選擇了其中的哪一個,這可不是你想要的。

對於這個問題,已經有過很多討論了,但是我想說的是,這並非 Windows 的 Bug 。

如果菜單包含多個具有相同命令的菜單項,那麼 MF_BYCOMMAND 是模棱兩可的,並且所承諾的隻是將找到具有該命令的某些項目。它可能不是您想要的,但由於您為多個項目提供了相同的命令,因此菜單管理器已盡最大努力。

這類似於其他搜索函數,如 FindWindow 和 GetDlgItem,它們對它們找到的第一個項目進行操作。如果多個項目符合您指定的條件,則僅返回其中一個項目。

另外還有一個具體問題:查詢菜單的時候,恰好沒有緩存,至少現在還沒有。但誰知道呢,如果我們發現許多應用程序快速連續地查詢同一項目,將來可能會有一個緩存。但是這個人沒有意識到的是,他們使用的未命名的自定義 GUI 庫在收到 WM_INITMENUPOPUP 消息之前不會創建子菜單。在打開子菜單之前找不到該項目的原因是,在打開子菜單之前,子菜單不存在。當然,你找不到不存在的東西。

總結

優先使用按位置進行菜單項目查找,並時刻牢記:按命令查找可能會找到多個,且可能返回那個你所不需要的。

最後

Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,裡面有很多關於Windows的小知識,對於廣大Windows平臺開發者來說,確實十分有幫助。
本文來自:《How do the menu functions find items?》