Насколько я понимаю, Application.Exit(), Application.ExitThread(), this.Close() посылают сообщение окнну, что нужно закрыть, выйти и т.д. Но это сообщение ложится в очередь и не выполнится, по крайней мере, пока не закончится выполнение текущей функции. Действительно, как было сказано, MessageBox.Show() не дает правильно обработать это сообщение (выхода), а return выбрасывает из функции до выполнения MessageBox.Show() и все завершается "как по маслу".