我想实现在多个窗口同时播放幻灯片的功能:
为此,我在显示图片窗口类的OnPaint中有部分相关代码:
CRect rect;
GetClientRect(&rect);
BITMAP bm;

CSingleLock slock(&kBitmapValidMutex);
slock.Lock();
CBitmap* pOldBitmap = kpMemDC->SelectObject(kpBitmap);
kpBitmap->GetObject(sizeof(BITMAP), &bm); dc.StretchBlt(0, 0, rect.Width(), rect.Height(), kpMemDC, 0, 0, 
bm.bmWidth, bm.bmHeight, SRCCOPY);
CBitmap* pBitmap = kpMemDC->SelectObject(pOldBitmap);


其中,kpMemDC是窗口类的CDC* 成员,在OnCreate()中通过以下方式取得:
CDC* pDC = GetDC();
kpMemDC = new CDC;
kpMemDC->CreateCompatibleDC(pDC);

kpBitmap是CBitmap* 成员,在OnCreate()中初试化
HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, "hello.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CBitmap* kpBitmap = new CBitmap;
kpBitmap->Attach(hBitmap);

在这几个窗口的父窗口有一个线程在跑,分别用相应的图片更新相应子窗口的kpBitmap, 由于其他的原因,此线程只能放在父窗口中。
CSingleLock slock(&kpWnd[wndNum]->kBitmapValidMutex);
slock.Lock();
kpBitmapArray[wndNum]->DeleteObject();
//kpBitmapArray[wndNum]->Detach();
delete kpBitmapArray[wndNum];
kpBitmapArray[wndNum] = pNewBitmap;
slock.Unlock(); 其中,kpWnd[wndNum]是指向各子窗口的指针。kpBitmapArray[wndNum]指向各窗口的kpBitmap.pNewBitmap是更新后的CBitmap* 。

现在出现的问题是,程序在跑了一段时间后,在上面列出的显示子窗口的OnPaint()中的一行代码:
CBitmap* pBitmap = kpMemDC->SelectObject(pOldBitmap);
出现异常。
跟踪发现是返回的pBitmap->m_hObject和前面选进的kpBitmap->m_hObject不一样。
进一步发现这种情况只有在子窗口的OnPaint()没有执行完,而父窗口线程开始更新另一个子窗口的图片时才会出现。但我在父窗口线程中删除的是其他子窗口的Bitmap,同一子窗口已经用互斥体保护了,可以证实是不会出现同步问题的。
另外我还发现所有子窗口的pOldBitmap->m_hObject都一样。是不是其他窗口在刷新的时候把某一窗口的DC位图映像搞混了。可是各窗口都是独立的呀。
大家帮帮忙看看怎么解决。谢谢!

解决方案 »

  1.   

    注册子窗口时指定 CS_OWNDC 试试,不过这比较浪费资源;或者指定 CS_PARENTDC 并同步对 Device Context 的访问。多个窗口的 Device Context 可能是共享的,这取决于窗口类的 style ,和 Device Context 共享有关的标志是:CS_OWNDC, CS_CLASSDC, CS_PARENTDC 
      

  2.   

    谢谢In355Hz,先给你20分。不管我指定CS_PARENTDC或者CS_OWNDC风格,都无法经受Stress test的考验,最长跑了1个多小时,就出错了。错误情况依然。如果用CS_OWNDC,甚至创建的第一个窗口无法显示。并且速度很慢。如果指定CS_CLASSDC, 我在任何子窗口上GetDC后画的东西都显示在第一个窗口上,因为MSDN认为WIN32的程序不应使用它,所以我没有做强力测试。我也尝试了在 OnPaint中设置一个父窗口成员的互斥体,让每个子窗口互斥的执行OnPaint,在父窗口线程做删除位图操作前也设置相同的互斥体,保证每个子窗口退出OnPaint前不做删除操作。但仍然不能解决问题。到底是什么原因?
      

  3.   

    i think, the problem is caused by thread synchronization.you must declare global CSingleLock variable,not local variable, so all threads can require the global lock to do self draw。