BitmapDecoder not releasing file lock

G

Guest

I am using System.Windows.Media.Imaging.BitmapDecoder as part of some code
that extracts metadata, but my problem can be reduced to the following simple
example:

using System;
using System.Windows.Media.Imaging;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string filepath = @"C:\mypic.jpg";
BitmapDecoder fileBitmapDecoder = BitmapDecoder.Create(new
System.Uri(filepath, UriKind.Absolute), BitmapCreateOptions.None,
BitmapCacheOption.Default);

fileBitmapDecoder = null;

// Lock is not released unless I perform a garbage collection.
//GC.Collect();
}
}
}

Unless I call GC.Collect(), the BitmapDecoder class holds a lock on
mypic.jpg until the application exits. I have stepped through the code with
Process Monitor running to prove it. For performance reasons I do not want to
use GC.Collect().

I need the lock released as soon as I am done with the BitmapDecoder class.
It does not implement IDisposable so that is not an option.

Thanks for any help,
Roger Martin
Tech Info Systems
www.techinfosystems.com
 
J

Jeffrey Tan[MSFT]

Hi Roger,

I have created a sample WPF project by testing your code snippet. Yes, I
can reproduce this locking issue. I can also see an opening handle on this
image file through Process Explorer.

Since the Process Monitor call stack can not resolve the .Net symbols very
well, I used windbg to debug this issue. I set a breakpoint for the
kernel32!CreateFileW and wait for the BitmapDecoder.Create() method to
break.

Below is the stack trace I got:

ChildEBP RetAddr
0012dfd8 00b4a9ff KERNEL32!CreateFileW
0012e01c 793700ba CLRStub[StubLinkStub]@b4a9ff
00000001 7936f3b3
mscorlib_ni!Microsoft.Win32.Win32Native.SafeCreateFile(System.String,
Int32, System.IO.FileShare, SECURITY_ATTRIBUTES, System.IO.FileMode, Int32,
IntPtr)+0x22
0012e144 793723bf mscorlib_ni!System.IO.FileStream.Init(System.String,
System.IO.FileMode, System.IO.FileAccess, Int32, Boolean,
System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES,
System.String, Boolean)+0x35f
014f6168 53c6cfa5 mscorlib_ni!System.IO.FileStream..ctor(System.String,
System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare)+0x73
0012e200 53954f12
PresentationCore_ni!System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderF
romUriOrStream(System.Uri, System.IO.Stream,
System.Windows.Media.Imaging.BitmapCacheOption, System.Guid ByRef, Boolean
ByRef, System.IO.Stream ByRef, System.IO.UnmanagedMemoryStream ByRef,
Microsoft.Win32.SafeHandles.SafeFileHandle ByRef)+0x3177a1
00000000 53aead81
PresentationCore_ni!System.Windows.Media.Imaging.BitmapDecoder.CreateFromUri
OrStream(System.Uri, System.Uri, System.IO.Stream,
System.Windows.Media.Imaging.BitmapCreateOptions,
System.Windows.Media.Imaging.BitmapCacheOption, Boolean)+0x19e
00000000 0137019f
PresentationCore_ni!System.Windows.Media.Imaging.BitmapDecoder.Create(System
Uri, System.Windows.Media.Imaging.BitmapCreateOptions,
System.Windows.Media.Imaging.BitmapCacheOption)+0x39
00000000 79e88f63 BitmapDecoderTest!BitmapDecoderTest.Window1..ctor()+0x57
0012e2a0 79e88ee4 mscorwks!CallDescrWorker+0x33
0012e320 79e88e31 mscorwks!CallDescrWorkerWithHandler+0xa3
0012e464 79e88d19 mscorwks!MethodDesc::CallDescr+0x19c
0012e47c 79e88cf6 mscorwks!MethodDesc::CallTargetWorker+0x20
0012e490 79ef9c27 mscorwks!MethodDescCallSite::Call_RetArgSlot+0x18
0012e528 79f28d13 mscorwks!TryCallMethod+0x84
0012e71c 7935f67c mscorwks!RuntimeTypeHandle::CreateInstance+0x421
00000001 7935f602
mscorlib_ni!System.RuntimeType.CreateInstanceSlow(Boolean, Boolean)+0x68
0012e784 7935f4e7
mscorlib_ni!System.RuntimeType.CreateInstanceImpl(Boolean, Boolean,
Boolean)+0x106
0012e7e8 54f2ebfa mscorlib_ni!System.Activator.CreateInstance(System.Type,
Boolean)+0x43
0012e7e8 54f2e9ba
PresentationFramework_ni!System.Windows.Markup.BamlRecordReader.CreateInstan
ceFromType(System.Type, Int16, Boolean)+0x10a

Furthermore, I dump the parameter of KERNEL32!CreateFileW below:

KERNEL32!CreateFileW(unsigned short * lpFileName = 0x014f6244, unsigned
long dwDesiredAccess = 0x80000000, unsigned long dwShareMode = 1, struct
_SECURITY_ATTRIBUTES * lpSecurityAttributes = 0x00000000, unsigned long
dwCreationDisposition = 3, unsigned long dwFlagsAndAttributes = 0x100000,
void * hTemplateFile = 0x00000000)

The key point is the dwShareMode parameter, which value is "1". "1" means
FILE_SHARE_READ for dwShareMode parameter. So BitmapDecoder.Create() method
opens the image with FILE_SHARE_READ, which means that other processes can
only read it at the same time, but can not delete/modify it before the file
is closed. This is the root cause of the image file locking.

I have forwarded this issue to the WPF team as a bug report, and asked for
the workaround. I will feedback any further information here ASAP.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Roger ,

Sorry for letting you wait.

I have discussed with one development lead of WPF. He confirms that
BitmapCacheOption.Default will only load and cache the image to memory
on-demond. You may use BitmapCacheOption.OnLoad instead, the decoder will
read the entire image immediately rather than on demand (the default
behavior).

I have tested BitmapCacheOption.OnLoad and it works well without locking
the file.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top