views:

2837

answers:

4

I have an update program that is completely independent of my main application. I run the update.exe to update the app.exe. To check to see if the file is in use, I move it to another file and catch an error if it is in use. If no problems occurr I rename it back. At least that was my plan...

Main program: app.exe
Update program: update.exe

This program is used over the network without any services running. So, the users is quite literally running the exe over the network on thier machine.

I need to update the app.exe when the update.exe has run. To check to see if the app.exe was still in use I was wrapping the following in a try/catch to see if it failed:

IO.File.Move(upddir & "\app.exe", upddir & "\app.exe.tst")
IO.File.Move(upddir & "\app.exe.tst", upddir & "\app.exe")

The funny thing is, even if the app.exe is running, the move can rename it to the app.exe.tst without any error. I can even continue on in the application without any errors.

I thought I was out of my mind, so I had another programmer look at this and he verified what I said above.

So, we tried this wrapped in a try catch:

Dim readfile As New FileStream(upddir & "\app.exe", FileMode.Open, FileAccess.Read, FileShare.None)
readfile.Dispose()

I put the fileshare as none that, at least I thought it would, show that there was someone in the file.

It still continued without any error.

Anyone know why I can rename a file in use? Also, is there a better way to do this than what I am doing now?

Thanks! Eroc

+1  A: 

You could do the following to check if the application has other instances running:

Process.GetProcessesByName("app.exe", "Machine1").Length > 0

Which is a more appropriate way of checking if the app is running.

Have a look at File.Move MSDN documentation. It details what exceptions are thrown. You are allowed to rename an exe even if it is in Use in Vista.

James
It sounds like a shared application, getProcessesByName isn't going to tell if it's running on another users PC.
Binary Worrier
It's run over the network and I wouldn't be able to check if it is running on another computer. That's why I went the move route.
ErocM
You should be able to pass in the remote machine name as a parameter
James
I know I didn't mention this earlier, but in most cases this is a peer to peer network. Am I still able to get the names of all the computers on the network and see if the computer has that application running?
ErocM
Can't see why not.
James
How do I get the name of all the computers on the network?
ErocM
Have a look at the following: http://www.dreamincode.net/code/snippet1978.htm
James
Thanks for all the help! ~~E
ErocM
A: 

What you could do is replace the target application with a caretaker exe.

This caretaker then spawns the target application, but also creates a locked file in a shared location. The lock is released and the file is deleted when the app exits.

Then, before you update the app.exe, you check are there any locked files in the shared location, if there are locked files then the app.exe is in use.

The caretaker program could be a window-less application, the following console app does pretty much what it needs to do

class Program
{
    static string lockFileName;
    static System.IO.StreamWriter lockFileWrtier;
    static void Main(string[] args)
    {
        lockFileName = "AppLock_" + System.IO.Path.GetRandomFileName();

        lockFileWrtier = new System.IO.StreamWriter(lockFileName);

        System.Diagnostics.Process p = new Process();
        p.StartInfo.FileName = "cmd.exe";
        p.EnableRaisingEvents = true;
        p.Exited += new EventHandler(p_Exited);

        p.Start();

        Console.WriteLine("Press any key to stop");
        Console.ReadKey();
    }

    static void p_Exited(object sender, EventArgs e)
    {
        lockFileWrtier.Dispose();
        System.IO.File.Delete(lockFileName);

        Console.WriteLine("Process has exited");
    }
}

The updater then looks for all "AppLock_*" files, and attempts to open them with a write lock, if it can't get a write lock on one of them, the exe is in use.

Hope this helps.

Binary Worrier
A: 

This is what I ended up doing. The network scan did not work on a peer-to-peer network. It didn't resolve the other computers at all.

Anyhow, here it is:

Private Sub CheckFileIfFileIsInUse(ByVal thefilename As String)
Try
' on the Vista OS you can rename a file that is in use
' the 'in use' of the original file follows the new file name

Dim testfile As String = thefilename & ".tst"

If IO.File.Exists(testfile) Then
IO.File.Delete(testfile)
End If

' so we have to rename it to something else
IO.File.Move(thefilename, testfile)

' copy it back to the original file name in case something
breaks ' this just keeps them in working order if it does
IO.File.Copy(testfile, thefilename)

' then we try to delete the original file that could be in use
' which will return an 'in use' error at this point
If IO.File.Exists(testfile) Then
IO.File.Delete(testfile)
End If

Catch ex As Exception
'throw it to the originating method
Throw
End Try
End Sub

Hope this helps the next person.

ErocM
A: 
Public Function FileInUse(ByVal sFile As String) As Boolean
    If System.IO.File.Exists(sFile) Then
        Try
            Dim F As Short = FreeFile()
            FileOpen(F, sFile, OpenMode.Binary, OpenAccess.ReadWrite, OpenShare.LockReadWrite)
            FileClose(F)
        Catch
            Return True
        End Try
    End If
End Function
Destek