这段代码线程安全吗
// experimental code
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width,
Height: Integer; out Bitmap: TBitmap );
var
AExtension: string;
ARect: TRect;
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
Image1.Picture.LoadFromFile( Path ); // added at design time to form
Bitmap := TBitmap.Create;
Bitmap.Width := Width;
Bitmap.Height := Height;
Bitmap.Canvas.StretchDraw( ARect, Image1.Picture.Graphic );
end;
end;
已编辑
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width, Height: Integer; out Bitmap: TBitmap );
var
ARect: TRect;
APicture: TPicture;
AExtension: string;
begin
// experimental code
if FileExists( Path ) then
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
APicture := TPicture.Create;
try
APicture.LoadFromFile( Path );
Bitmap := TBitmap.Create;
Bitmap.SetSize( Width, Height );
Bitmap.IgnorePalette := True;
Bitmap.PixelFormat := pf24bit;
Bitmap.Transparent := False;
Bitmap.Canvas.Lock; **// New**
try
Bitmap.Canvas.StretchDraw( ARect, APicture.Graphic );
finally
Bitmap.Canvas.Unlock; **// New!**
end;
finally
APicture.Free;
end;
end;
end;
end;
这似乎完全解决了绘图问题!显然,在使用Draw或StretchDraw时必须锁定和解锁画布,因为在线程中,由于graphics.pas中的GDI对象缓存机制,其Bitmap.canvas的DC有时会被清除。
// experimental code
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width,
Height: Integer; out Bitmap: TBitmap );
var
AExtension: string;
ARect: TRect;
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
Image1.Picture.LoadFromFile( Path ); // added at design time to form
Bitmap := TBitmap.Create;
Bitmap.Width := Width;
Bitmap.Height := Height;
Bitmap.Canvas.StretchDraw( ARect, Image1.Picture.Graphic );
end;
end;
Edited
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width, Height: Integer; out Bitmap: TBitmap );
var
ARect: TRect;
APicture: TPicture;
AExtension: string;
begin
// experimental code
if FileExists( Path ) then
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
APicture := TPicture.Create;
try
APicture.LoadFromFile( Path );
Bitmap := TBitmap.Create;
Bitmap.SetSize( Width, Height );
Bitmap.IgnorePalette := True;
Bitmap.PixelFormat := pf24bit;
Bitmap.Transparent := False;
Bitmap.Canvas.Lock; **// New**
try
Bitmap.Canvas.StretchDraw( ARect, APicture.Graphic );
finally
Bitmap.Canvas.Unlock; **// New!**
end;
finally
APicture.Free;
end;
end;
end;
end;
This seems to fix the drawing problem completely! Apparently you have to lock and unlock the canvas when using Draw or StretchDraw because in a thread, the DC of its Bitmap.canvas is sometimes cleared due to the GDI Object Caching mechanism in graphics.pas.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不可以,因为:
您只能从主 VCL 线程使用 VCL 控件。
No, because of this:
You can only work with the VCL controls from the main VCL thread.
一般来说,VCL 代码不是线程安全的,这适用于大多数可用的 VCL 对象。
你说:
“无例外”并不表示“线程安全”。这就像说“我开车去上班,没有发生车祸,所以我的车是防撞的”。
线程问题与时间高度相关,并且以多种方式表现出来——而不仅仅是异常。需要记住的重要一点是,线程问题可能会作为潜在缺陷存在数月,然后才会发生任何意外。即便如此,它们通常也很难以任何一致性措施来重现。
当您说“图像似乎部分空白或绘制不正确”时,一个重要的问题是:是否总是相同的图像以相同的方式表现错误?如果是这样,那么问题可能只是您用来加载图像的控件对这些特定文件有问题。
您实际上正在运行多个线程吗?我在您的代码中没有看到任何表明这一点的内容。
您是否尝试过运行单线程来确认是否确实是线程问题?
编辑
那么最简单的解决方案可能是:
下面将在 VCL 主线程中调用您的自定义处理程序,并等待返回。
编辑2
请求更多示例代码:
声明消息常量。
声明记录类型。真的很简单,但你也需要指针。
声明消息处理程序。
实现消息处理程序。
In general VCL code is not thread safe, and this applies to the majority of VCL objects available for use.
You said:
"No exceptions" are not an indication of 'thread safety'. That's the same as saying "I drove to work, and didn't crash, so my car is crash proof."
Threading issues are highly timing dependent, and manifest themselves in a variety of ways - not just exceptions. The important thing to remember is that threading issues can exist as latent defects for months before anything untoward happens. And even so, they are typically very difficult to reproduce with any measure of consistency.
When you say "images seem to be partially blank or not drawing correctly", an important question is: Is it always the same images misbehaving, in the same way? If so, then the issue might simply be that the control you're using to load the images is having a problem with those specific files.
Are you actually running multiple threads? I did't see anything in your code to indicate as such.
Have you tried running single-threaded to confirm whether it really is a threading issue?
EDIT
Then the simplest solution will probably be:
procedure TFormMain.MyThumbnailProvider
so that it can synchronise with the VCL Main Thread, and pass the work on to the synchronised handler.The following will call your custom handler in the VCL main thread, and wait for a return.
EDIT2
More sample code requested:
Declaring the message const.
Declaring the record type. Really easy, but you need the pointer too.
Declaring the message handler.
Implementing the message handler.