Win32 API GetMenuItemInfo 仅返回项文本的第一个字符

本文关键字:文本 第一个 字符 返回 API GetMenuItemInfo Win32 | 更新日期: 2023-09-27 17:56:27

我正在尝试使用GetMenuItemInfo API收集菜单项的文本。

这是我正在使用的代码:

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool GetMenuItemInfo(IntPtr hMenu, uint uItem, bool fByPosition, ref MENUITEMINFO lpmii);
[StructLayout(LayoutKind.Sequential)]
public struct MENUITEMINFO 
{
    public uint cbSize;
    public uint fMask;
    public uint fType;
    public uint fState;
    public uint wID;
    public IntPtr hSubMenu;
    public IntPtr hbmpChecked;
    public IntPtr hbmpUnchecked;
    public IntPtr dwItemData;
    public String dwTypeData;
    public uint cch;
    public IntPtr hbmpItem;
    // Return the size of the structure
    public static uint sizeOf
    {
        get { return (uint)Marshal.SizeOf(typeof(MENUITEMINFO)); }
    }
}
MENUITEMINFO mif = new MENUITEMINFO();
mif.cbSize = MENUITEMINFO.sizeOf;
mif.fMask = MIIM_STRING; 
mif.fType = MFT_STRING;
mif.dwTypeData = null;
bool res = Win32.GetMenuItemInfo(hMenu, (uint)0, true, ref mif); //To load cch into memory
mif.cch += 1;
mif.fMask = MIIM_STRING;
mif.fType = MFT_STRING;
mif.dwTypeData = new String(' ', (Int32)(mif.cch));
res = Win32.GetMenuItemInfo(hMenu, (uint)i, true, ref mif); //To fill dwTypeData

不幸的是,在这些行之后,dwTypeData 会生成一个只有 1 个字符而不是 mif.cch 字符的字符串。注意:此字符是菜单项的第一个!

返回 MENUITEMINFO 结构时,数据封送处理中似乎有一些错位,不是吗?

请让我知道如何解决此类问题!

最好

切尔西

Win32 API GetMenuItemInfo 仅返回项文本的第一个字符

你的标题翻译很好,但你还没有dwTypeData完全正确。这不能使用 string 从呼叫者编接到被调用方。您需要使用这样的手动编组来执行此操作。

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool GetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, MENUITEMINFO lpmii);
[StructLayout(LayoutKind.Sequential)]
public class MENUITEMINFO 
{
    public int cbSize;
    public uint fMask;
    public uint fType;
    public uint fState;
    public uint wID;
    public IntPtr hSubMenu;
    public IntPtr hbmpChecked;
    public IntPtr hbmpUnchecked;
    public IntPtr dwItemData;
    public IntPtr dwTypeData;
    public uint cch;
    public IntPtr hbmpItem;
    public MENUITEMINFO()
    {
        cbSize = Marshal.SizeOf(typeof(MENUITEMINFO));
    }
}
....
MENUITEMINFO mif = new MENUITEMINFO();
mif.fMask = MIIM_STRING; 
mif.fType = MFT_STRING;
mif.dwTypeData = IntPtr.Zero;
bool res = GetMenuItemInfo(hMenu, 0, true, mif);
if (!res)
    throw new Win32Exception();
mif.cch++;
mif.dwTypeData = Marshal.AllocHGlobal((IntPtr)(mif.cch*2));
try
{
    res = GetMenuItemInfo(hMenu, 0, true, mif);
    if (!res)
        throw new Win32Exception();
    string caption = Marshal.PtrToStringUni(mif.dwTypeData);
}
finally
{
    Marshal.FreeHGlobal(mif.dwTypeData);
}

更新 2

使用反射System.Windows.Forms.MenuItem中找到的代码。似乎他们也使用字符串。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MENUITEMINFO_T
{
    public int cbSize = Marshal.SizeOf(typeof(NativeMethods.MENUITEMINFO_T));
    public int fMask;
    public int fType;
    public int fState;
    public int wID;
    public IntPtr hSubMenu;
    public IntPtr hbmpChecked;
    public IntPtr hbmpUnchecked;
    public IntPtr dwItemData;
    public string dwTypeData;
    public int cch;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetMenuItemInfo(HandleRef hMenu, int uItem, bool fByPosition, [In, Out] MENUITEMINFO_T lpmii);
  ................
  MENUITEMINFO_T menuiteminfo_t;
  menuiteminfo_t = new MENUITEMINFO_T();
  menuiteminfo_t.fMask = MIIM_STRING;
  menuiteminfo_t.dwTypeData = new string(''0', 256);
  menuiteminfo_t.cch = menuiteminfo_t.dwTypeData.Length - 1;
  bool result = GetMenuItemInfo(new HandleRef(null, hMenu), 0, true, menuiteminfo_t);

更新 1

正如 Lebeau @Remy所建议的那样,字符串封送处理与 char[] 封送之间存在差异。 在我将CharSet=CharSet.Auto属性添加到结构后,使用您的代码一切正常。

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    public struct MENUITEMINFO
    {
        public uint cbSize;
        public uint fMask;
        public uint fType;
        public uint fState;
        public uint wID;
        public IntPtr hSubMenu;
        public IntPtr hbmpChecked;
        public IntPtr hbmpUnchecked;
        public IntPtr dwItemData;
        public string dwTypeData;
        public uint cch;
        public IntPtr hbmpItem;
        // return the size of the structure
        public static uint sizeOf
        {
            get { return (uint)Marshal.SizeOf(typeof(MENUITEMINFO)); }
        }
    }

        IntPtr hWnd = FindWindow(null, "untitled - notepad");
        IntPtr hMenu = GetMenu(hWnd);

        MENUITEMINFO mif = new MENUITEMINFO();
        uint MIIM_STRING = 0x00000040;
        uint MFT_STRING = 0x00000000;
        mif.cbSize = MENUITEMINFO.sizeOf;//(uint)Marshal.SizeOf(typeof(MENUITEMINFO));
        mif.fMask = MIIM_STRING;
        mif.fType = MFT_STRING;
        mif.dwTypeData = null;
        //IntPtr hMenu = menuStrip1.Handle;

        //1st call to get the text length into (cch)
        bool res = GetMenuItemInfo(hMenu, (uint)0, true, ref mif); //To load cch into memory
        if (res)
        {
            mif.cch += 1;
            //Set the length of the buffer to cch + 1
            mif.dwTypeData = new string(' ', (int)(mif.cch));
            res = GetMenuItemInfo(hMenu, (uint)0, true, ref mif); //To fill dwTypeData
        }

查看此链接,了解有关字符串的默认封送处理的更多详细信息

老:

您需要初始化 dwTypeData 和 cch 数据成员。

获取菜单项

字符串示例(使用新的菜单项信息结构):

List<string> ls = new List<string>();
IntPtr hMenu = Win32.GetMenu(hWnd);
if (hMenu.ToInt32() != 0)
{
    for (int i = Win32.GetMenuItemCount(hMenu); i >= 0; i--)
    {
        uint MIIM_STRING = 0x00000040;
        uint MFT_STRING  = 0x00000000;
        Win32.MENUITEMINFO mif = new Win32.MENUITEMINFO();
        mif.cbSize = (uint)Marshal.SizeOf(typeof(Win32.MENUITEMINFO));
        mif.fMask = MIIM_STRING;
        mif.fType = MFT_STRING;
        mif.cch = 256;
        mif.dwTypeData = new string(' ', (int)(mif.cch));
        bool a = Win32.GetMenuItemInfo(hMenu, 0, true, ref mif);
        ls.Add(mif.dwTypeData);
    }
}