【问题标题】:P/Invoke RemoveMenu SetLastError not workingP/Invoke RemoveMenu SetLastError 不起作用
【发布时间】:2020-05-07 02:08:03
【问题描述】:

我的代码:

[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.

这意味着 API 在失败时没有设置 LastError。为什么以及如何?

RemoveMenu API 文档。

【问题讨论】:

  • 成功无法删除菜单项#4294967295。它不存在。您可以使用 Marshal.GetLastWin32Error() 来防止引发异常。但实际上,您会修复代码以指定正确的菜单项。
  • 先谢谢你的评论。我正在编写一个组件,而不是调用者,所以我希望它在失败时抛出一个正确的错误。现在如果hMenu 是无效句柄,它可以工作,但如果项目是不存在的项目,则错误消息不正确。
  • "但是如果item是不存在的item,错误信息是不正确的。" 尝试先使用GetMenuItemInfo来检查item是否存在。(error code = @ 987654326@如果不存在)

标签: c# .net winapi pinvoke


【解决方案1】:

从技术上讲,这种行为并没有错。文档只是说在失败时调用GetLastError(),但并没有说GetLastError() 不能返回0 作为原因。事实上,至少根据CMenu::RemoveMenu  is failing 的说法,0 实际上是报告的内容(尽管像ERROR_MENU_ITEM_NOT_FOUND 这样的东西会更有意义)。

这很容易解决,在抛出Win32Exception之前使用Marshal.GetLastWin32Error()

[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);

【讨论】:

  • "return 0 as the reason" 实际上,正如我测试的那样,它没有设置最后一个错误,我在RemoveMenu之前调用setlasterror。然后调用getlasterror:得到setlasterror中设置的相同值。我会在内部确认这种行为。
  • @DrakeWu-MSFT 如果这是真的,那么文档是错误的。
  • 问题是当item不存在时,API没有SetLastError,所以GetLastWin32Error是其他API的结果,这个不靠谱。但现在我想我理解了这个设计。实际上,删除不再存在的项目应该不会报告错误。这是一个预期的结果,所以只需处理 code == ERROR_INVALID_MENU_HANDLE 就够了。
  • @ahdung 如果这是真的,那么您会期望它返回true 而不是false,但事实并非如此。如果没有调用SetLastError(),您希望如何获得ERROR_INVALID_MENU_HANDLE
  • @rem 我同意这个API应该在item不存在时返回true,如果返回false,它必须设置最后一个错误。至于ERROR_INVALID_MENU_HANDLE,在我的测试中,它工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
  • 2014-02-24
相关资源
最近更新 更多