【问题标题】:Failed with error 87: The parameter is incorrect. How to determine which parameter is incorrect?失败,错误 87:参数不正确。如何判断哪个参数不正确?
【发布时间】:2020-04-08 06:22:07
【问题描述】:

我正在尝试在单元测试中创建一个尽可能简单的 win32 窗口,但我收到错误 87:如何获取哪个参数不正确?

#include <windows.h>
#include <strsafe.h>

LPTSTR GetErrorMessage(wstring fnName)
{
    LPTSTR messageBuffer{};
    LPTSTR displayBuffer{};
    DWORD dw = GetLastError();

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        0, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&messageBuffer, 0, 0);

    displayBuffer = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, lstrlen(messageBuffer) + (fnName.size() + 40) * sizeof(TCHAR));
    StringCchPrintf(displayBuffer, LocalSize(displayBuffer) / sizeof(TCHAR), L"%s failed with error %d: %s", fnName.c_str(), dw, messageBuffer);

    return displayBuffer;
}

TEST_METHOD(WinTest)
{
    auto hwnd = CreateWindowExW(WS_EX_APPWINDOW, 0, L"test w", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, 0, 0, 0, 0);
    Assert::IsNotNull(hwnd, GetErrorMessage(L"CreateWindowExW"));

    ShowWindow(hwnd, SW_SHOWDEFAULT);
    Sleep(1000);
}

断言失败。 CreateWindowExW 失败,错误 87:参数不正确。

参考:createwindowexw on docs.microsoft.com

【问题讨论】:

  • 类名不能为0
  • @walnut 对。我按照您的建议进行了编辑,以消除这种干扰。

标签: c++ winapi


【解决方案1】:

回答您提出的特定 问题 - Win32 API 不会告诉您WHICH 参数无效。您必须阅读失败函数的文档,然后调试代码以比较您实际传递给函数的值,看看它们与函数期望的可接受值有何不同。

在这个特定的示例中,您将一个空指针传递给CreateWindowEx()lpClassName 参数,这是不允许的。您必须指定要创建的窗口类的名称。


附带说明,您的GetErrorMessage() 函数正在泄漏内存,因为它不会释放FormatMessage()LocalAlloc() 分配的内存。 messageBufferdisplayBuffer 都需要用 LocalFree() 释放。

我强烈建议您让 GetErrorMessage() 返回 wstring 而不是原始的 TCHAR* 指针,例如:

wstring GetErrorMessage(const wstring &fnName)
{
    DWORD dw = GetLastError();

    wostringstream displayBuffer;
    displayBuffer << fnName << L" failed with error " << dw;

    LPWSTR messageBuffer{};
    if (FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        0,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&messageBuffer,
        0,
        0))
    {
        displayBuffer << L": " << messageBuffer;
        LocalFree(messageBuffer);
    }

    return displayBuffer.str();
} 

【讨论】:

  • 调用GetLastError 可能为时已晚。错误代码必须是函数的输入。由于不同的原因,实现仍然会泄漏内存。请参阅 this answer 以获取强大的实现。
  • @IInspectable 只有在displayBuffer 抛出异常时才会泄漏,如果有的话,这种情况很少见。
  • 在内存变得稀缺时泄漏内存可能不是一个可持续的策略。当然不是在你编写诊断代码时。虽然你不知道这段代码最终运行的环境,但你也不能对它做出任何假设(就像暗示的那样,目标系统无论如何都没有准备好处理内存不足的情况)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-20
  • 1970-01-01
  • 2021-06-28
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多