C# OpenFileDialog spawns many threads, and application exit hanging - c#

Lately I have been having problems with my application not shutting down properly. After it has been told to exit, when I look in the Task Manager the process is still running, and I am unable to kill the process.
Suddenly I realized a strange pattern. The shutdown problem only appeared if I had opened a OpenFileDialog anytime when the application was running. I debugged a bit and saw that some threads did not shut down after the application should have exited. Also, to my surprise, when I invoked OpenFileDialog.ShowDialog(), it spawned a lot of threads (See the pictures below). The threads are alive throughtout the lifetime of the application.
Why does OpenFileDialog spawn so many threads? And why are they not closed after the file dialog is closed.
How does the OpenFileDialog problem relate to my shutdown problem...?
Threads just before openFileDialog.ShowDialog():
Threads while the dialog is open:
Threads right after openFileDialog.ShowDialog() has returned:
Threads hanging after the application has been shut down:
Code for opening the dialog:
private void startAllSequenceToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofn = new OpenFileDialog();
DialogResult result = ofn.ShowDialog();
if (result == DialogResult.Cancel)
return;
MessageBox.Show("do stuff");
}

I search the web for this and found nothing but I fixed by issue by calling Dispose. Code below:
private void startAllSequenceToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofn = new OpenFileDialog();
DialogResult result = ofn.ShowDialog();
if (result == DialogResult.Ok)
{
MessageBox.Show("do stuff");
}
// This one line seems to allow my application to exit cleanly in debug and release.
// But I don't instantiate a new object.
// I used the control on the form and called Dispose from form_closing.
ofn.Dispose();
}

This thread OpenFileDialog/c# slow on any file. better solution? has some half decent answers. All in all, as a last resort check with ProcExp from sysinternals. Also, is it only slow in the debugger? If so I wouldn't worry about it since it doesn't affect your users. Just make sure to isolate from your other code so your team is not constantly tripping over it in the debugger since it is slow.

Related

Wait until "Write complete"

"simple" question to the "streamer guy's there". My program starts SQL backup processes in single tasks, for any backup per DB.
All the tasks start one by one after the first task finished. But, when the SQL backup command goes to the SQL server, than the process to write the backupfile takes more time then task takes to finish. At this moment, the user can close the program and skip the backupprocess to the big DB files.
Is there a way to block my programm from closing, until every single backupfile is completly written to the HDD?
You can handle the Closing of the Window like this:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (BackupStillRunning)
e.Cancel = true;
else
e.Cancel = false;
}
What you should do though is ask the user if he really wants to quit, something like this:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (BackupStillRunning)
{
if (MessageBox.Show("The backup is still running, if you close the application, the backup will be cancelled. Do you want to proceed?", "Caption", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
e.Cancel = true;
}
else
{
e.Cancel = false;
}
}
Simply not letting the user close the application will quickly get frustrating. If you really dont want the user to close the application, you should at least show a message explaining why.
As Damien_The_Unbeliever pointed out, there is no way to completely prevent the application from shutting down.

How to check a Window already opened when button is clicked?

I am Working in Visual Studio 2008 Winforms Application project in Windows 7 (32 bit).I am doing the project in C#.
I have placed some buttons in a tab and added actions for that once it is clicked. While clicking the button am just running a .exe file in its action part.
My problem is that, i opened a window by clicking one button(so the .exe file is running), now while am clicking the button again it is opening same window again irrespective of checking that it is open or not. I want to solve this issue,as when a window is opened it must not open again on another click on same button. How to solve this issue. ?
Please help....
Thanks in advance..
You could check if the process is already running, when re-clicking the button:
private void btnStartExecutable_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("InsertProcessNameHere");
if (pname.Length == 0)
{
MessageBox.Show("Application isn't running yet.");
//Start application here
Process.Start("InsertProcessNameHere");
}
else
{
MessageBox.Show("Application is already running.");
//Don't start application, since it has been started already
}
}
You can try this:
bool processExited = true;
private void button1_Click(object sender, EventArgs e)
{
if (processExited)
{
Process process = new Process();
process.EnableRaisingEvents = true;
process.Exited += MyProcessExited;
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = "notepad.exe";
process.Start();
processExited = false;
}
else
{
MessageBox.Show("Still running");
}
}
void MyProcessExited(object sender, EventArgs e)
{
processExited = true;
}
The right answer here IMHO is that unless the two application shares a common resource or can talk to each other through some channel, there is no safe and efficient way to achieve what you want. Since the process is external, it could already be running before your calling app starts, or even while it's already running. You won't be able to tell if the process has been started from your app or not.
By the time I'm writing this your question does not yet state if you are in liberty to modify the external app you are calling. If you are however, using a Mutex would be a quick and easy way to solve your problem.
In your external app, whenever you want to make the other app aware of whatever condition you want (be it that the process is running or that a specific window is opened), have a Mutex instance created like this:
var mutex = new Threading.Mutex(true, "mutex unique identifier");
And in your calling app, try to create a Mutex instance with the same identifier:
bool alreadyExists;
var mutex = new Threading.Mutex(false, "mutex unique identifier", out alreadyExists);
Here the alreadyExists variable will tell you whether or not the external process is running or not. This is much safer than trying to identify it via its name, as other processes could have the same or a new version could be of a different name. Of course, the mutex identifier must be as unique as possible (like a Guid), otherwise you may encounter the same problem. ;)
Whenever you feel like the mutex must be released (at external app level), release it:
mutex.ReleaseMutex();
Note that if the process ends the mutex will be automatically released by the OS.
If the external app isn't a .NET based app, you can still create a mutex with Win32 API functions.
Thanks for the support.. I got the answer like this..
1) Creating an event'Exit' for the process in function button click
2) Define a function for the exit event where you set a flag
3) Check the flag is set or not everytime while opening the process in the function button click
Event for Exit: 'P' is the name of process:
p.Exited += new EventHandler(p_Exited);
p_Exited will be the function name where we will set the flag.
Thanks all...
If you know the name of the process that gets started or the path the .exe is run from you can use the Process class to check to see if it is currently running.
http://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx

ShowDialog in Closing-Event

If the user closes the Application a Save-File-Message have to be shown (to be sure that he wants to discard the changes of edited files).
to implement this, i have a menuitem with a command-binding (without key-gesture):
private void Command_Exit(object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
the mainwindow has a closing-event. in this event i check if there unsaved files. if yes, the savedialog has to be opened (to choose, which files have to be saved):
private void Window_Closing(object sender, CancelEventArgs e)
{
if (sdl.Count() > 0)
{
SaveDialog sd = new SaveDialog();
IEnumerable<Doc> close = sd.ShowDialog(this);
if (close == null)
e.Cancel = true;
else
foreach (Doc document in close)
document.Save();
}
}
in this ShowDialog-Method (implemented in my SaveDialog-Class) i call
bool? ret = ShowDialog();
if (!ret.HasValue)
return null;
if (!ret.Value)
return null;
The problem is:
If i use the Alt+F4-Shortcut to close the Application (default-behaviour of the mainwindow) it works and i get the savedialog if there are unsaved files. but if i close the application by executing the Command_Exit-Method, the Method-Call
bool? ret = ShowDialog();
returns null and the dialog does not appear.
If i assign the Alt+F4 KeyGesture to the CommandBinding, the problem is switched: Executing Command_Exit works well but Alt+F4 Shortcut not.
What is the reason that the ShowDialog()-Method works not in both cases and how to fix it?
The Application.Current.Shutdown route allows you to listen for the shutdown request by handling the Exit event as detailed here:
http://msdn.microsoft.com/en-us/library/ms597013.aspx
It doesn't detail how it closes windows, so I wouldn't necessarily be convinced that the closing event handler would fire before it closes the application.
The other very standard way to shut the application down is to close the main window (the one shown at the very beginning). This would likely be the Window.Close method, if you are in the context of the window already, just call Close(). This will then hit the closing event handler.
Your Command_Exit implementation is wrong. Application.Current.Shutdown() means that the application is already shutting down, which can prevent the dialogs from opening.
You should implement the command other way: in the command you should ask your business logic if it's safe to shutdown, and issue Application.Current.Shutdown() only in that case. Otherwise, you should ask the business logic to start the shutdown sequence, which would in turn save the open files, and issue a Shutdown upon completing save operations.
Moreover, you should trigger the same routine when the user tries to close the main window (that is, on its Window.Closing).

C#/.NET: Closing another process outside the main window

I just wanna ask your opinion/suggestion on how to 'terminate' a running application/process is C#
Right now, I do have the following codes:
Process myProcess;
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
DirectoryInfo di = new DirectoryInfo(System.Environment.GetFolderPath(Environment.SpecialFolder.Programs));
myProcess = Process.Start(di + #"\Wosk\Wosk.appref-ms"); // opening a file coming for Startup Menu
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
myProcess.Kill(); // not working - Cannot process request because the process has exited
}
I also tried myProcess.Close(); but nothing's happening.
You should have a look at
Process.HasExited Property
A process can terminate independently
of your code. If you started the
process using this component, the
system updates the value of HasExited
automatically, even if the associated
process exits independently.
Based on your comment it looks like the Process instance has already exited when you hit the close button. This can happen at any time and it's something you need to guard against. The easiest way is to simply catch the exception that results from calling Kill on an already exited process.
try {
myProcess.Kill();
} catch ( InvalidOperationException ) {
// Process is already finished so nothing to do
}
You are starting a program that was installed with ClickOnce. The .appref-ms is executed by a helper program, rundll32.exe, that starts the process and quickly exits. To terminate the started process, you'll need to find the actual running .exe with Process.GetProcessesByName() and use the Kill method.
We can't tell you what the process name is, that's contained in the .appref-ms file. But it is easy for you to see with TaskMgr.exe.
Process[] islemler = Process.GetProcessesByName("osk");
foreach (Process islem in islemler)
islem.Kill();
First please replace:
di + #"\Wosk\Wosk.appref-ms"
with:
Path.Combine(di.FullName, #"Wosk\Wosk.appref-ms")
Now to the point: I don't know what Wosk.appref-ms is or how this process is started. If this is a file it will be opened with the default program associated with this file extension. The problem could be related to the fact that the process you start only starts another process and terminates immediately. That's why when you try to kill it it says that it has already exited, but the actual process it spawned is still running. In this case you will have to enumerate through the running processes with Process.GetProcesses(), find the process and stop it.

Why would Application.Exit fail to work?

I have an application that has been getting strange errors when canceling out of a dialog box. The application can't continue if the box is cancelled out of, so it exits, but it is not working for some reason, and thus it keeps running and crashes.
I debugged this problem, and somehow the application runs right past the Application.Exit call. I'm running in Debug mode, and this is relevant because of a small amount of code that depends on the RELEASE variable being defined. Here is my app exit code. I have traced the code and it entered the ExitApp method, and keeps on going, returning control to the caller and eventually crashing.
This is an application which provides reports over a remote desktop connection, so that's why the exit code is a bit weird. Its trying to terminate the remote session, but only when running under release because I don't want to shut down my dev machine for every test run.
private void ExitApp()
{
HardTerminalExit();
Application.Exit();
}
// When in Debug mode running on a development computer, this will not run to avoid shutting down the dev computer
// When in release mode the Remote Connection or other computer this is run on will be shut down.
[Conditional("RELEASE")]
private void HardTerminalExit()
{
WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, false);
}
I've run a debugger right past the Application.Exit line and nothing happens, then control returns to the caller after I step past that line.
What's going on? This is a Windows Forms application.
This is an article which expands on the same train of thought you are going through: http://www.dev102.com/2008/06/24/how-do-you-exit-your-net-application/
Basically:
Environment.Exit - From MSDN: Terminates this process and gives the
underlying operating system the
specified exit code. This is the code
to call when you are using console
application.
Application.Exit - From MSDN: Informs all message pumps that they
must terminate, and then closes all
application windows after the messages
have been processed. This is the code
to use if you are have called
Application.Run (WinForms
applications), this method stops all
running message loops on all threads
and closes all windows of the
application. There are some more
issues about this method, read about
it in the MSDN page.
Another discussion of this: Link
This article points out a good tip:
You can determine if System.Windows.Forms.Application.Run has been called by checking the System.Windows.Forms.Application.MessageLoop property. If true, then Run has been called and you can assume that a WinForms application is executing as follows.
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit();
}
else
{
// Use this since we are a console app
System.Environment.Exit(1);
}
Having had this problem recently (that Application.Exit was failing to correctly terminate message pumps for win-forms with Application.Run(new Form())), I discovered that if you are spawning new threads or starting background workers within the constructor, this will prevent Application.Exit from running.
Move all 'RunWorkerAsync' calls from the constructor to a form Load method:
public Form()
{
this.Worker.RunWorkerAsync();
}
Move to:
public void Form_Load(object sender, EventArgs e)
{
this.Worker.RunWorkerAsync();
}
Try Environment.Exit(exitCode).
I have went though this situation in many cases I use Thread.CurrentThread.Abort()
and the process is closed. It seems that Application.Exit isn't hooking up properly with current thread.
Also ensure any threads running in your application have the IsBackground property set to true. Non-background threads will easily block the application from exiting.
Make sure you have no Console.ReadLine(); in your app and Environment.Exit(1); will work and close your app.
I created the following that will exit the app anywhere. You don't have to worry if the Form is running or not, the test determines that and calls appropriate Exit.
public void exit(int exitCode)
{
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit()
}
else
{
// Use this since we are a console app
System.Environment.Exit(exitCode);
}
} //* end exit()
Is this application run (in the Main method) using Application.Run()? Otherwise, Application.Exit() won't work.
If you wrote your own Main method and you want to stop the application, you can only stop by returning from the Main method (or killing the process).
Try this :
in Program.cs file :
after Application.Run(new form());
add Application.Exit();
private void frmLogin_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult result = MessageBox.Show("Do you really want to exit?", "Dialog Title", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
Environment.Exit(0);
}
else
{
e.Cancel = true;
}
}
else
{
e.Cancel = true;
}
}

Categories

Resources