I'm writing a small library to help manage some objects in Excel. I'm testing this DLL using a simple console application that makes calls to the library, then prints the results out. I can then end the program in any of the typical fashions, usually by either hitting return (thus completing the ReadLine call) or hitting the window's close button. However, the reference to the Excel instance behaves differently based on how the program exits.
In my program, if no existing reference to Excel can be found, I use the following line:
_app = new ExcelInterop.Application();
where _app is an instance of Microsoft.Office.Interop.Excel.Application in either a static or singleton class (I've tried both, both have the same results).
Assuming the program creates it's own instance (and doesn't find one already open):
The instance will remain open if the program is exited by clicking the close window button:
The instance is released, and no longer appears in the task manager if the program is exited by reaching the end of the code in the Main block
Is there anyway to make all program ends behave like the latter case? Furthermore, this DLL will go on to be used in a WPF application, are there similar concerns in WPF? Or at large, even?
Perhaps most importantly, what are the technical reasons for this behavior?
A console mode program is a pretty hostile place for the COM interop wrapper objects that are needed for an apartment-threaded out-of-process COM server. This program demonstrates the issue:
using System;
class Program {
static void Main(string[] args) {
var prg = new Program();
Console.ReadLine();
}
~Program() {
Console.WriteLine("Clean-up completed");
System.Threading.Thread.Sleep(1500);
}
}
Try it both ways, by pressing Enter and by clicking the Close button. You'll see that the finalizer never gets executed. The operating system terminates the process before it gets a chance to shut down properly when you click the Close button.
Same problem with the finalizers for the COM wrappers. They cannot execute so IUnknown::Release() doesn't get called and the Office program is completely unaware that the client program is no longer there. Windows has its own cleanup for abandoned out-of-process servers but that doesn't work for Office programs for some otherwise mysterious reason.
That explains it, fixing it isn't so easy. You'll have to register a callback that runs when the Close button is clicked. If necessary, set the app reference to null if it is still in scope and force the finalizer to run with GC.Collect() + GC.WaitForPendingFinalizers(). Do keep in mind that this is just a band-aid, not a fix. It won't work when the user aborts your program while you are busy talking to the Office program. Avoiding a console mode project is best.
Related
Suppose I have a C# WinForms application and it is started by external program simply by using Process.Start(MyModule.exe).
I've tried to debug my code by using My project properties->Debug->Start Action->Start external program (with setting proper Working directory of course).
My enother attempt was Debug->Attach to process
UPDATE: Both my module and external program use one resource. So external program releases it, then calls Process.Start(), waits for my process to exit ans then capture the resource again. So I can't attach when your program is already running.
Both of them failed - breakpoint in Program.cs was never hit.
So, how can I debug my code in such circumstances?
There are two ways I know of to easily solve this problem. The first way is have your program request a debugger attach to it as the first thing it does in Main via Debugger.Launch()
public static void Main(string[] args)
{
Debugger.Launch();
//Rest of your code here
}
This will make a dialog like the following show up
This will allow you to attach to your running visual studio or start a new instance.
The other way to solve this when you can't use the previous method (for example I don't think it works inside services) is put a loop at the start of your code that will loop forever until a debugger is attached, this gives you enough time to do the "Attach to process" method you tried earlier without letting the program progress.
public static void Main(string[] args)
{
while(!Debugger.IsAttached)
{
Thread.Sleep(1000); //Sleep 1 second and then check again.
}
//Rest of your code here
}
There are two different methods you can use System.Diagnostics.Debugger.Launch() or System.Diagnostics.Debugger.Break() The first will attach a debugger (letting you choose which) and then do nothing. In the case where one is already attached nothing will happen.
The latter will do exactly as Launch in the case no debugger is attached and will serve as a break point if one is attached.
So simply write System.Diagnostics.Debugger.Break(); where you want your break point to be.
That will result in a dialog asking you how you wish to debug the program (which of course also means your should remove the line when your done debugging)
In the dialog choose the appropriate instance of VS (or create a new) and the simply continue debugging as usual
I made a program based on Aforge (it's a video library). This library creates its own refresh events for the next video frame from camera. So far so good, earlier people have helped me with multi threading so these Aforge threads could report back to the main program thread, again so far so good, it works great.
The code can be seen here: how to do multithreading when using outside referenced code.
But now I regularly notice a new program error. The problem starts when I want to exit the program. At the moment the Aforge thread might still be active. And it wants to write back to main form that is closed.
Somehow I need to stop the other thread before I close the program. There is an option in Aforge to do something like camera stop, but it's not enough. But then still my code wants to write on the main form that's already closing.
Is there a way to stop all threads, or some safe way to close from the originating thread? I even placed the back reporting to the main program in a try catch construction but it didn't work well, the only way of stopping it in these situations is to press the stop execution button within Visual Studio itself.
If I understand your problem correctly, you may have an Invoke call about to happen on your form just as you've closed the form. I've had this happen as well.
What I've done is to set a "shutdown" variable when I start to close the form, and then use AppDomain.CurrentDomain.UnhandledException to watch for InvalidOperationException (or whatever you're getting), and ignore if shutdown is set.
I'd like to save data from a console application in its final state when closed. I've figured out how to use serialization to save the data, but not how to make this happen when the application closes.
One method is to set an unmanaged handler to intercept the close command and perform an operation, however once the event handler has been called, GC() has already been run and the managed program is no longer in memory.
Any ideas?
Edit:
The essential problem here is that I have an object that listens to a stream for the life of the program. If the program is then closed externally (eg by pushing the x in the corner) then no other code in the Main() method is executed, bypassing the closing serialization code.
Normally, you'd just put this code at the end of your Main routine - this would then be the last thing that is run prior to your console application closing.
If you're trying to handle something at the last possible moment before the managed code shuts down, you can subscribe to AppDomain.DomainUnload. This event is fired right as the AppDomain is unloaded.
I would create an application-life-time class instance that stores the state, and add serialization code to its destructor.
Another idea is using try{} finally{} in your program.
I'm trying to launch an external updater application for a platform that I've developed. The reason I'd like to launch this updater is because my configuration utility which handles updates and license configuration for the platform has shared dependencies with other assemblies in the folder where the update will be deployed. So, while I can rename the configuration utility and overwrite it when deploying the update, I can't rename or overwrite the DLLs it depends on. Hence, the external updater application.
I'm handling all of the update gathering logic in the configuration utility, then attempting to launch the updater to handle the actual file copy/overwrite operations. Obviously, because of the file in use issues, I need the configuration utility to exit right after the updater begins.
The problem I'm having is that I'm using the standard Process.Start method of launching the updater, and as soon as the configuration utility exits, the updater process gets killed too.
Is there any way that I can create a Process that outlives its parent, or launch an external application that can run beyond the program that launched it?
EDIT:
Apparently, in my updater application, I miscalculated the number of command line arguments which are passed to it. Because of this, the updater would exit immediately. I misinterpreted this to mean that the launcher application was killing the "child" process, when in fact, it wasn't.
The answers below are correct.
It seems that the problem you are seeing has a different reason because the Process class will not kill any processes started using Process.Start when your application exits.
See this simple sample program, the calculator will stay open:
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
Process.Start(#"C:\windows\system32\calc.exe");
}
}
There's no reason why a process started with Process.Start should automatically die when the launcher exits. My guess is that you're doing something odd in the updater.
I've written an updater doing exactly this kind of thing before, and it's been fine.
For example:
Launcher.cs:
using System;
using System.Diagnostics;
class Launcher
{
static void Main()
{
Console.WriteLine("Launching launchee");
Process.Start("Launchee.exe");
Console.WriteLine("Launched. Exiting");
}
}
Launchee.cs:
using System;
using System.Threading;
class Launchee
{
static void Main()
{
Console.WriteLine(" I've been launched!");
Thread.Sleep(5000);
Console.WriteLine(" Exiting...");
}
}
Compile both of them, separately, and run Launcher.exe. The "launchee" process definitely lasts longer than the launcher.
Just a thought from my foggy memory, but I seem to remember having a discussion a while back that when the Process.Start method is called from Form that the spawned process has some sort of dependency (not sure what, why or how, memory is a bit foggy).
To deal with it, a flag was set that was actually called from the Main() method of the application after the main form/app exited and that if the process was launched from the Main() method, eveything worked out just fine.
Just a thought, like I said, this is purely from memory, but some of the examples posted here all being called from the Main() method of a console app seemed to jog something.
Hope all works out well for you.
We run a C# console application that starts multiple threads to do work. The main function looks something like this:
try
{
DoWork();
}
catch (Exception err)
{
Logging.Log("Exception " + err.ToString());
}
Logging.Log("Finished");
The DoWork() function reads new jobs from a database, and spawns threads to process one work item each. Since last week, the application has started disappearing mysteriously. It disappears from the processes list and there is no entry in the event logs. The log file shows work up to a certain point: it does not log an exception, or the "Finished" line.
Any clue(s) on how a C# application can vanish like that?
EDIT: Threads are created like:
new Thread(SomeObj.StartFunc).Start();
Some of the disappearances occur when no threads are running.
P.S. We installed DebugDiag with a rule to create a crash dump whenever our program crashed. It did not create any dump files when the process disappeared.
You need to have a similar catch block at the top level of the function that every thread works. If there is an uncaught exception on a thread it will kill the application, and the catch block on the main thread is not going to help.
What's the identity that you're using to run the console application?
Also, you might want to use SetConsoleCtrlHandler to capture the console events. Look at this blog post for more details. We had a similar issue when the console application was run under a service account, and it would occasionally get terminated. I'm not sure if this is what you're running into. Let me know I can post some code.
UPDATE: It looks like your scenario resembles what we had experienced. In your console event handler, you need to check for the LogOff event and return true. Look at this KB article.
public static void inputHandler(ConsoleCtrl.ConsoleEvent consoleEvent)
{
if (ConsoleEvent == ConsoleCtrl.ConsoleEvent.CtrlLogOff)
return true;
return false;
}
It's possible that one of the threads that the DoWork method is spawning is throwing an exception. The default behavior in this case is for the process to terminate. You can stop this from happening by using the AppDomain.UnhandledException event to override the default behavior.
A console program quits when the main function exits. Since DoWork just spawns a few threads it's returning control to main right away, and since Main has nothing else to do it exits and the program ends. At this time the threads spawned by DoWork are also killed.
That it worked before means either there was something in DoWork() to wait on those threads that now returns right away (is broken) or that part still works but a thread that used to take a long time to return now aborts and returns right away.
It could perhaps be the Logging.Log function that throws your exception.
I have managed to make programs disappear without a trace in a similar fashion to you (no exception traces and no termination log messages) in the past. Almost all the time it was related to killing the stack (the name of this website always reminds me).
It is possible that you are suddenly trying to process far more data than usual, or using re-entrant routines, or being 'clever' with pointers.
DISCLAIMER: My experience was with a Win32 C++ application, not C#.
It could be a memory leak. If your application takes too much memory, Windows will kill it. You can check how much memory you are using: if it grows over time, you may have a memory leak.
Another possibility is that somewhere, you have code calling Environment.Exit(). Try a full text search through your code to double-check. You never know!
Be careful; there are some exceptions that cannot be caught: OutOfMemoryException and StackOverflowException.
Therefore your program will die terribly, but silently.