שתף באמצעות


Read Only filestream is locking out file

Question

Thursday, May 8, 2014 9:27 AM

Hi, 

I have a problem in that when we run a section of code to open a file stream which accesses a file on a network share and immediately close it (a document previewer) which is read only, if another process tries to access the file they get the error "This file has been locked by another user"

I've ruled out the possibility that it was a 3rd party control and I can reproduce the problem with the following code 90% of the time

Using stream As Stream = New FileStream(_strLastDocumentPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
  stream.Seek(0, SeekOrigin.Begin)
  stream.Close()
End Using

Do you have any ideas what might be causing this and if so - how to fix it? My assumptions at the moment are that it may be related to the Garbage Collector.

Thanks,

All replies (28)

Friday, May 9, 2014 4:36 AM ✅Answered

As theories go it's a bit of a stretch, certainly, but others on that StackOverflow thread mentioned anti-virus products as a possible cause also.  I still find it odd that a call to GC.Collect seems to cure it and I'd be interested to know if explicitly calling CloseHandle() on the underlying handle will solve it.  I wonder if the OP would care to use ProcessExplorer from SysInternals to track the associated handle on the file.  I wonder if it's some performance optimization that the framework uses in the event that the file might be reopened (sort of like how connection pooling works) and the handle is only truly released in the finalizer if it's a network file?

Either way - curiouser and curiouser...


Friday, May 9, 2014 2:32 PM ✅Answered | 1 vote

I took a quick peek at the code for the Dispose method for System.IO.FileStream.  The first line states (and this is a bit of a translation so bear with me):

If _handle Is Nothing OrElse _handle.IsClosed OrElse _writePos <= 0 Then Return

This implies to me that if the stream position is at 0 when the OP closes & disposes, it may not actually release the handle until Finalization.

Adam - as a test, could you advance the stream forwards one byte immediately before your call to Stream.Close and tell us what happens?


Sunday, May 11, 2014 3:17 AM ✅Answered

My analysis was pulled from a DotPeek decompilation; I would trust the reference source over what it generated.  At least the content of the reference source seems to make more sense.

Ah, ok, then I'm sure it was DotPeek's fault; I was pretty sure you wouldn't have misread that C#.  :)

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

I also just noticed I typed <= 0 rather than >= 0 too when converting the decompiled C# <redfacedsmiley>.  My bad!

I still find this a weird one though.  If it is indeed something to do with Windows Network File Caching, why does the forced GC clear it up? Essentially we're saying the former is somehow affected directly by the latter, making me wonder if there's some type of special handling in the Framework for network file access over local IO - but nothing I've seen either in the reference source or in dotPeek's decompilation would indicate that they're treated differently at all.

But then, I didn't see anything obvious in the finalizer that would imply it either.  How strange!


Monday, May 12, 2014 8:58 AM ✅Answered

OK so I should kick myself for not noticing this earlier but...

I created a new project with your code in it to test out the solutions proposed in this thread and was unable to reproduce it (having said that - the hit and miss nature of this problem this could be another red herring)

So I went back to the source code you sent me and I think I've found a problem. While you did cut down the source code to bare bones there is one routine that still exists that might be having an effect...

Your previewer first attempts to determine what kind of file it is previewing and if it is a word document it then tried to determine if it is a .docx or a .doc.  You do this by looking at the first few bytes of the file but that routine does not dispose of the stream.

I'm not 100% certain this is the full cause of the problem as I'd have expected it to go wrong more often than it does. 

I still think that caching may play a role as I can get the same sort of locking error when using the preview in windows explorer to view documents on a server.


Thursday, May 8, 2014 1:08 PM

Is the code you posted representative of what you're actually doing?  All I can see is that it's opening a stream then immediately closing/disposing of it, which seems rather pointless.  If this isn't the actual code, we need to see what is.


Thursday, May 8, 2014 1:11 PM

After performing the seek I passed the stream to our Document Preview control to load the document. However I still get the exact same problem with the code above. I removed as much as I possibly could for it to still go wrong to aid in diagnostics. 

The only fix I have found which I do not like is to call GC.Collect (forcing a garbage collection) immediately after the End Using statement. 


Thursday, May 8, 2014 1:19 PM

This is quite interesting, and a quick search reveals you are not alone in your frustrations, Mr Lonsdale!

http://stackoverflow.com/questions/2670429/filestream-to-save-file-then-immediately-unlock-in-net

Looks like others have experienced the same issue, particularly related to network shares.  Some claim that antivirus is locking the file (giving it a quick scan after it detects a change) but if a forced GC pass is unlocking it for you then I find the antivirus explanation unlikely.

Almost sounds like some sneaky caching of the file handle is going on doesn't it?  I would suggest if you don't like the GC.Collect(), maybe a call to the CloseHandle() API instead and see if that fixes it?


Thursday, May 8, 2014 1:22 PM

Thanks for the reply,

I did see that thread before I made my post here. The only difference is that the top answer suggests implementing a using statement which we're already doing, and they are writing whereas we are just reading. I was thinking it could be possible that MS word opens the file with something similar to FileShare.None, which could cause this.

I'll take a look into the CloseHandle API


Thursday, May 8, 2014 1:49 PM

I changed the share mode and I can open the file in notepad while it is running.

Imports System.IO
Module Module1
    Sub Main()
        Using stream As New FileStream("C:\Test\Text.text", FileMode.Open, FileAccess.Read, FileShare.Read)
            stream.Seek(0, SeekOrigin.Begin)
            Threading.Thread.Sleep(10000) 'To create time don't copy and paste it
            stream.Close()
        End Using
    End Sub
End Module

Success
Cor


Thursday, May 8, 2014 3:03 PM

I changed the share mode and I can open the file in notepad while it is running.

Imports System.IO
Module Module1
    Sub Main()
        Using stream As New FileStream("C:\Test\Text.text", FileMode.Open, FileAccess.Read, FileShare.Read)
            stream.Seek(0, SeekOrigin.Begin)
            Threading.Thread.Sleep(10000) 'To create time don't copy and paste it
            stream.Close()
        End Using
    End Sub
End Module

Success
Cor

FileShare.Read should be more restrictive than FileShare.ReadWrite.  Notepad really isn't the best example for this either, it doesn't request any locks on the file when it opens it, and from what I gather the OP was trying this on a network share.


Thursday, May 8, 2014 3:12 PM

And why are you writing this? I don't see the purpose then that you tell the OP must not try it.  Miserable is the word we use for this kind of replies.

Success
Cor


Thursday, May 8, 2014 4:15 PM

Your code is specifying a FileShare mode of ReadWrite which will allow other processes to open the file for reading and writing, but if the other process is trying to open the file exclusively, it will still fail, regardless of your sharing mode.

What file sharing mode is the other process using?


Thursday, May 8, 2014 4:18 PM

Thanks for the response Chris,

Its actually Microsoft Word that is trying to lock the file out which I'm assuming must be exclusively. Still though I'd have thought because I'm doing a using statement it should destroy it almost immediately thereafter without the need for a garbage collection. I guess I'm really trying to find an answer as to why I need to use the GC in this situation and why the end using isn't properly destroying the file handle - because I really dislike using the GC - I consider it bad programming practice!


Thursday, May 8, 2014 4:24 PM

Your code is specifying a FileShare mode of ReadWrite which will allow other processes to open the file for reading and writing, but if the other process is trying to open the file exclusively, it will still fail, regardless of your sharing mode.

Is the other processes file sharing mode compatible with yours?

Chris, from what I gather this is happening after he's closed/disposed of the FileStream.  Something is still maintaining a lock on the file handle and it's only released when garbage collection is forced if I understand correctly.


Thursday, May 8, 2014 10:29 PM

This is quite interesting, and a quick search reveals you are not alone in your frustrations, Mr Lonsdale!

http://stackoverflow.com/questions/2670429/filestream-to-save-file-then-immediately-unlock-in-net

Looks like others have experienced the same issue, particularly related to network shares.  Some claim that antivirus is locking the file (giving it a quick scan after it detects a change) but if a forced GC pass is unlocking it for you then I find the antivirus explanation unlikely.

Almost sounds like some sneaky caching of the file handle is going on doesn't it?  I would suggest if you don't like the GC.Collect(), maybe a call to the CloseHandle() API instead and see if that fixes it?

I'd be really curious to know if the OP has any "security" software on this client, and if so, what happens when it is turned off...

Suppose, just hypothetically, that a security product poked around in managed memory looking for streams so that it could analyze their contents.  When it found one it kicked off its own object in its own application domain with a pointer to the memory in the other domain, but then failed to implicitly destroy that handle and instead relied on its own finalizer to clean it up...

Perhaps that is getting pretty inventive, but having seen some of what these vendors have tried to do in the past, I can't really put it past one to try to pull off something like that.

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Friday, May 9, 2014 5:19 AM

Thanks for the response Chris,

Its actually Microsoft Word that is trying to lock the file out which I'm assuming must be exclusively. Still though I'd have thought because I'm doing a using statement it should destroy it almost immediately thereafter without the need for a garbage collection. I guess I'm really trying to find an answer as to why I need to use the GC in this situation and why the end using isn't properly destroying the file handle - because I really dislike using the GC - I consider it bad programming practice!

If you read something on Internet, then that is like the bible for you; It is definitely true as long as you don't understand it. Look who writes something. There is more rubbish written then true solutions.

This is the Garbage Collector it is about releasing memory you have used in your program. Nothing to do with Files.

http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx

Moreover, you write actually Microsoft Word is locking it, then the solution should be in MS word and not somewhere around.

The forum for Visual Studio and Office is this one.

http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=vsto

But give a different description then now. 

Did you try my simple sample by the way, it seems that your solution must be difficult. Be a profesional programmer, "try" first the easy ones.

In fact seems your problem completely described here and therefore I used it in my sample.

http://msdn.microsoft.com/en-us/library/system.io.fileshare(v=vs.110).aspx

Success
Cor


Friday, May 9, 2014 8:31 AM

If you read something on Internet, then that is like the bible for you; It is definitely true as long as you don't understand it. Look who writes something. There is more rubbish written then true solutions.

This is the Garbage Collector it is about releasing memory you have used in your program. Nothing to do with Files.

http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx

Moreover, you write actually Microsoft Word is locking it, then the solution should be in MS word and not somewhere around.

The forum for Visual Studio and Office is this one.

http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=vsto

But give a different description then now. 

Did you try my simple sample by the way, it seems that your solution must be difficult. Be a profesional programmer, "try" first the easy ones.

In fact seems your problem completely described here and therefore I used it in my sample.

http://msdn.microsoft.com/en-us/library/system.io.fileshare(v=vs.110).aspx

Success
Cor

That seems like an unnecessary response Cor, and I'm disappointed to see such a response from you.

Adam has a problem, he cut his code down more and more until he isolated the problem down to a few lines of code.

If you run that code against a Word document that lives on a server then try to open that document in Word then Word complains that the file is locked... sometimes.

The stream is disposed of and in theory no file lock should be in place. The lock can last a few seconds or a few minutes. Given that calling the garbage collector releases the lock immediately then clearly something doesn't get released until the GC runs; which would explain why the lock lasts for a variable amount of time.

Far from reading tin pot ideas on the internet he posted here where he should be able find people who help him understand why this happens. 

I don't see anything in what he posted to imply he isn't being professional and you're out of order to imply it IMO.


Friday, May 9, 2014 2:50 PM

I took a quick peek at the code for the Dispose method for System.IO.FileStream.  The first line states (and this is a bit of a translation so bear with me):

If _handle Is Nothing OrElse _handle.IsClosed OrElse _writePos <= 0 Then Return

This implies to me that if the stream position is at 0 when the OP closes & disposes, it may not actually release the handle until Finalization.

Adam - as a test, could you advance the stream forwards one byte immediately before your call to Stream.Close and tell us what happens?

This is actually extremely useful to know. I'll test this and see what happens. Thank you so much for this.


Friday, May 9, 2014 5:05 PM

If you read something on Internet, then that is like the bible for you; It is definitely true as long as you don't understand it. Look who writes something. There is more rubbish written then true solutions.

This is the Garbage Collector it is about releasing memory you have used in your program. Nothing to do with Files.

http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx

Moreover, you write actually Microsoft Word is locking it, then the solution should be in MS word and not somewhere around.

The forum for Visual Studio and Office is this one.

http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=vsto

But give a different description then now. 

Did you try my simple sample by the way, it seems that your solution must be difficult. Be a profesional programmer, "try" first the easy ones.

In fact seems your problem completely described here and therefore I used it in my sample.

http://msdn.microsoft.com/en-us/library/system.io.fileshare(v=vs.110).aspx

Success
Cor

That seems like an unnecessary response Cor, and I'm disappointed to see such a response from you.

Adam has a problem, he cut his code down more and more until he isolated the problem down to a few lines of code.

If you run that code against a Word document that lives on a server then try to open that document in Word then Word complains that the file is locked... sometimes.

The stream is disposed of and in theory no file lock should be in place. The lock can last a few seconds or a few minutes. Given that calling the garbage collector releases the lock immediately then clearly something doesn't get released until the GC runs; which would explain why the lock lasts for a variable amount of time.

Far from reading tin pot ideas on the internet he posted here where he should be able find people who help him understand why this happens. 

I don't see anything in what he posted to imply he isn't being professional and you're out of order to imply it IMO.

Jan,

Do you have a solution, until now I see only persons who tell to try nothing. Did you read all the links I gave to the OP? Be aware I've seen this problem more, but it the OP does not start trying the simplest one but only relies on hacking the GC. Yea then I find that not professional.

Success
Cor


Saturday, May 10, 2014 2:25 AM

This is actually extremely useful to know. I'll test this and see what happens. Thank you so much for this.

You're most welcome, sir.  Let us know if it fixes it; I know Reed & I are certainly intrigued by this one!


Saturday, May 10, 2014 3:08 PM

I took a quick peek at the code for the Dispose method for System.IO.FileStream.  The first line states (and this is a bit of a translation so bear with me):

If _handle Is Nothing OrElse _handle.IsClosed OrElse _writePos <= 0 Then Return

This implies to me that if the stream position is at 0 when the OP closes & disposes, it may not actually release the handle until Finalization.

Adam - as a test, could you advance the stream forwards one byte immediately before your call to Stream.Close and tell us what happens?

hmm... when I look at the reference source, I see something a little different:

protected override void Dispose(bool disposing)
        {
            // Nothing will be done differently based on whether we are 
            // disposing vs. finalizing.  This is taking advantage of the
            // weak ordering between normal finalizable objects & critical
            // finalizable objects, which I included in the SafeHandle 
            // design for FileStream, which would often "just work" when 
            // finalized.
            try {
                if (_handle != null && !_handle.IsClosed) {
                    // Flush data to disk iff we were writing.  After 
                    // thinking about this, we also don't need to flush
                    // our read position, regardless of whether the handle
                    // was exposed to the user.  They probably would NOT 
                    // want us to do this.
                    if (_writePos > 0) {
                        FlushWrite(!disposing);
                    }
                }
            }
            finally {
                if (_handle != null && !_handle.IsClosed)
                    _handle.Dispose();
                
                _canRead = false;
                _canWrite = false;
                _canSeek = false;
                // Don't set the buffer to null, to avoid a NullReferenceException
                // when users have a race condition in their code (ie, they call
                // Close when calling another method on Stream like Read).
                //_buffer = null;
                base.Dispose(disposing);
            }
        }

http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs#8270a043211dafd8

So this just forces a flush of the write buffer before closing to ensure that any data in the process of being written is able to complete before the stream is disposed.

Keep in mind that the actual Position property value is calculated based upon the internal _read and _write positions.  Since the example never writes to the stream, the _writePos value should not be greater than zero.

If this isn't related to another process interfering with normal memory management then my guess is that it does have to do with Windows internal caching for network shares. So another thing that could be done just for testing would be to copy the network file locally, modify it, then copy it back to the network share.  See if the lock is released when doing it that way. Granted, this would just provide a workaround without really telling why the lock occurs in the first place.

You may need to use inspection tools (perhaps PerfView) to monitor the application at run time and watch what happens in memory.

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Saturday, May 10, 2014 3:41 PM

My analysis was pulled from a DotPeek decompilation; I would trust the reference source over what it generated.  At least the content of the reference source seems to make more sense.


Saturday, May 10, 2014 3:57 PM

My analysis was pulled from a DotPeek decompilation; I would trust the reference source over what it generated.  At least the content of the reference source seems to make more sense.

Ah, ok, then I'm sure it was DotPeek's fault; I was pretty sure you wouldn't have misread that C#.  :)

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Sunday, May 11, 2014 12:29 AM

 Jan,

Do you have a solution, until now I see only persons who tell to try nothing. Did you read all the links I gave to the OP? Be aware I've seen this problem more, but it the OP does not start trying the simplest one but only relies on hacking the GC. Yea then I find that not professional.

Success
Cor

I haven't replied sooner because to be honest I found your reply not only unhelpful but rude and frankly insulting. I actually explained in the first post that this goes wrong only 90% of the time, so there are still situations where there are no errors raised by MS Word. 

That being said I did try your code and it of course worked. You wasn't using MS Word, you wasn't using a network location two of the key elements of my initial problem. I find it extremely unprofessional of you to try and offer advice which is completely irrelevant and unrelated. Its like me complaining my car cuts out occasionally and you saying "well, I got a new car and it works fine so you might want to try that"

Firstly, we had a large block of code that wasn't working, common sense troubleshooting methods would dictate that you try to isolate the problem and rule out as many different variables as possible that could be influencing encountered errors. We did this by removing the previewer and various other lines of code until I was left with a bare-bones example which still causes the issue I originally reported. 

After reaching this code we then thought about what other factors could be causing a file to be locked out after we have disposed of it (End Using) and wondered whether it could be due to the dispose method not correctly closing the file. The Garbage Collector should destroy any resources which have been disposed of and still exist. We placed this in the code to determine whether this would fix the problem and it did which points to me that the handle was not being destroyed. 

I never at any point said that the GC.Collect was by any means a solution that I was planning on implementing. I wanted to know WHY this fixes it, WHY the handle to the file is not being destroyed correctly and more importantly WHAT the proper fix should be. 

Not only did you post code which is completely useless (I also find it kind of ironic that you tell me to test the simplest code when you never even attempted to recreate the problem I am facing yourself using MS Word and a UNC Path) but you then call me unprofessional, assume I had accepted answers found on the internet as gospel (I never even said anything of the sort).

Take a look at Quanta and Reed who have actually taken their time to understand my problem and go out of their way to find fixes. I appreciate that more than I can explain in words. On the other hand as far as I'm concerned you've just been rude and arrogant this entire thread. The entire principal of being an MVP is that you understand the technology and offer help and support to others. I have seen neither of those from you today. In fact just the way you used a FileStream with the FileShare of read rather than ReadWrite which I initially posted suggests that you don't understand this on a basic level.

I apologise for being rude and arrogant to you also but when somebody goes out of their way twice to call me unprofessional when I have isolated a problem and request help completely disgusts me. And please before you insult Jan by asking what he has contributed take the time to realise that he was a VB6 MVP before the language and support were retired. And he was a damn sight better at helping people than you have been.


Sunday, May 11, 2014 12:32 AM

Also thank you, Reed / Quanta massively for your help so far. I believe we have tried some file diagnostic tools and I will try to get those results on Monday when I'm back in the office. I believe this may be Windows Network Caching and if your suggestion of modifying the file and copying it back also works then I will look into disabling caching for that particular share and see what results that has to offer. I also have the FileClose API to look into.

Thanks again. 


Sunday, May 11, 2014 8:05 PM

Maybe you could try the FileStream.Unlock Method although I do not have a network to test this with.

I would guess the PC the File Share is on would launch a "SvcHost.exe" maybe when a remote PC wants to access a file on it perhaps. Maybe some other process provides access to the file on the PC with the File Share from a remote PC.

I'm not sure if WMI can detect what process has a file locked on a remote PC. Plus WMI is fairly slow from what I've read so by the time it could detect that, if it could detect that, then possibly the file would already be unlocked.

This code can detect on my PC which process has a file locked. I brought a video up in Windows Media Player then launched the Open File Dialog and picked that .wmv file on my desktop while it was being played by WMP.

Maybe you could use it with a timer to see if your app still has the file locked when you run the code that %90 of the time causes the file to be locked. And see if it's your app that still has it locked or not.

I don't suppose this code would be able to get the processes of a remote PC to see which process has a file locked on the remote PC. But perhaps it can. I'm unfamiliar with the Pinvoke functions or how they ascertain where to get process information from.

Option Strict On

Imports System.Runtime.InteropServices

Public Class Form1

    ' Code converted from thread http://stackoverflow.com/questions/317071/how-do-i-find-out-which-process-is-locking-a-file-using-net

    <DllImport("rstrtmgr.dll", CharSet:=CharSet.Unicode)> _
    Private Shared Function RmRegisterResources(pSessionHandle As UInteger, nFiles As UInt32, rgsFilenames As String(), nApplications As UInt32, <[In]> rgApplications As RM_UNIQUE_PROCESS(), nServices As UInt32, _
        rgsServiceNames As String()) As Integer
    End Function

    <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
    Private Shared Function RmStartSession(ByRef pSessionHandle As UInteger, dwSessionFlags As Integer, strSessionKey As String) As Integer
    End Function

    <DllImport("rstrtmgr.dll")> _
    Private Shared Function RmEndSession(pSessionHandle As UInteger) As Integer
    End Function

    <DllImport("rstrtmgr.dll")> _
    Private Shared Function RmGetList(dwSessionHandle As UInteger, ByRef pnProcInfoNeeded As UInteger, ByRef pnProcInfo As UInteger, <[In], Out> rgAffectedApps As RM_PROCESS_INFO(), ByRef lpdwRebootReasons As UInteger) As Integer
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RM_UNIQUE_PROCESS
        Public dwProcessId As Integer
        Public ProcessStartTime As System.Runtime.InteropServices.ComTypes.FILETIME
    End Structure

    Const RmRebootReasonNone As Integer = 0
    Const CCH_RM_MAX_APP_NAME As Integer = 255
    Const CCH_RM_MAX_SVC_NAME As Integer = 63

    Private Enum RM_APP_TYPE
        RmUnknownApp = 0
        RmMainWindow = 1
        RmOtherWindow = 2
        RmService = 3
        RmExplorer = 4
        RmConsole = 5
        RmCritical = 1000
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Private Structure RM_PROCESS_INFO
        Public Process As RM_UNIQUE_PROCESS

        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCH_RM_MAX_APP_NAME + 1)> _
        Public strAppName As String

        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCH_RM_MAX_SVC_NAME + 1)> _
        Public strServiceShortName As String

        Public ApplicationType As RM_APP_TYPE
        Public AppStatus As UInteger
        Public TSSessionId As UInteger
        <MarshalAs(UnmanagedType.Bool)> _
        Public bRestartable As Boolean
    End Structure

    Dim LockedFileProcesses As New List(Of Process)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.CenterToScreen()
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        LockedFileProcesses.Clear()
        RichTextBox1.Text = ""
        Dim OFD As New OpenFileDialog
        OFD.InitialDirectory = "C:\Users\John\Desktop"
        OFD.Title = "Check Locked File"
        OFD.Multiselect = False
        If OFD.ShowDialog = Windows.Forms.DialogResult.OK Then
            LockedFileProcesses = WhoIsLocking(OFD.FileName)
            If LockedFileProcesses.Count > 0 Then
                For Each Item In LockedFileProcesses
                    RichTextBox1.AppendText(Item.ProcessName.ToString & " .. " & Item.Id.ToString & vbCrLf)
                Next
            End If
        End If
    End Sub

    Private Function WhoIsLocking(path As String) As List(Of Process)
        Dim handle As UInteger
        Dim key As String = Guid.NewGuid().ToString()
        Dim processes As New List(Of Process)()

        Dim res As Integer = RmStartSession(handle, 0, key)
        If res <> 0 Then
            Throw New Exception("Could not begin restart session.  Unable to determine file locker.")
        End If

        Try
            Const ERROR_MORE_DATA As Integer = 234
            Dim pnProcInfoNeeded As UInteger = 0, pnProcInfo As UInteger = 0, lpdwRebootReasons As UInteger = RmRebootReasonNone

            Dim resources As String() = New String() {path}
            ' Just checking on one resource.
            res = RmRegisterResources(handle, CUInt(resources.Length), resources, 0, Nothing, 0, Nothing)

            If res <> 0 Then
                Throw New Exception("Could not register resource.")
            End If

            'Note: there's a race condition here -- the first call to RmGetList() returns
            '      the total number of process. However, when we call RmGetList() again to get
            '      the actual processes this number may have increased.
            res = RmGetList(handle, pnProcInfoNeeded, pnProcInfo, Nothing, lpdwRebootReasons)

            If res = ERROR_MORE_DATA Then
                ' Create an array to store the process results
                Dim processInfo As RM_PROCESS_INFO() = New RM_PROCESS_INFO(CInt(pnProcInfoNeeded - 1)) {}
                pnProcInfo = pnProcInfoNeeded

                ' Get the list
                res = RmGetList(handle, pnProcInfoNeeded, pnProcInfo, processInfo, lpdwRebootReasons)
                If res = 0 Then
                    processes = New List(Of Process)(CInt(pnProcInfo))

                    ' Enumerate all of the results and add them to the 
                    ' list to be returned
                    For i As Integer = 0 To CInt(pnProcInfo - 1)
                        Try
                            processes.Add(Process.GetProcessById(processInfo(i).Process.dwProcessId))
                            ' catch the error -- in case the process is no longer running
                        Catch generatedExceptionName As ArgumentException
                        End Try
                    Next
                Else
                    Throw New Exception("Could not list processes locking resource.")
                End If
            ElseIf res <> 0 Then
                Throw New Exception("Could not list processes locking resource. Failed to get size of result.")
            End If
        Finally
            RmEndSession(handle)
        End Try

        Return processes
    End Function

End Class

La vida loca


Monday, May 12, 2014 8:11 AM

No I don't have a solution. I can replicate the problem though. 

Yes I read your links Cor. I don't see how it helps though.  In my tests it makes no difference if the file is opened Read, ReadWrite etc. 

I'll try Quanta's suggestion and see if that makes a difference. 

In my tests I found it went wrong consistently with a .docx and never went wrong with a .doc

However upon repeating the tests later in the day both document types had the problem equally so that proved to be a read herring.

Cor, the OP said he did not want to rely on calling the GC manually as he did not feel this was a suitable solution. So I still think you are being unfair. 

Since I can recreate the problem I will post back when I've tried Quanta's theory.


Monday, May 12, 2014 9:44 AM

Jan,

We are probably another kind of developers. I'm not talking about you, but I'm never going the elite sophisticated looking way. I take always first the easiest solution. Why, simply because that is the best maintainable. The OP is in my perception surely the opposite from me.

This forum is not made for single OP's but as a knowledge base. So others will read this thread and see many nonsense from which they believe it is true. If I see that, I discuss that, because I think I help thousands in a better direction.

Mostly the problem of the current OP is solved by using the flush explicitly, but his question was stated in a way that I was not sure about what he was writing about and I'm still not sure.

http://msdn.microsoft.com/en-us/library/system.io.stream.flush(v=vs.110).aspx

By the way, I find it a compliment like Adam threads the replies from mr. Monkeyboy the same like mine. The latter gives currently very good direct usable help in the forums, more in depth than beginners will notice.

Success
Cor