gpt4 book ai didi

c++ - 使用 C++ Builder 在 Windows 上截取屏幕截图的线程安全

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:11:15 25 4
gpt4 key购买 nike

在 Windows 上截屏不是线程安全的吗?

我的以下代码有时会拍摄一些照片,但在大多数情况下,imgScreenshot(这只是一个 TImage)一直只是纯白色...

我错过了什么吗?

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);
}

环境是 C++ Builder 10.1.2 Berlin

最佳答案

Isn't taking a screenshot on Windows thread-safe?

在使用默认情况下不是线程安全的 VCL 包装器类时不是。如果您直接使用普通的 Win32 API 函数,那么可以编写线程安全代码。

您的代码失败的主要原因是因为 VCL 旨在在多个对象之间共享 GDI 资源,而主 UI 线程经常释放未使用/休眠的 GDI 资源。因此,您的工作线程的 TBitmap 图像数据可能会在您调用 Synchronize() 将其复制到您的 TImage 之前被破坏。

也就是说,如果您在 上调用 Lock()/Unlock(),您正在尝试的可以完成工作线程中的 Canvas 对象,例如:

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);
}
}

关于c++ - 使用 C++ Builder 在 Windows 上截取屏幕截图的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41149999/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com