没有采取在Windows线程安全的屏幕截图?
不使用默认情况下不是线程安全的VCL包装类时。如果您直接使用简单的Win32 API函数,那么是的,可以编写线程安全的代码。
您的代码失败的主要原因是因为VCL旨在共享多个对象之间的GDI资源,并且主UI线程经常释放未使用/休眠的GDI资源。因此,您的工作线程的TBitmap
图像数据很可能会被破坏,然后您可以致电Synchronize()
将其复制到您的TImage
。
话虽这么说,你正在尝试什么可以来,如果你请在您的工作线程Canvas
对象Lock()
/Unlock()
进行,例如:
struct CanvasLocker
{
TCanvas *mCanvas;
CanvasLocker(TCanvas *C) : mCanvas(C) { mCanvas->Lock(); }
~CanvasLocker() { mCanvas->Unlock(); }
};
void __fastcall TCaptureThread::Execute()
{
int CurWidth = 1600;
int CurHeight = 900;
std::unique_ptr<TCanvas> Canvas(new TCanvas);
std::unique_ptr<TBitmap> BMP(new TBitmap);
FBMP = BMP.get();
{
CanvasLocker lock(Canvas); // <-- add this!
Canvas->Handle = GetDC(0);
}
{
CanvasLocker lock(BMP->Canvas); // <-- add this!
BMP->Width = CurWidth;
BMP->Height = CurHeight;
}
FR = Rect(0, 0, CurWidth, CurHeight);
while (!Terminated)
{
{
CanvasLocker lock1(Canvas); // <-- add this!
CanvasLocker lock2(BMP->Canvas); // <-- add this!
BMP->Canvas->CopyRect(FR, Canvas.get(), FR);
}
Synchronize(&UpdatePicture);
Sleep(100);
}
}
void __fastcall TCaptureThread::UpdatePicture()
{
CanvasLocker lock1(FBMP->Canvas); // <-- add this!
CanvasLocker lock2(FMainForm->imgScreenshot->Canvas); // <-- add this!
FMainForm->imgScreenshot->Canvas->CopyRect(FR, FBMP->Canvas, FR);
// or: FMainForm->imgScreenshot->Picture->Bitmap->Assign(FBMP);
}
话虽这么说,是因为TCanvas
是上锁的,你可能能够与完全消除Synchronize()
闪避:
void __fastcall TCaptureThread::Execute()
{
int CurWidth = 1600;
int CurHeight = 900;
std::unique_ptr<TCanvas> Canvas(new TCanvas);
std::unique_ptr<TBitmap> BMP(new TBitmap);
{
CanvasLocker lock(Canvas);
Canvas->Handle = GetDC(0);
}
{
CanvasLocker lock(BMP->Canvas);
BMP->Width = CurWidth;
BMP->Height = CurHeight;
}
TRect r = Rect(0, 0, CurWidth, CurHeight);
while (!Terminated)
{
{
CanvasLocker lock1(BMP->Canvas);
{
CanvasLocker lock2(Canvas);
BMP->Canvas->CopyRect(r, Canvas.get(), r);
}
CanvasLocker lock3(FMainForm->imgScreenshot->Canvas);
FMainForm->imgScreenshot->Canvas->CopyRect(r, BMP->Canvas, r);
// or: FMainForm->imgScreenshot->Picture->Bitmap->Assign(BMP);
}
Sleep(100);
}
}
谢谢,雷米,F或者这个非常详细的答案。我通过锁定上述画布来完成并运行,但同步仍然是必须的。没有它我得到了一些随机AV。 (通过最终方式:我绝对喜欢你的“本地部分RAII”。 – FlKo