1

已解决:我已经发布了我的解决方案作为答案。

这是我的问题:(gif)(如果我在任何 WM_PAINT 消息之前取消最小化时重新加载位图以绘制背景图像,则可以解决。)

背景消失

每当我取消最小化应用程序,应用程序首次显示 OK 的时间(除非您正在使用调试器单步执行,否则会短暂显示一秒钟),然后突然变黑(或在应用程序窗口类中设置为 hbrBackground 的任何颜色)时,都会发生这种情况。我可以通过重新加载 WM_PAINT 中使用的 HBITMAP 来防止这种行为,这些 HBITMAP 是全局变量,并在应用程序启动时使用相应的值进行初始化。

gif 开始显示应用程序在最小化后重新打开,调试器逐步通过 Rich Edit Control 消息循环的父窗口,所有窗口的背景变为黑色之前和之后的时刻,然后进入 Rich Edit Control 子类消息循环,进入 WM_PAINT。

  • 如果我在应用程序之间切换而相关应用程序以前从未被最小化过,这永远不会发生。
  • 如果富编辑控件 (RICHEDIT50W) 之前没有显示任何文本,即不会发生这种情况。如果没有显示任何文本,该应用程序可以正常工作。
  • 这是窗口树:
    • 主窗口
      • 一些子窗口
      • 子窗口 1
        • 丰富的编辑控制

踏出子窗口 1 WndProc;进入 WndSubclassProcWhatever 回调中 Rich Edit Control 的 WM_PAINT。

在意识到在 unminimize 之后调用 LoadImage() 可以解决后台问题之前,我做了一些事情:

  • 用子类拦截富编辑控件的消息循环,并处理(以及在每个其他窗口中)消息:WM_COMMAND、WM_IME_NOTIFY、WM_NCPAINT、WM_WINDOWPOSCHANGED、WM_WINDOWPOSCHANGING、WM_ERASEBKGND... 主要返回与 DefSubclassProc/DefWindowProcW 不同的内容.

  • 重新打开应用程序后立即调用 ValidateRect() ...

    在此之前发生过这种情况,而不是整个应用程序变黑,只有文本“突出显示”或富编辑控件父级变黑,整个应用程序在另一个最小化取消最小化周期后变黑。

我在更新的 Windows 10 中使用具有默认设置的 Visual Studio Community 2019,并且在发布和调试版本中都看到了这个问题。

我现在期待防止位图“卸载”,从而节省许多看似不必要的 LoadImage() 调用。解决了

我尝试上传代码的最小版本,但行为结果并不完全相同,所以感谢之前给出的答案!

4

2 回答 2

3

这与 Rich Edit Control 无关,即使您删除所有控件,也会发生这种情况。

您所要做的就是在注册窗口时为窗口背景添加默认颜色。

这里:

ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEXW wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style = CS_DBLCLKS;
        wcex.lpfnWndProc = WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = hInstance;
        wcex.hIcon = NULL; // Procesás WM_GETICON
        wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground = NULL;
        wcex.lpszMenuName = NULL;
        wcex.lpszClassName = L"mainWindowClass";
        wcex.hIconSm = NULL; // Procesás WM_GETICON

        return RegisterClassExW(&wcex);
    }

最小化窗口后再次点击会导致它使用默认的背景颜色重绘,但是您在这里将背景颜色设置为NULL。所以尝试更改wcex.hbrBackground = NULLwcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1)

更新:

听起来你和我以前遇到的问题一样。

这是我之前的代码:

 case WM_PAINT:
        {
            PAINTSTRUCT ps;
           HDC hdc =  BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here... 
           hdcMem = CreateCompatibleDC(hdc);
           HGDIOBJ previousbit = SelectObject(hdcMem, hBmp);
           AlphaBlend(hdc, 0, 0, width_1, height_1, hdcMem, 0, 0, width_1, height_1, bf);
           DeleteDC(hdcMem);
           EndPaint(hWnd, &ps);
        }
        break;
case WM_MOUSEWHEEL:
    {
        if (GET_WHEEL_DELTA_WPARAM(wParam) > 0 && bTrans <= 234)
        {
            bTrans += 20;
            bf.SourceConstantAlpha = bTrans;
            InvalidateRect(hWnd, NULL, TRUE);
        }
        if (GET_WHEEL_DELTA_WPARAM(wParam) < 0 && bTrans >= 20)
        {
            bTrans -= 20;
            bf.SourceConstantAlpha = bTrans;
            InvalidateRect(hWnd, NULL, TRUE);
        }
        return 0;
    }

我滑动鼠标滚轮,它会触发InvalidateRect(hWnd, NULL, TRUE);

但是如果我 delete DeleteDC(hdcMem),它将返回一个没有图片的主窗口。

调试快照是:

在此处输入图像描述

是的,您可以找到previousbit == NULL.

正如@Remy Lebeau 所说,您正在泄漏返回的HBITMAP内容SelectObject(),并允许您在背后HDC破坏您的潜在利益。bitmapBackgroundMainWindow

这是主要原因。

于 2019-10-30T06:12:37.400 回答
1

调用 DeleteObject() 解决了这个问题。

这是来自使用相应 DeleteObject() 调用修复的位图背景窗口 WM_PAINT 消息之一的代码:

    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    HDC temporaryDC = CreateCompatibleDC(hdc);
    BITMAP bitmapToBitBlt;
    HGDIOBJ hgdiobjToBitBlt = SelectObject(temporaryDC, bitmapBackgroundMainWindow);
    GetObjectW(bitmapBackgroundMainWindow, sizeof(BITMAP), &bitmapToBitBlt);
    BitBlt(hdc, 0, 0, bitmapToBitBlt.bmWidth, bitmapToBitBlt.bmHeight, temporaryDC, 0, 0, SRCCOPY);
    DeleteObject(temporaryDC); // This fixes the app.
    EndPaint(hWnd, &ps);
    return 0;

正如Windows Docs所说,在调用 CreateCompatibleDC() 之后:

当您不再需要内存 DC 时,调用 DeleteDC 函数。我们建议您调用 DeleteDC 来删除 DC。但是,您也可以使用 HDC 调用 DeleteObject 来删除 DC。

这如何转化为我的应用程序的意外行为,我不知道,请随时在评论中澄清!

于 2019-10-30T13:28:27.773 回答