Isn't taking a screenshot on Windows thread-safe?
My following code sometimes takes some shots, but in most cases, the imgScreenshot (which is just a TImage) keeps being just plain white...
Am I missing something?
void __fastcall TCaptureThread::Execute()
{
int CurWidth = 1600;
int CurHeight = 900;
std::unique_ptr<TCanvas> Canvas(new TCanvas);
Canvas->Handle = GetDC(0);
FBMP = new TBitmap; // private class field
FBMP->Width = CurWidth;
FBMP->Height = CurHeight;
FR = Rect(0, 0, CurWidth, CurHeight); // private class field
while(!Terminated)
{
FBMP->Canvas->CopyRect(FR, Canvas, FR);
Synchronize(&UpdatePicture);
Sleep(100);
}
delete FBMP;
FBMP = NULL;
}
void __fastcall TCaptureThread::UpdatePicture()
{
FMainForm->imgScreenshot->Canvas->CopyRect(FR, FBMP->Canvas, FR);
}
Environment is C++ Builder 10.1.2 Berlin
Not when using VCL wrapper classes that are not thread-safe by default. If you were using plain Win32 API functions directly, then yes, it would be possible to write thread-safe code.
The main reason your code fails is because the VCL is designed to share GDI resources between multiple objects, and the main UI thread frequently frees unused/dormant GDI resources. So your worker thread's
TBitmap
image data is likely to get destroyed before you can callSynchronize()
to copy it to yourTImage
.That being said, what you are attempting can be done if you call
Lock()
/Unlock()
on theCanvas
objects in your worker thread, eg:That being said, because
TCanvas
is lockable, you might be able to get away with removingSynchronize()
altogether: