GetWindowLongPtr将错误设置为“类已存在”

时间:2012-03-09 02:45:03

标签: c++ winapi wrapper

在我的Windows API包装器中,我可以选择在出现错误时出现一个消息框。我有一个我真的无法确定的。

这是我的主要功能:

int main()
{
    Window win; //create default window with default class (name changes each new instance)

    return messageLoop(); //the familiar GetMessage() while loop, returns msg.wParam
}

这一切都很好,但当我关闭我的窗口(刚刚通过X按钮测试)时,我收到以下消息(这是我在复制消息框时得到的):

---------------------------
Error
---------------------------
File: "G:\programming\v2\wwbasewindow.h"
Function: _fakeWndProc
Line: 61
Error Code: 1410
Error: Class already exists.


---------------------------
OK   
---------------------------

现在很清楚这个错误来自何处,但不完全是为什么。这是_fakeWndProc函数。调用该函数后,整个wrap (function, args)语法检查GetLastError()。这就是您没有看到错误检查的原因。

LRESULT CALLBACK BaseWindow::_fakeWndProc (msgfillparams) //trick procedure (taken from someone's gui wrapper guide)
{
    BaseWindow * destinationWindowPtr = 0; //for which window message goes to

    //PROBLEM IN THE FOLLOWING LINE (gets a pointer to the window, set when it's created)
    destinationWindowPtr = (BaseWindow *)wrap (GetWindowLongPtr, hwnd, GWLP_USERDATA);

    if (msg == WM_COMMAND && lParam != 0) //if control message, set destination to that window
        destinationWindowPtr = (BaseWindow *)wrap (GetWindowLongPtr, (hwin)lParam, GWLP_USERDATA);

    if (destinationWindowPtr) //check if pointer is valid
        return destinationWindowPtr->_WndProc (hwnd, msg, wParam, lParam); //call window's procedure
    else
        return wrap (DefWindowProc, hwnd, msg, wParam, lParam); //call default procedure
}

我只是想知道为什么这个调用是(尝试创建一个类?)除此之外,我尝试从WM_CLOSE消息出现时检查错误代码。我在行之前和之后输出代码。这是出现的结果:

Before: 0
After: 0
--->Before: 0
--->Before: 1410
After: 1410
Before: 1410
After: 1410
...

这让我感到困惑,因为这意味着函数会在内部某处调用SendMessage。但为什么不为其他人做同样的事情呢?

错误本身并没有太大的区别,因为程序刚刚结束,但我不想让它闲逛。我该如何处理?

注意: 我只是在PostQuitMessage (0);出现时尝试不调用WM_DESTROY,并创建了2个窗口。两个人在关闭时都给出了相同的错误,所以不一定是程序的结束。

此外,每个人都给出了错误1400(无效的窗口句柄),但仅在我没有调用PostQuitMessage时。此错误源自在这些窗口的相应窗口过程中对DefWindowProc的调用。关于那个的任何想法吗?

编辑:

根据请求,以下是wrap的代码:

// pass along useful error information (useless constants within error function)
#define wrap(...) Wrap (__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)

// cstr == char *
// con == const
// sdword == int (signed dword)

// version if return value of API function is not void
template<typename TRet, typename... TArgs>
typename std::enable_if<!std::is_void<TRet>::value, TRet>::type
Wrap(con cstr file, const char * const func, con sdword line, TRet(*WINAPI api)(TArgs...), TArgs... args)
{
    TRet result = api(std::forward<TArgs>(args)...); //call API function
    if (GetLastError()) __wwError.set (GetLastError(), file, func, line); //set variables and create message box
    return result; // pass back return value
}

// version if return value is void
template<typename... TArgs>
void Wrap(con cstr file, const char * const func, con sdword line, void(*WINAPI api)(TArgs...), TArgs... args)
{
    api(std::forward<TArgs>(args)...);
    if (GetLastError()) __wwError.set (GetLastError(), file, func, line);
}

我100%肯定这一点,__wwError.set()虽然有效。用它包装的所有其他函数都会给出相应的消息框。

1 个答案:

答案 0 :(得分:7)

您对GetLastError的调用完全不正确。你不能不加区分地调用GetLastError。您应该只在API调用文档说它有效时才调用它。通常情况下,如果API调用报告失败。

对DefWindowProc的调用很好地说明了这可能会出错。 DefWindowProc的文档没有提到函数报告失败的方法。它没有提到调用GetLastError。因此,不应该对GetLastError进行调用,并且返回未定义的,无意义的值。

由于Win32函数没有单一的通用机制来报告失败,因此尝试使用单个常见错误处理例程包装所有Win32 API调用注定要失败。

您需要做的是根据自己的优点处理每个API调用,并编写适合该API调用的错误检查。由于您使用的是C ++,我建议您在此处使用例外。写一个函数,ThrowLastWin32Error说,只要API函数报告失败就会调用。 ThrowLastWin32Error的实现将调用GetLastError,然后在抛出适当的描述性异常之前调用FormatMessage以获取文本描述。你可以这样使用它:

if (!CallSomeWin32Function())
    ThrowLastWin32Error();

但重点是你确实需要逐个检查函数是否成功,因为不同的Win32函数会以不同的方式报告失败。