-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Close Stream when creating an ImageSource from a Uri #6843
base: main
Are you sure you want to change the base?
Conversation
During XAML serialization, an ImageSource may first be loaded by ImageSourceConverter.ConvertFrom. This calls BitmapDecoder.CreateFromUriOrStream with a pack URI, opens a Stream, and keeps it open. This will eventually be closed by the BitmapDecoder finalizer (see comments in that method). Subsequently the same pack URI is opened by ImageSourceTypeConverter.ConvertTo. This throws an IOException: 'Entries cannot be opened multiple times in Update mode.'. This occurs because the same ZipArchiveEntry is being opened a second time, while the first stream is still open. By specifying BitmapCacheOption.OnLoad here, BitmapDecoder.Initialize will eagerly close the stream, which allows the ZipArchiveEntry to be opened a second time.
The call stack for the first time the pack URI is opened (this is the stack addressed by this PR):
The call stack for the second time, which throws the IOException (see #6842):
|
I am not sure about this one. Changing the behavior here has a massive impact on all WPF applications because it's used in hot path area. Testing it on a single application for a single purpose does not seem enough. Also you say its a regression from .NET Framework. I've decompiled the .NET Framework GAC assembly and it also uses Decompilation taken from PresentationCore.dll Version 4.8.9032.0: |
Changed my risk assessment to "Unknown" to better align with the two following sentences. I will posit that leaving Streams (a managed object) to be closed by a finalizer is strongly against .NET best practices, and should be avoided if possible. |
Ultimately I suspect this is related to the switch from WindowsBase to System.IO.Packaging for |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run |
Azure Pipelines failed to run 1 pipeline(s). |
This PR should also fix #9418. |
Fixes #6842
Description
During XAML serialization, an
ImageSource
may first be loaded byImageSourceConverter.ConvertFrom
. This callsBitmapDecoder.CreateFromUriOrStream
with a pack URI, opens aStream
, and keeps it open. This will eventually be closed by theBitmapDecoder
finalizer (see comments in that method).wpf/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/BitmapDecoder.cs
Lines 215 to 221 in c8742b5
Subsequently the same pack URI is opened by
ImageSourceTypeConverter.ConvertTo
. This throws anIOException: 'Entries cannot be opened multiple times in Update mode.'
. This occurs because the sameZipArchiveEntry
is being opened a second time, while the first stream is still open.By specifying
BitmapCacheOption.OnLoad
here,BitmapDecoder.Initialize
will eagerly close the stream, which allows theZipArchiveEntry
to be opened a second time.Customer Impact
Fixes an exception that prevents certain documents (presumably ones containing images, or ImageBrushes?) from printing.
Regression
Yes, regression from .NET Framework 4.8.
Testing
Tested in real-world application by using Faithlife.WPF: https://github.com/Faithlife/wpf/blob/stable/README.md#faithlifewpf
Risk
Unknown. May improve system resource usage by closing streams early instead of letting them be closed by a finalizer? OTOH, may perform unnecessary image decoding work up-front?
Microsoft Reviewers: Open in CodeFlow