1

I am trying to call an application with simple code like

public void Run(string command)
{
    Process proc = new Process();
    proc.StartInfo.FileName = "acvTemp.exe";
    proc.StartInfo.Arguments = command;             

    proc.Start();

    proc.WaitForExit();
}

The fileName process I am launching actually spawns a new window. Its being launched with some commands that make it no exit . I.e

command = acvtest.exe /launch /wait /log:<temp.log>

So acvtest.exe starts running on the machine and is actually is still running so I could run other commands like

acvtest.exe /getid:<name>

This is how I will manually use the application.

acvtest.exe /launch /wait /log:<temp.log>
acvtest.exe /getid:<name>

Note the actual /launch process return to shell command prompt, because with /launch a new command window is opened and output of /getid is actually written to the log.

My problem is when the first /launch or /getid commands run, waitforexit() seems to be exiting even before the handle is released on log. (may be before some child thred exits?)

I.e the following command fails until I put some sleep or wait in between. even with waitforexit()

 Run("/launch /wait /log:<temp.log>");
 Run("/getid:<name>");
 Run("shutdown");

 //Needs some sleep or wait here

 using (StreamReader reader = new StreamReader("temp.log"))
 {
     Console.WriteLine(reader.ReadToEnd());
 }

Without any sleep or wait between the above two sections, accessing the log fails with error that it is already being used by another process. Looks like the application is exiting even before it actually finishes its processes. Is this a problem with teh application? Anything I can do to work around it?

I am suspecting I may need some differt Run() code here because a new shell is launched.

[update]

The problem is not just with the log file. When I am runnning Run("/getid:") on say some 100,000 file names, many of these are failing with 'resources not available' error, which is why I thought the application may be exiting even before its releasing its resources Thanks for looking.

user393148
  • 897
  • 4
  • 16
  • 27

3 Answers3

0

Is this a problem with teh application? Anything I can do to work around it?

I would say there is probably no problem at all with the application. Most likely the file has simply not been released completely by the operating system itself.

A common work around is to wrap the attempt to read the file in a Try/Catch block and either enclose that in a while loop with a delay, or call that code from a Timer.

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Thanks for your response. The problem is not just with the log file. When I am runnning Run("/getid:") on say some 100,000 file names, many of these are failing with 'resources not available' error, which is why I thought the application may be exiting even before its releasing its resources – user393148 Oct 25 '13 at 22:47
  • Is inserting a wait between every Run() command the solution? – user393148 Oct 25 '13 at 22:48
  • Haha...that's some important information you left out there! It's hard to say what amount of delay is necessary for that application to work "properly". Who knows how it is coded internally. Furthermore, what if the conditions on the entire system change, and then the delay that worked before no longer works? I think the best you're going to get is simply to adjust the amount of delay in a Sleep() in-between and then "pray" that it works all the time. Sorry. – Idle_Mind Oct 25 '13 at 23:06
  • Sorry. I just wanted to give the easiest info first. Is there a better alternate to using wait or sleep – user393148 Oct 26 '13 at 00:12
0

One solution to the file lock problem is proposed here. You can then extract the PID of the process of interest.

Then again, if the log file is held open until the process quits, there's your "semaphore" right there.

Community
  • 1
  • 1
Eric Lloyd
  • 509
  • 8
  • 19
0

I suppose you could either try to open the file as readonly by using the following code

FileStream fs = File.Open("temp.log", FileMode.Open, FileAccess.Read);

or you use some code like this one:

try
{
    // some code here ...

    // Try to access the file within 1000 (or whatever is specified) ms.
    FileAccessHelper.WaitForFileAccessibility("test.log", 1000);

    // and here ...
}
catch (FileAccessHelperException e)
{
    // your error handling here...
    Console.WriteLine("Unable to open the file within 1000ms");
}

The FileAccessHelper class looks like this:

namespace CodingFun
{
    using System;
    using System.IO;
    using System.Threading;

    /// <summary>
    /// Represents our FileAccessHelper class.
    /// </summary>
    public static class FileAccessHelper
    {
        /// <summary>
        /// Blocks until the specified file can be accessed or a timeout occurs.
        /// </summary>
        /// <param name="filename">The file which shall be accessed.</param>
        /// <param name="timeout">The timeout in milliseconds.</param>
        /// <param name="accessMode">Specifies the file access mode, default is read only.</param>
        public static void WaitForFileAccessibility(string filename, int timeout, FileAccess accessMode = FileAccess.Read)
        {
            int tries = 0;
            bool readDone = false;

            do
            {
                try
                {
                    // Try to open the file as read only.
                    FileStream fs = File.Open(filename, FileMode.Open, accessMode);

                    // Close it if it worked and...
                    fs.Close();

                    // ... set a flag so that we know we have successfully opened the file.
                    readDone = true;
                }
                catch (Exception e)
                {
                    // increase the counter and...
                    tries++;

                    // ... check if a timeout occured.
                    if ((100 * tries) >= timeout)
                    {
                        throw new FileAccessHelperException(string.Format("Unable to access the file {0} within the specified timeout of {1}ms", filename, timeout), e);
                    }
                    else
                    {
                        // If not just sleep 100 ms.
                        Thread.Sleep(100);
                    }
                }
            }
            while (!readDone);
        }
    }
}

And the FileAccessHelperException class looks like this:

namespace CodingFun
{
    using System;
    using System.Runtime.Serialization;
    using System.Security;

    /// <summary>
    /// Represents the FileAccessHelperException class.
    /// </summary>
    public class FileAccessHelperException : Exception
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="FileAccessHelperException"/> class.
        /// </summary>
        public FileAccessHelperException()
            : base()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FileAccessHelperException"/> class.
        /// </summary>
        /// <param name="message">The message that describes the error.</param>
        public FileAccessHelperException(string message)
            : base(message)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FileAccessHelperException"/>
        /// class with a specified error message and a reference to the inner
        /// exception that is the cause of this exception.
        /// </summary>
        /// <param name="message">The error message that explains the reason for the exception.</param>
        /// <param name="innerException">
        /// The exception that is the cause of the current exception, or a null reference
        /// if no inner exception is specified.
        /// </param>
        public FileAccessHelperException(string message, Exception innerException)
            : base(message, innerException)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FileAccessHelperException"/> class with serialized data.
        /// </summary>
        /// <param name="info">
        /// The System.Runtime.Serialization.SerializationInfo that holds the serialized
        /// object data about the exception being thrown.
        /// </param>
        /// <param name="context">
        /// The System.Runtime.Serialization.StreamingContext that contains contextual
        /// information about the source or destination.
        /// </param>
        /// <exception cref="System.ArgumentNullException">
        /// The info parameter is null.
        /// </exception>
        /// <exception cref="System.Runtime.Serialization.SerializationException">
        /// The class name is null or System.Exception.HResult is zero (0).
        /// </exception>
        [SecuritySafeCritical]
        protected FileAccessHelperException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }
}

I hope that helps ;-)

Markus Safar
  • 6,324
  • 5
  • 28
  • 44
  • Ah... Already late... The StreamReader should already open the stream as read only so the second solution should (hopefully) help. – Markus Safar Oct 25 '13 at 23:23