Within my application the user can select different files and executables via a OpenFileDialog
. From the path of the chosen file a ProcessModel
is created and added to a ObservableCollection
.
The plan is that the user can select different files and programs and add them to a list within the application. The software should then open - and later close - the chosen files as soon as a certain event is fired (in this case a gesture by the user captured with the camera).
The ProcessModel
holds several properties for different options, but the ones important for my question are set in the constructor as follows:
public ProcessModel(string path)
{
ProcessName = Path.GetFileNameWithoutExtension(path);
processExtension = Path.GetExtension(path);
ProcessPath = path;
instances = new List<Process>();
}
What I want to do with each ProcessModel
is, that in case a certain event in the application is triggered I want to start the associated process. Furthermore, I want to track, how many instances of the same processes have been started and also be able to close them via another event. To achieve this, I listen to the Process.Exited
event and handle my list of instances accordingly.
Before I get to the actual issue, here are the methods I use (all within my ProcessModel
class):
creating and starting a new process:
/// <summary>
/// Starts a new instance of the current process
/// </summary>
public void StartNewInstance()
{
try
{
Process newInstance;
if (processExtension == GenDefString.ExecutableExtension)
{
newInstance = new Process();
newInstance.StartInfo.UseShellExecute = false;
newInstance.StartInfo.FileName = ProcessPath;
newInstance.Start();
}
else
{
newInstance = Process.Start(ProcessPath);
}
newInstance.EnableRaisingEvents = true;
newInstance.Exited += OnProcessExited;
instances.Add(newInstance);
UpdateNrOfInstances();
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
}
stopping the last instance in the list:
/// <summary>
/// stops the last instance int he list
/// </summary>
public void StopLastInstance()
{
if (instances.Count < 1) return;
try
{
var instanceToDelete = instances.Last();
instanceToDelete.Exited -= OnProcessExited;
instanceToDelete.CloseMainWindow();
instanceToDelete.Close();
instances.RemoveAt(instances.Count - 1);
UpdateNrOfInstances();
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
}
method, which listens to the event of the process being closed (externally):
/// <summary>
/// Trigger Status changed Event was raised
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
public void OnProcessExited(object source, EventArgs e)
{
var process = source as Process;
if (process == null) return;
instances.Remove(process);
UpdateNrOfInstances();
}
Updating the number of current instances to the GUI:
/// <summary>
/// Sets the value for the number of instances (used for GUI update)
/// </summary>
private void UpdateNrOfInstances()
{
NrOfInstancesRunning = instances.Count;
}
As you can see in the StartNewInstance()
method, I check if the extension is from an executable or an software associated file (GenDefString.ExecutableExtension
is a string holding @".exe"). Everthing is working as intented, however if for example the user puts two different .pdf
files, the second process is immediately terminated, because my pdf-viewer has already been started by ProcessModel
associated to the first .pdf
file.
For this case I need to handle things differently. As far as I can see, I have to ways of doing it:
- Forcing each newly started process into it's own Window: I don't really consider this a good idea additionally to not really knowing how to achieve that with all different software types.
- Informing the user what is happening and why there are 0 instances in the respective item, when clearly the file is opened. I prefer this one and my approach would be to get information from the
source
argument of theOnProcessExited()
method.
So my question: how can I distinguish if the process exit happened because of the described case?
EDIT: My current approach would be to track the process IDs, however I'm wondering if there is a better solution, maybe already implemented to the Process-Class
EDIT2: For better understanding, the complete project can be found here.