2

I have a WinForms application. It's written to disk. I run the application from disk and eject the disk from CD. Then I take the exception: there is no disk in the drive. please insert a disk into drive. How can I catch this exception and correctly close my application?

Rover
  • 2,203
  • 3
  • 24
  • 44
  • What do you mean by "correctly close my application"? Do you just want to catch the exception, or do you want to perform cleanup actions? – Pieter van Ginkel Oct 18 '10 at 10:46
  • I want catch this exception and replace it message on own (and then may be close application). – Rover Oct 18 '10 at 11:19

4 Answers4

4

You should try to detect cd eject. Here is a working sample: publicjoe.f9.co.uk/csharp/snip/snip002.html

you can also check out this: Detecting Eject/Insert of Removeable Media

Community
  • 1
  • 1
honibis
  • 811
  • 1
  • 5
  • 13
  • Application.ThreadException doesn't catch this exception. The message is appear, but Application_ThreadException doesn't invoked. – Rover Oct 18 '10 at 11:13
  • Did you add UnhandledException handler too? This message wont be displayed itself if you handle it. – honibis Oct 18 '10 at 11:22
  • I tried to add AppDomain.CurrentDomain.UnhandledException. It also doesn't catch this exception. – Rover Oct 18 '10 at 11:32
  • edited the answer, adding SetUnhandledExceptionMode. You can also consider detecting cd eject. – honibis Oct 18 '10 at 11:50
  • Same problem. I take the error message and can't close application by X button. But now i take some exceptions in .._Exception methods. But it appear only after unneeded MessageBox. – Rover Oct 18 '10 at 12:13
  • This is the only way to handle system exceptions(as soon as i know). You should try to detect cd eject. Here is a working sample: http://www.publicjoe.f9.co.uk/csharp/snip/snip002.html – honibis Oct 18 '10 at 12:38
  • Checking of ejecting of CD is working. You can change your post and leave only links on detection of CD ejection and I mark your answer as accepted. Thanks for help! :) – Rover Oct 18 '10 at 13:38
  • @honibis The working sample from your page http://publicjoe.f9.co.uk/csharp/snip/snip002.html is not online anymore. Can you please submit it again ? TY – Filimindji Sep 30 '16 at 10:10
3

This is a generic problem with any kind of program, not specific to a Winforms app. It is related to the way a process is created. Windows creates a so-called memory mapped file, it maps the bytes in the file into the address space of the process. It is a very efficient way to read data from a file, a disk read only occurs if the data is actually needed. When program execution jumps to a specific chunk of code, or the JIT compiler needs the IL for a method, a page fault is generated when the data hasn't been read yet. The operating system solves it by reading a chunk from the file. You only pay for code that actually runs.

Another major benefit is when the system is under pressure and too much RAM is needed to keep processes running. The memory manager chucks pages out of RAM to make room for the process that needs the CPU. These pages are normally written to the paging file. But that's unnecessary when they came from the EXE file. It can simply discard them and always get them back by re-reading the file.

You can probably see where this leads: loading pages from the EXE file can't work anymore when you popped out the disk. Windows notices this and puts up the dialog. This is a very low level error handling mechanism, you cannot trap it in the process itself. That couldn't work since that would require executing code in your program. Code that cannot be loaded from disk anymore.

You might be able to suppress the error by pinvoking SetErrorMode(). Not sure, never tried it. But that doesn't really solve anything, the next best thing that could happen is that Windows terminates the program with an obscure error. The only reasonable solution is either to let the user put the disk back, as requested by Windows, or to run an installer from your media so that a copy of the program is created on the hard drive.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
2

Use EDITBIN /SWAPRUN to tell Windows that your executable resides on a removable device. It'll copy it to the swap file before running it.

This is what you'd usually do for (e.g.) an installer. I'm not sure if this works if you depend on other DLLs, but I assume it does.

For other resources, you'd want to copy them to a temporary location as soon as possible during initialization.

Alternatively, you can call SetErrorMode to disable the message box and handle the error correctly.

Roger Lipscombe
  • 89,048
  • 55
  • 235
  • 380
0

You can modify your Program.cs like this:

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        try
        {
            Application.Run(new Form1());
        }
        catch (Exception ex)
        {
            // Display the exception to the end user.
        }
        finally
        {
            // Do your cleanup here.
        }
    }

This should catch all exceptions you do not catch otherwise in the application itself.

Pieter van Ginkel
  • 29,160
  • 8
  • 71
  • 111
  • use a finally instead of a catch block. finally blocks will be hit regardless of system and thread exception. – Femaref Oct 18 '10 at 10:59