GetMenuItemInfo не получает информацию об элементе меню

У меня есть это 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

Вот как я пытаюсь получить информацию о выбранном пункте меню (проверьте комментарии внутри, пожалуйста):

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

Как я могу решить это?

ОБНОВИТЬ:

Теперь мой код выглядит следующим образом, он получает идентификатор любого элемента, но не строку:

    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)

1 ответ

Решение

Вы должны установить fMask член, чтобы указать, какие данные для извлечения, MIIM_STRING | MIIM_ID (&H40 Or &H2) для получения текста и удостоверения личности участников.

Извлечение текстового элемента требует двух шагов: Извлечение длины текста для выделения 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, который возвращает строку, состоящую из указанного числа пробелов. Это только для удобства, вы могли бы использовать StringBuilder также.

Если у вас есть проблемы с кодировкой символов (текст, который выглядит как китайские символы), будьте внимательны при импорте функции Windows API. Большинство Windows API-интерфейсов выпускаются в двух вариантах: ANSI и UNICODE с A а также W постфикс, соответственно. В этом случае вы должны указать GetMenuItemInfoW,

Другие вопросы по тегам