Why won't GetMenuItemInfo work?

0

I'm trying to read the label names of menu items in an active application and store them in a List<String>.

Unfortunately, dwTypeData ALWAYS returns null. Why is this?

            List<string> ls = new List<string>();
        IntPtr hMenu = Win32.GetMenu(hWnd);

            if (hMenu.ToInt32() != 0)
            {

                for (int i = Win32.GetMenuItemCount(hMenu); i >= 0; i--)
                {
                    try
                    {
                        uint MIIM_STRING = 0x00000040;
                        uint MFT_STRING = 0x00000000;
                        uint MIIM_TYPE = 0x00000010;
                        Win32.MENUITEMINFO mif = new Win32.MENUITEMINFO();
                        mif.cbSize = (uint)Marshal.SizeOf(typeof(Win32.MENUITEMINFO));
                        mif.fMask = MIIM_TYPE;
                        mif.fType = MFT_STRING;
                        mif.cch = 256;
                        mif.dwTypeData = "";
                        Win32.GetMenuItemInfo(hMenu, (uint)i, true, ref mif); //To load cch into memory
                        Win32.GetMenuItemInfo(hMenu, (uint)i, true, ref mif); //To fill dwTypeData
                        ls.Add(mif.dwTypeData);
                    }
                    catch { }

                }
            }

        return ls;
c#
wpf
winapi
pinvoke
asked on Stack Overflow Jun 9, 2013 by Nickersoft • edited Jun 9, 2013 by JoshDM

3 Answers

1

a) the loop should be for (int i = Win32.GetMenuItemCount(hMenu) - 1; i >= 0; i--)

b) before the first call to GetMenuItemInfo(), you need to set mif.dwTypeData to NULL (zero)

c) before the second call to GetMenuItemInfo(), mif.dwTypeData should point to a buffer allocated with a size of mif.cch + 1 -- see MSDN documentation

Make sure you deallocate the memory afterwards!

answered on Stack Overflow Jun 10, 2013 by Edward Clements
1

Your problem is that you are trying to perform this action in a different process. When you call GetMenuItemInfo you pass the address of a MENUITEMINFO struct. But that address is only valid in your process. Because each process has its own private virtual memory space, that pointer that you send has no meaning in the other process.

It's possible that you could use VirtualAllocEx, WriteProcessMemory and ReadProcessMemory to allocate, write and read an instance of the MENUITEMINFO struct in the address space of the other process. That's your only hope of making this mechanism work. There are lots of examples to be found using websearch that illustrate the technique.

However, I would not recommend that you do that. You should use one of the standard automation interfaces to solve your actual problem. For example UIAutomation.

answered on Stack Overflow Jun 10, 2013 by David Heffernan
0

Try to replace

mif.fMask = MIIM_TYPE;
mif.fType = MFT_STRING;

with

mif.fMask = MIIM_FTYPE;
mif.fType = MIIM_STRING;

The Win32 API MENUITEMINFOA documentation states that

MFT_STRING is replaced by MIIM_STRING.

answered on Stack Overflow Oct 17, 2020 by J. F. De Rek ZA

User contributions licensed under CC BY-SA 3.0