Сообщение WM_PAINT, цикл BeginPaint

Я не могу понять, почему я получил цикл на функцию BeginPaint. Я уже читал сообщения об этом цикле, но почти все они рекомендуют: "Не забудьте использовать функцию BeginPaint в сообщении WM_PAINT, потому что в противном случае это повлечет за собой последующие сообщения WM_PAINT". Это не мой случай. Можете ли вы дать мне несколько советов?

Это мой оконный класс ("CWindow"):

class CWindow {
public:

   CWindow();
   virtual ~CWindow();
   bool RegisterClass(HINSTANCE hInstance);
   bool CreateWnd(HINSTANCE hInstance);
   bool Show(int nShow);
private:

    HWND handleWindow;
    ATOM atom;
    bool isRegistered;
    bool isCreated;
    static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    void OnPaint();
    void OnDestroy();
};

Функция WndProc.

LRESULT CALLBACK CWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{  
    CWindow* windowPtr = reinterpret_cast<CWindow*> ( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
    PAINTSTRUCT ps;
    HDC hdc;
    switch( msg ) {  
        case WM_PAINT:
            // There is a loop right here!
            hdc = BeginPaint( windowPtr->handleWindow,  &ps );
            // The code below doesn't executed!
            RECT rect;
            (void)GetClientRect(windowPtr->handleWindow, &rect);

            (void)DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect,
            DT_SINGLELINE | DT_CENTER | DT_VCENTER);

            EndPaint( windowPtr->handleWindow, &ps );
            break;
        case WM_DESTROY:
            windowPtr->OnDestroy();
            break;
        default:
            return DefWindowProc( hWnd, msg, wParam, lParam );
    }
    return 0;
}

RegisterClass

bool CWindow::RegisterClass(HINSTANCE hInstance)
{
    const TCHAR app_name[] = TEXT("HelloWin");
    WNDCLASSEX  windowClass;

    ZeroMemory( &windowClass, sizeof(windowClass) );
    windowClass.cbSize = sizeof(windowClass);
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = WindowProc;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hInstance = hInstance;
    windowClass.hIcon = 0;
    windowClass.hIcon = 0;
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = 0;
    windowClass.lpszMenuName = NULL;
    windowClass.lpszClassName = app_name;
    windowClass.hIconSm = NULL;

    atom = RegisterClassEx( &windowClass );
    DWORD errorCode = GetLastError();
    if( errorCode ) {
        isRegistered = 0;
        std::wcout << L"ErrorCode: " << errorCode << std::endl;
    } else {
        isRegistered = 1;
    }
    return isRegistered;
}

CreateWindow

bool CWindow::CreateWnd(HINSTANCE hInstance)
{
    handleWindow = CreateWindow((PCTSTR)atom,               // window class name or atom
                         TEXT("The Hello Program"),  // window caption
                         WS_OVERLAPPEDWINDOW,        // window style
                         CW_USEDEFAULT,              // initial x position
                         CW_USEDEFAULT,              // initial y position
                         CW_USEDEFAULT,              // initial x size
                         CW_USEDEFAULT,              // initial y size
                         NULL,                       // parent window handle
                         NULL,                       // window menu handle
                         hInstance,                  // program instance handle
                         NULL);                      // creation parameters 
    DWORD errorCode = GetLastError();
    if( !handleWindow ) {
        isCreated = 0;
    } else { 
        isCreated = 1;
    }
    return isCreated;
}

Шоу

bool CWindow::Show(int nShow)
{
    if( isCreated ) {
        ShowWindow( handleWindow, nShow );
        return UpdateWindow( handleWindow );
    } else {
        return 0;
    }
}

WinMain

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevINstance, LPSTR lpCmdLine, int nShow )
{
    CWindow window;
    window.RegisterClass( hInstance );
    window.CreateWnd( hInstance );
    window.Show( nShow );
    int response = 0;
    MSG msg;
    while( GetMessage( &msg, 0, 0, 0 ) ) {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
        return 0;
    }

1 ответ

Решение

Так как ты никогда не звонишь SetWindowLongPtr,

CWindow* windowPtr = reinterpret_cast<CWindow*>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );

возвращает nullptr, что вы впоследствии попытаетесь разыменовать

BeginPaint( windowPtr->handleWindow,  &ps )

Это вызовет исключение нарушения прав доступа, вызывая BeginPaint вызов никогда не будет выполнен, оставив неправильный регион как есть. Как следствие, система продолжает генерировать WM_PAINT Сообщения. Это та же проблема, что и не звонить BeginPaint в целом. 1

Чтобы решить эту проблему, вам нужно либо прикрепить дескриптор окна к экземпляру окна, вызвав SetWindowLongPtr или просто используйте hWnd параметр, который передается в ваш CWindow::WindowProc,


1 Обратите внимание, что при определенных условиях система автоматически обрабатывает необработанные исключения в WindowProc в 64-разрядных версиях Windows.

Другие вопросы по тегам