1

我不明白为什么我在 BeginPaint 函数上有一个循环。我已经阅读过关于这种循环的帖子,但几乎所有帖子都推荐:“不要忘记在 WM_PAINT 消息上使用 BeginPaint 函数,否则它需要后续的 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;
}

注册类

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;
}

创建窗口

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;
    }
4

1 回答 1

1

既然你从来不打电话SetWindowLongPtr

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

返回 a nullptr,您随后尝试取消引用:

BeginPaint( windowPtr->handleWindow,  &ps )

这将触发访问冲突异常,导致BeginPaint调用甚至永远不会被执行,从而使无效区域保持原样。结果,系统不断生成WM_PAINT消息。这与完全不打电话是同一个问题BeginPaint1

要解决这个问题,您要么必须通过调用将窗口句柄附加到窗口实例SetWindowLongPtr,要么只需使用hWnd传递给您的CWindow::WindowProc.


1 请注意,在某些条件下,系统会在 64 位版本的 Windows 上静默处理WindowProc中未处理的异常。

于 2018-08-03T11:42:36.163 回答