Wait until "Write complete" - c#

"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.

Related

C# open a webpage and see if it was closed

I am trying to keep track of a webpage; whether it was closed, specifically. I use this code to open processes and keep track of close:
this.Process = new Process();
this.Process.EnableRaisingEvents = true;
this.Process.Exited += new EventHandler(Process_Exited);
this.Process.StartInfo.FileName = this.ProcessPath;
this.Process.StartInfo.Arguments = this.Arguments;
this.Process.Start();
private void Process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Exiting...");
}
This works fine for other types of processes, like batch files (it'll print "Exiting..." when I close them). However, if I use it to open a webpage and then close that webpage, it'll never print "Exiting". I assume this is because the browser can have multiple tabs and it's waiting for the whole browser to close. How can I keep track of the specific tab being exited?

Unpacking a .cab file and then closing the running process on windows CE 6.0 with .net mobile 3.5

I have a windows CE 6.0 program that uses a .cab file for installation. it incorporates the guide from http://msdn.microsoft.com/en-us/library/aa446487.aspx to support automatic self-updates.
the program can check for updates just fine, it downloads the update like it should, but when I try to make it unpack the .cab file it just downloaded, it fails.
this is my code:
void ResponseReceived(IAsyncResult res)
{
try
{
_mResp = (HttpWebResponse)_mReq.EndGetResponse(res);
}
catch (WebException ex)
{
MessageBox.Show(ex.ToString(), "Error");
return;
}
// Allocate data buffer
_dataBuffer = new byte[DataBlockSize];
// Set up progrees bar
_maxVal = (int)_mResp.ContentLength;
pgbDownloadBar.Invoke(new EventHandler(SetProgressMax));
// Open file stream to save received data
_mFs = new FileStream(#"\Application\CCOptimizerSetup.cab",
FileMode.Create);
// Request the first chunk
_mResp.GetResponseStream().BeginRead(_dataBuffer, 0, DataBlockSize,
OnDataRead, this);
}
void OnDataRead(IAsyncResult res)
{
// How many bytes did we get this time
int nBytes = _mResp.GetResponseStream().EndRead(res);
// Write buffer
_mFs.Write(_dataBuffer, 0, nBytes);
// Update progress bar using Invoke()
_pbVal += nBytes;
pgbDownloadBar.Invoke(new EventHandler(UpdateProgressValue));
// Are we done yet?
if (nBytes > 0)
{
// No, keep reading
_mResp.GetResponseStream().BeginRead(_dataBuffer, 0,
DataBlockSize, OnDataRead, this);
}
else
{
// Yes, perform cleanup and update UI.
_mFs.Close();
_mFs = null;
Invoke(new EventHandler(AllDone));
}
}
private void AllDone(object sender, EventArgs e)
{
Cursor.Current = Cursors.Default;
DialogResult dialogresult = MessageBox.Show(#"CCOptimizer has finished downloading. Open now?", "Download complete", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
switch (dialogresult)
{
case DialogResult.OK:
Application.Exit();
Dispose();
Close();
Invoke(new EventHandler(StartProcess));
break;
case DialogResult.Cancel:
Form1 oForm = new Form1();
oForm.Show();
Hide();
break;
}
}
private void StartProcess(object sender, EventArgs e)
{
Process.Start(#"\Application\CCOptimizerSetup.cab", null);
}
It doesn't work though. wherever I place the invocation of StartProcess(), either it just shuts down with no message or I get an error during unpacking that one of the files i'm trying to update is still in use. During debugging, it just stops the program. If I try on an installed version, it very briefly flashes a window, then locks up the machine with the WaitCursor rotating and needs a reboot, although it can install just fine afterwards.
How can I close the current program and open a .cab file without having to reboot the machine?
You've got a flaw in your update logic, probably that the app you want to update is the thing checking for updates (it's not entirely clear from the question, but the behavior suggest this is the case).
An application cannot directly update itself because, for what should be fairly obvious reasons, you cannot replace the assemblies that are already loaded and running.
There are, generally speaking, two ways that I have used to get around this. Both require a second executable (which in many case I already have as a watchdog app anyway).
Instead of directly launching your application, launch some "updater" application first. That application can check for updates, inform the user, download, and install/overwrite the target application because it's not yet running. The updater then runs the target application when it's done, or if no update steps are required.
Instead of directly launching your application, launch some "bootstrap" application first. The bootstrap looks in local temporary storage for any update files, executes them if they exist, and then runs the normal application. Have the application itself check for updates and pull them to the temporary storage location. When updates have been pulled, have it shutdown and restart the bootstrap, which then will apply the update.

C# OpenFileDialog spawns many threads, and application exit hanging

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.

Preventing the application from leaving the file operation in the middle and exiting

I'm making something that writes data to a file. Now the problem I'm facing is that the application exits and the file writing operation is left hanging midway. As in I want a set of things to be either written completely or none. But the application exits and only half of it is written sometimes. Any suggestions on what I'm doing wrong here? Thanks.
There isn't much to go on here... but...
Are you properly flushing your file stream?
It could be you're finishing your program just fine, but closing it before you're fully written.
try {
// Open file, start writing...
}
catch (Exception e)
{
// Close file and discard it (if that's what you want), log error with e.ToString()
}
// Close file
Let's take WinForm as an example. When users click the X button in the top-right corner(or some other buttons hence the exit), in the click event(or some other event like Form_Closing), check the status of the File_Operation_Thread(I assume you have such a Thread/BackgroundWorker to operate the file, otherwise your UI will be hanging). If the thread is running, show a dialog with Wait/Cancel button saying "The operation is being processing". The final implementation looks like:
BackgroundWorker worker = new BackgroundWorker();
void WriteButton_Clicked(object sender, EventArgs args)
{
//start writing to the file asynchronously, something like
//worker.DoWork += (s,e) => { /*writing to file*/ };
}
void ExitButton_Clicked(object sender, EventArgs args)
{
if (worker.IsBusy)
{
//show a dialog window
if (CANCEL)
{
worker.CancelAsync();
//but rolling the changes back is a nightmare!!
}
else
{
//exit the applcation when worker.RunWorkerCompleted
}
}
}
You probably have an exception that is caught and "eaten" by a try/catch block. Try to activate the handling of exceptions by the debugger (Debug->Exceptions->Common Language Runtime, and select both the check boxes).

delay Application Close best practice?

Is there a better way to handle the task of doing something after the user has chosen to exit a WinForms program than this :
[edit 1 : in response to comment by 'NoBugz] In this case there is no ControlBox on the Form, and there is a reason for putting one level of indirection in what happens when the user chooses to close the Form [/edit 1]
[edit 2 : in response to all comments as of GMT +7 18:35 January 20 ] Perhaps using fading out the MainForm is a simple illustration of what you might want do as the Application is being closed : the user cannot interact with that : it is self-evidently related to the user's decision to terminate the application. [/edit 2]
(use some form of threading ?) (implications for a multi-threaded app ?) (does this code "smell bad" ?)
// 'shutDown is an external form-scoped boolean variable
//
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// make sure we don't block Windows ShutDown
// or other valid reasons to close the Form
if (e.CloseReason != CloseReason.ApplicationExitCall) return;
// test for 'shutDown flag set here
if (shutDown) return;
// cancel closing the Form this time through
e.Cancel = true;
// user choice : default = 'Cancel
if (MessageBox.Show("Exit Application ?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.OK)
{
// user says Exit : activate Timer, set the flag to detect Exit
timer1.Enabled = true;
shutDown = true;
}
}
Summary : In a very standard WinForms application (one MainForm launched in Program.cs in the standard way) : in the FormClosing Event handler of the MainForm :
exit immediately (triggering the default behavior : which is to close the MainForm and exit the Application) if :
a. the CloseReason is anything other CloseReason.ApplicationExitCall
b. if a special boolean variable is set to true, or
if no immediate exit : cancel the "first call" to FormClosing.
the user then makes a choice, via MessageBox.Show dialog, to Exit the Application, or Cancel :
a. if the user Cancels, of course, the Application stays "as is."
b. if the user has chosen to 'Exit :
set the special boolean flag variable to true
run a Timer that does some special stuff.
when the internal test in the Timer code detects the "special stuff" is done, it calls Application.Exit
My suggestions, both as a developer and a user:
A very fast task
Just do the task in the Closing event handler.
A less fast, but not incredibly slow task
Create a non-background thread (so it's not shut down when the application exits) with the task in the Closing event handler.
Let the application exit. Forms will go away, et cetera, but the process will keep running until the task is done.
Just remember to handle exceptions and such in that worker thread. And make sure that things doesn't crash if the user reopens your application before that task is done.
Slower tasks
In the Closing event handler, open a shutting-down-form and let the form itself close.
Do the task in the/behind the shutting-down-form while displaying some friendly progress and information.
Exit application when task is done.
Some untested example code. We are doing something similar to this in one of our applications. The task in our case is to store window properties (location, size, window state, et cetera) to a database.
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// If it wasn't the user who asked for the closing, we just close
if (e.CloseReason != CloseReason.UserClosing)
return;
// If it was the user, we want to make sure he didn't do it by accident
DialogResult r = MessageBox.Show("Are you sure you want this?",
"Application is shutting down.",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (r != DialogResult.Yes)
{
e.Cancel = true;
return;
}
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
// Start the task
var thread = new Thread(DoTask)
{
IsBackground = false,
Name = "Closing thread.",
};
thread.Start();
base.OnFormClosed(e);
}
private void DoTask()
{
// Some task to do here
}
I don't see anything "wrong" with this. My only recommendation would be to let the user know that the program is "shutting down" by raising a non-modal window or perhaps a notification toaster above the system tray.
A couple of minor points:
I'd question the need for a timer: as the application is exiting anyway, and the user won't therefore expect the UI to be responsive, why not simply do the clean-up code on the UI thread? As suggested by #Dave Swersky, a little notification window during cleanup would be polite.
What happens if the application exit is triggered by a Windows shutdown or a user logoff?

Categories

Resources