2

In a C# application that opens both a Windows Form and a Console, how come the Finalizer is called whenever the From is closed, but not whenever the Console is closed? Is there any way for the Finalizer to be called even if the application is being closed from the console?

I noticed this when creating a class that creates a file on Construction and deletes the file on Dispose / Finalize. It worked as expected when closing the Form, but Files were being created but not removed when closing the Console.

EDIT

I must be confused about the terms. Here is my code for the Temporary File:

class TemporaryFile : IDisposable {
    private String _FullPath;

    public String FullPath {
        get {
            return _FullPath;
        }
        private set {
            _FullPath = value;
        }
    }

    public TemporaryFile() {
        FullPath = NewTemporaryFilePath();
    }

    ~TemporaryFile() {
        Dispose(false);
    }

    private String NewTemporaryFilePath() {
        const int TRY_TIMES = 5; // --- try 5 times to create a file

        FileStream tempFile = null;
        String tempPath = Path.GetTempPath();
        String tempName = Path.GetTempFileName();

        String fullFilePath = Path.Combine(tempPath, tempName);
            try {
                tempFile = System.IO.File.Create(fullFilePath);
                break;
            }
            catch(Exception) { // --- might fail if file path is already in use.
                return null;
            }
        }

        String newTempFile = tempFile.Name;
        tempFile.Close();

        return newTempFile;        
    }

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool calledFromDispose) {
        DeleteFile();
    }

    public void DeleteFile() {
        try {
            System.IO.File.Delete(FullPath);
        } catch(Exception) { } //Best effort.
    }
}
iCantSeeSharp
  • 3,880
  • 4
  • 42
  • 65
souldzin
  • 1,428
  • 11
  • 23
  • 1
    Don't use finalizers in C#. That's an archaic concept. Use IDisposable properly – Federico Berasategui Aug 12 '13 at 16:51
  • 3
    Whithout sample code/exception details this never happened... – Alexei Levenkov Aug 12 '13 at 16:52
  • 1
    How do you arrange to call Dispose() ? You're doing something wrong. – H H Aug 12 '13 at 16:52
  • The class seems to be okay, I can bet you are not using `using` and don't call `Dispose` in your application. You cannot rely on finalizers, they are in their full right to not run at all (especially in a short-live console application). You have to use `Dispose` (either directly or through `using`). – Vlad Aug 12 '13 at 17:46
  • @Vlad You are right, I am not using 'using' or calling 'Dispose' but I'm relying on the finalizers to be called. It looks like I'm going to need to capture the console exit event and call dispose from their or something like that. – souldzin Aug 12 '13 at 18:06
  • @SoulDZIN: Okay, so all you need it to catch the console window closing, which is exactly what is not very well supported. I would go for either getting completely rid of the console window (and showing the logs and whatnot inside the main window), or unloading it to a separate process and communicating with it through some IPC means (which is of course ugly). – Vlad Aug 12 '13 at 18:20
  • @Vlad I agree completely with hiding the console window in the Release version. I suppose for debugging, I'm just going to have to remember to close the window properly. – souldzin Aug 12 '13 at 18:27
  • 1
    @SoulDZIN - You might try disabling the close button just to prevent yourself from accidentally closing it. http://stackoverflow.com/questions/6052992/how-can-i-disable-close-button-of-console-window-in-a-visual-studio-console-appl – Erik Funkenbusch Aug 12 '13 at 19:29

1 Answers1

7

The problem is not in your code per se.

When you close a console app by clicking on the x in the window, Windows simply terminates the process. It does not gracefully shut it down, therefore none of your cleanup code gets called.

It's possible to hook into the Console API and catch the close handler and then manually dispose of your objects, but there are reports that this functionality does not work very well under more recent versions of windows.

Capture console exit C#

Community
  • 1
  • 1
Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • I somewhat suspected this, so I'm probably going to hide the Console. In that case is there a way to catch if the OS is trying to terminate the process? I plan on putting a large amount of data into the temporary file, and it would be undesirable if that data never got erased for the user if he had to end the process prematurely or something. – souldzin Aug 12 '13 at 18:26
  • @SoulDZIN: [this](http://msdn.microsoft.com/en-us/library/system.windows.forms.application.applicationexit.aspx) must help. – Vlad Aug 12 '13 at 18:31
  • @Vlad - No. That event won't get called in the event of the application being forcibly terminated either. That only gets called during a graceful shutdown. – Erik Funkenbusch Aug 12 '13 at 19:22
  • @Mystere Man: well, if the application is closed through Task Manager, there's no way to intercept this, right? So we can ignore it. I think the OP just means "closes the window" saying "trying to terminate the process". If however the OS is forcibly terminating the process, there is of course no legal way. – Vlad Aug 12 '13 at 19:29
  • @Vlad - He means clicking the close box in a windows console window, which does (in theory) send some Win32 signals to the app, and if ignored it does the same thing as killing it in task manager. However, there are apparently problems in Windows 7+ in catching these signals properly. It's probably related to the anti-shatter fixes they've put in place. – Erik Funkenbusch Aug 12 '13 at 19:32
  • I meant forcibly terminating the process. It sounds like there's no way to catch this; which makes sense, because its trying to forcibly be terminated. Still, @MystereMan answered my original question. Accepting. – souldzin Aug 12 '13 at 19:36