I'm seeing a very similar problem with my BitBlt's. It will return FALSE only occasionally (once every few hours, being called a few times a second) and an immediate call to GetLastError returns 0.
MFC in VS .NET 2003. I don't know what Hyperthreading is or whether I have it enabled, though.
We have a dialog app that connects over TCP/IP to a server and receives video data. On the data receive callback, we BitBlt the image into a CDC that was created in initialization using the following:
CDC* clientDC = this->GetWindowDC();
if(clientDC == NULL)
throw -1;
if(! m_imageMemDC.CreateCompatibleDC(clientDC) )
throw -1;
if(! m_imageMemBitmap.CreateCompatibleBitmap(clientDC, CAM_W*m_numCamW, CAM_H*m_numCamH))
throw -1;
if( (m_pImageMemOldBitmap = m_imageMemDC.SelectObject(&m_imageMemBitmap)) == NULL )
throw -1;
this->ReleaseDC(clientDC);
A Timer control is used to send a WM_PAINT every second. OnPaint, we StretchBlt the m_imageMemDC to the screen, as follows:
CDC* clientDC = this->GetWindowDC();
if(clientDC == NULL)
return;
clientDC->SetStretchBltMode(COLORONCOLOR);
EnterCriticalSection(&m_imageMemDCSection);
clientDC->StretchBlt(0, 0, clientWidth, clientHeight, &m_imageMemDC, 0, 0, CAM_W*m_numCamW, CAM_H*m_numCamH, SRCCOPY)
LeaveCriticalSection(&m_imageMemDCSection);
this->ReleaseDC(clientDC);
As you can see, we use a CCriticalSection, and lock it every time we access m_imageMemDC. Here's the BitBlt code:
EnterCriticalSection(&m_imageMemDCSection);
if(! ::BitBlt(m_imageMemDC.GetSafeHdc(), posX, posY + GetInfoBarHeight(), width-2, height - GetInfoBarHeight() *2,imgPtr->GetDC(), 0, 0, SRCCOPY))
{
CString info;
info.FormatMessage(IDS_E_BITBLT, _camID, GetLastError());
theLog.Log(info, EVENTLOG_ERROR_TYPE, 0, 0, CRITICAL);
TRACE (info);
}
LeaveCriticalSection(&m_imageMemDCSection);
As previously mentioned, we get the eventlog error, which includes the GetLastError() return code as '0', on average once an hour, but not at a regular interval.
Why does BitBlt fail?
Thanks.
ASKER
Yes, I appreciate too that this is likely a design issue. I can provide other sections of code to test theories, but not my entire application...
I know that it is a best practice to keep critical section (ie. locked) code to a minimum, but I don't see how it could cause an error, in this example, with another function call that requires access to the same lock.
Also, I'm not sure I understand how to synchronize my "handling of that object ... to the main thread". I think that I'm already doing it using the Critical Section. I can't BitBlt when I'm StretchBlt'ing and vice versa.
You're certainly right about our performing a lot of processing in critical sections. I should add that we actually lock twice in OnDraw, the first time to do some drawing of text and rectangles on the DC, and then the second for the StretchBlt. The only other times we lock are for the BitBlt on the socket thread, and in initialization when we set up the DC.