ahdung
ahdung

Reputation: 409

P/Invoke RemoveMenu SetLastError not working

my codes:

[DllImport("user32.dll", SetLastError = true)]
static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);

static void RemoveMenu(IntPtr hMenu, int item, bool byPosition)
{
    if (!RemoveMenu(hMenu, (uint)item, (uint)(byPosition ? 0x400 : 0)))
    {
        throw new Win32Exception();
    }
}

RemoveMenu(xxx, -1, false); //got exception and it's message is: The operation completed successfully.

This means that API didn't Set the LastError when it failed. why and how?

RemoveMenu API doc.

Upvotes: 0

Views: 203

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596417

Technically, the behavior is not wrong. The documentation merely says to call GetLastError() on failure, but it doesn't say that GetLastError() can't return 0 as the reason. And indeed, at least according to CMenu::RemoveMenu  is failing, 0 is actually what is reported (though something like ERROR_MENU_ITEM_NOT_FOUND would have made more sense).

This is very easy to work around, using Marshal.GetLastWin32Error() before throwing the Win32Exception:

[DllImport("user32.dll", SetLastError = true)]
static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);

static void RemoveMenu(IntPtr hMenu, int item, bool byPosition)
{
    if (!RemoveMenu(hMenu, (uint)item, (uint)(byPosition ? 0x400 : 0)))
    {
        int err = Marshal.GetLastWin32Error();
        if (err != 0)
            throw new Win32Exception(err);
    }
}

RemoveMenu(xxx, -1, false);

Upvotes: 1

Related Questions