沒有采取在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