【问题标题】:GetMenuItemInfo does not retrieve the menu item informationGetMenuItemInfo 不检索菜单项信息
【发布时间】:2013-11-12 19:51:39
【问题描述】:

我有这个 mii 变量,它分配一个 MenuItemInfo 结构来设置(或获取)系统菜单的项目。

Private mii As New MenuItemInfo

<System.Runtime.InteropServices.
StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Public Structure MENUITEMINFO
    Public cbSize As Integer
    Public fMask As Integer
    Public fType As Integer
    Public fState As Integer
    Public wID As Integer
    Public hSubMenu As IntPtr
    Public hbmpChecked As IntPtr
    Public hbmpUnchecked As IntPtr
    Public dwItemData As IntPtr
    Public dwTypeData As String
    Public cch As Integer
    Public hbmpItem As IntPtr
End Structure

当我尝试使用 API 函数GetMenuItemInfo 使用变量来存储有关现有菜单项的信息时,会出现问题,变量没有改变任何东西,所有结构成员仍然为空。

这是API函数(注意Byref设置正确)

''' <summary>
''' Gets the handle of the form's system menu.
''' </summary>
''' <param name="hMenu">
''' The handle to the menu that contains the menu item.
''' </param>
''' <param name="uItem">
''' The identifier or position of the menu item to get information about.
''' The meaning of this parameter depends on the value of fByPosition.
''' </param>
''' <param name="fByPosition">
''' The meaning of uItem.
''' If this parameter is FALSE, uItem is a menu item identifier,
''' If this parameter is TRUE, it is a menu item position.
''' </param>
''' <param name="lpmii">
''' A pointer to a MenuItemInfo structure that specifies the information to retrieve.
''' Note that you must set the cbSize member to sizeof(MENUITEMINFO) before calling this function.
''' </param>
<System.Runtime.InteropServices.
DllImport("user32.dll")> _
Private Shared Function GetMenuItemInfo(
        ByVal hMenu As IntPtr,
        ByVal uItem As UInteger,
        ByVal fByPosition As Boolean,
        ByRef lpmii As MenuItemInfo) As Boolean
End Function

这就是我试图检索点击的菜单项信息的方式,(请检查里面的 cmets):

Protected Overrides Sub WndProc(ByRef m As Message)

    Select Case m.Msg

        Case &H112 ' WM_SYSCOMMAND

            mii = New MenuItemInfo
            mii.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(mii)
            ' NOTE:
            ' MSDN says that I need to put the dwTypeData to a null value,
            ' if I want to retrieve a TEXT type item so...
            mii.dwTypeData = Nothing

            ' NOTE:
            ' m.WParam contains the ID of the clicked Item,
            ' so I use True to set is an Identifier and not a position.
            Dim success? As Boolean = _
                GetMenuItemInfo(MenuHandle, m.WParam, True, mii)

            MsgBox(success)        ' Result: True
            MsgBox(mii.wID)        ' Result: 0 (empty)
            MsgBox(mii.dwTypeData) ' Result: (empty)

            MsgBox(m.wParam)       ' Result: (The expected item ID)

    End Select

    ' Return control to base message handler.
    MyBase.WndProc(m)

End Sub

我该如何解决这个问题?

更新:

现在我的代码如下所示,它检索任何项目的 ID,但不检索字符串:

    Dim mii As New MenuItemInfo()
    mii.cbSize = Marshal.SizeOf(GetType(MenuItemInfo))
    mii.fMask = Mask.ID Or Mask.TEXT ' &H40 Or &H2
    ' mii.fType = ItemType.TEXT ' &H0

    Dim success? As Boolean = GetMenuItemInfo(MenuHandle, m.WParam, False, mii)

    MsgBox(mii.wID) ' Result: (The Expected ID)
    MsgBox(mii.dwTypeData) ' Result: (empty string)

【问题讨论】:

    标签: .net vb.net winapi windows-messages systemmenu


    【解决方案1】:

    您必须设置 fMask 成员来指定要检索的数据,MIIM_STRING | MIIM_ID (&amp;H40 Or &amp;H2) 来检索文本和 ID 成员。

    检索文本成员需要两个步骤:检索文本长度以分配适当长度的String,然后实际检索文本:

    mii = New MenuItemInfo
    mii.cbSize = Marshal.SizeOf(GetType(MenuItemInfo))
    mii.dwTypeData = Nothing
    mii.fMask = Mask.TEXT ' &H40
    ' Retrieve the text length member
    GetMenuItemInfo(MenuHandle, m.wParam, True, mii)
    ' Account for terminating NUL character and allocate String
    mii.cch += 1
    mii.dwTypeData = Space(mii.cch)
    ' Specify MIIM_STRING | MIIM_ID to retrieve both text and ID
    mii.fMask = Mask.TEXT Or Mask.ID ' &H40 Or &H2
    ' Retrieve data
    GetMenuItemInfo(MenuHandle, m.wParam, True, mii)
    

    请注意,您必须分配具有适当大小的字符串并在mii.cch 中指定缓冲区大小。上面的代码使用了Strings.Space Method,它返回一个由指定数量的空格组成的字符串。这只是为了方便,您也可以使用StringBuilder

    如果您在导入 Windows API 函数时遇到字符编码(看起来像汉字的文本)问题,请具体说明。大多数 Windows API 有两种形式:ANSI 和 UNICODE,分别带有 AW 后缀。在这种情况下,您应该指定GetMenuItemInfoW

    【讨论】:

    • 谢谢你,我们已经接近了,现在它检索到任何项目的ID而不是文本,我也尝试将类型设置为文本但文本成员仍然为空:mii.fType = ItemType.TEXT ' &amp;H0L
    • 我需要说的是,当我在菜单中添加一个新项目时,它是用中文添加的!所以我需要更改 InsertMenuItem Api 的字符集以正确添加项目,我尝试为 GetMenuItemInfo API 指定字符集 ANSI 但仍然没有检索到 dwTypeData 成员,无论是我自己的项目还是系统项目,字符串我得到的总是空的。
    • @Elektro 我改变了主意 :) 检索字符串不像我最初发布的那样工作。我更新了正确的答案。
    猜你喜欢
    • 2011-06-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 2023-03-07
    • 2017-02-02
    • 2019-01-25
    • 2013-08-08
    • 2011-12-10
    相关资源
    最近更新 更多