GetWindowLongPtr устанавливает Error в «Класс уже существует» - PullRequest
1 голос
/ 09 марта 2012

В моей оболочке 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 Ответ

7 голосов
/ 09 марта 2012

Ваши вызовы GetLastError просто неверны. Вы не можете без разбора вызывать GetLastError таким образом. Вы должны вызывать его только тогда, когда в документации по вызовам API сказано, что это действительно так. Обычно это происходит, если вызов API сообщает об ошибке.

Вызовы DefWindowProc являются прекрасной иллюстрацией того, как это может пойти не так. В документации для DefWindowProc не упоминается способ сообщения о сбое функции. И это не упоминает о вызове GetLastError. Таким образом, ваши вызовы GetLastError не должны выполняться и возвращают неопределенные, бессмысленные значения.

Поскольку для функции Win32 не существует единого общего механизма сообщения о сбое, ваша попытка обернуть все вызовы Win32 API одной общей процедурой обработки ошибок обречена на провал.

Что вам нужно сделать, это обработать каждый вызов API с учетом его достоинств и записать проверку ошибок, соответствующую этому вызову API. Поскольку вы используете C ++, я бы порекомендовал вам использовать здесь исключения. Напишите функцию, скажем ThrowLastWin32Error, которую вы вызываете всякий раз, когда функция API сообщает об ошибке. Реализация ThrowLastWin32Error вызовет GetLastError, а затем вызовет FormatMessage, чтобы получить текстовое описание, прежде чем выдавать подходящее описательное исключение. Вы бы использовали это так:

if (!CallSomeWin32Function())
    ThrowLastWin32Error();

Но суть в том, что вам нужна индивидуальная проверка успешности функции, поскольку различные функции Win32 по-разному сообщают о сбое.

...