Cleaning up after user presses Ctrl+C

Topics: Developer Forum
Feb 10, 2007 at 7:18 PM
Edited Feb 10, 2007 at 11:41 PM
I was having problems with my ConvertFrom-Base64 cmdlet when using the OutputPath parameter if I cancelled the command. I couldn't delete the file without exiting (perhaps a gc::collect() would have worked also - but users shouldnt' have to know this). So I came up with the following:

protected override void BeginProcessing()
    _strBld = new StringBuilder(4200);
    if (_outputPath != null)
        string rpath = this.GetUnresolvedProviderPathFromPSPath(_outputPath);
        _fileStream = new FileStream(rpath, FileMode.Create, FileAccess.Write);
        System.Console.CancelKeyPress += delegate { Cleanup(); };
protected override void EndProcessing()
    string base64 = _strBld.ToString();
    byte[] bytes = Convert.FromBase64String(base64);
private void Cleanup()
    System.Console.CancelKeyPress -= delegate { Cleanup(); };
    _strBld = null;
    if (_fileStream != null) _fileStream.Close();

What do you guys think? Is this safe - hooking and unhooking the CancelKeyPress event? Not sure about the threading implications. The docs don't say anything about which thread the event is called back on.
Feb 10, 2007 at 10:29 PM
BTW if this is something that is safe, perhaps we should push it into one of the base classes (PscxCmdlet?)?
Feb 10, 2007 at 10:38 PM
ugh, that is terrible. btw the ctrl-c handler runs on its own dedicated thread, but thats not the issue here.

however, whats wrong with Dispose? can you get the latest version and verify whether the file is closed when you cancel the command? it seems to be on my machine, however I'm not sure whether my test is correct.
Feb 10, 2007 at 11:34 PM
Well duh! :-) I didn't even realize that you made PscxCmdlet IDisposable. I just assumed that since Cmdlet/PSCmdlet weren't IDisposable I was on my own to figure out how to handle Ctrl+C. This is certainly much better. Your code changes look good. Thanks!

A question for you though. Why not null out _strBld and _text in the if (disposing) block of Dispose? I know these are managed objects that don't require disposing but they can be quite large and just because someone disposes an object (ie this cmdlet) that doesn't mean that they have released all references to it (which could keep alive large objects/arrays held by it's fields).

BTW Oisin asked about this same problem on the newsgroup and didn't get any helpful responses. I wonder if he is also using the Dispose override to cleanup?
Feb 10, 2007 at 11:57 PM
Yeah, I made the PscxCmdlet IDisposable when Oisin was facing this very same problem.
I think we can rely on PowerShell not keeping references to the cmdlet object after calling Dispose, so explicit removal of the reference makes no difference, since the whole object tree is cleaned up during next GC either way. BTW If we wanted to optimize for (non-existent) cmdlet object reuse case, we should forget the reference in the EndProcessing method, not in Dispose...