【问题标题】:hwnd thread affinity painting from a different threadhwnd 来自不同线程的线程亲和性绘画
【发布时间】:2011-08-03 03:09:03
【问题描述】:

我有一个DGRect::draw(HWND hwnd),它只是在hwnd 窗口句柄上绘制一个空白HBITMAP。 如果我从 main() 调用它,我工作得很好。如果从 QTcpServer Derived 的 DGRDPServer::DGRDPServer() 构造函数调用,它甚至可以正常工作。它也适用于DGRDPServer::listen(qint64 port)。 hwnd 在DGRDPServer 构造函数中传递。当我从DGRDPServer::incomingConnection(int socketDescriptor) 调用它时出现问题,我有hwndqDebug()ed 值,它可以。是什么导致平局失败。 ?? 这是我的DGRect::draw(HWND hwnd)代码

QByteArray ba;
HDC hdc = GetWindowDC(hwnd);
HBITMAP scrn = CreateCompatibleBitmap(hdc,/*width*/200,/*height*/200);
SetBitmapBits(scrn, /*size()*/200*200*4, ba.data());

BITMAP bm;
PAINTSTRUCT ps;
HDC whdc = BeginPaint(hwnd, &ps);
HDC hdcMem = CreateCompatibleDC(whdc);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, scrn);
GetObject(scrn, sizeof(bm), &bm);
BitBlt(whdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);

更新

似乎hwnd 只能从主线程绘制。但是 UpdateWindow 调用来自不同的线程。看起来像DGRDPServer::incomingConnection(int socketDescriptor) 这样的函数是从不同的线程调用的。那么如何从不同的线程绘制hwnd 呢?

【问题讨论】:

  • 所有接收 HWND 的函数都必须由创建窗口的线程创建。这些是规则。

标签: multithreading winapi qt sockets gdi


【解决方案1】:

我的猜测是这里的问题是您使用 BeginPaint:as per docs:应用程序不应调用 BeginPaint,除非响应 WM_PAINT 消息

除此之外,您还可以使用普通的 GetDC/ReleaseDC 而不是 BeginPaint/EndPaint 对。

然而,做这种事情的“windows 方式”是只使用工作线程适当地更新内部数据,然后使用InvalidateRect 或类似的方法告诉 Windows 需要更新窗口, Windows 稍后将发送 WM_PAINT。 UpdateWindow 本质上是一个更直接的版本:它将 WM_PAINT 发送到窗口,然后(这导致实际的绘制发生在该 hwnd 的线程上)。

【讨论】:

  • 如果BeginPaint 在没有WM_PAINT 消息的情况下无法工作,当从DGRDPServer::DGRDPServer() 调用时DGRect::draw(HWND hwnd) 怎么办
  • 文档的意思是:如果你从 WM_PAINT 中调用 BeginPaint,你会没事的。他们说您不应该从 BeginPaint 外部调用它;但不保证它会失败。也许它会一直失败;也许不会。也许它会起作用,但只有在某些限制下。也许它现在可以工作,但在下一个操作系统版本上会失败。违背文档,这样做是有风险的。我的猜测是 BeginPaint 具有线程亲和力:所以如果你从同一个线程调用它,你可能会“走运”。
猜你喜欢
  • 2017-12-06
  • 2011-01-15
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多