Как в консольной программе поймать момент закрытия окна?
От: Ergo  
Дата: 08.06.10 21:48
Оценка:
Есть консольная программа, в ней нужно предпринять некоторые действия в момент, когда пользователь нажимает на крест в углу окна. Есть ли способ сделать это с помощью managed кода?
Re: AppDomain.CurrentDomain
От: BluntBlind  
Дата: 09.06.10 02:30
Оценка: -1
Подпишись на соответствующее событие.
Re[2]: AppDomain.CurrentDomain
От: Ergo  
Дата: 09.06.10 04:06
Оценка: 1 (1)
BB>Подпишись на соответствующее событие.

Попробовал, ни ProcessExit, ни DomainUnload не вызываются в этом случае. Вопрос все еще в силе.
Re: Как в консольной программе поймать момент закрытия окна?
От: Uzzy Россия  
Дата: 09.06.10 04:15
Оценка: 4 (1)
Здравствуйте, Ergo, Вы писали:

E>Есть консольная программа, в ней нужно предпринять некоторые действия в момент, когда пользователь нажимает на крест в углу окна. Есть ли способ сделать это с помощью managed кода?


http://stackoverflow.com/questions/1119841/net-console-application-exit-event
Re[3]: Простой пример:
От: BluntBlind  
Дата: 09.06.10 04:21
Оценка:
Здравствуйте, Ergo, Вы писали:
E>Попробовал, ни ProcessExit, ни DomainUnload не вызываются в этом случае. Вопрос все еще в силе.
class Program
{

    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.DomainUnload += new EventHandler(CurrentDomain_DomainUnload);
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Exit");
    }

    static void CurrentDomain_DomainUnload(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Unload");
    }
}

Output:

My Code' is enabled.
Exit
The program '[3356] ConsoleApplication1.vshost.exe: Managed' has exited with code 0 (0x0).

Не отработал только Unload
Re: Как в консольной программе поймать момент закрытия окна?
От: Jolly Roger  
Дата: 09.06.10 04:59
Оценка:
Здравствуйте, Ergo, Вы писали:

E>Есть консольная программа, в ней нужно предпринять некоторые действия в момент, когда пользователь нажимает на крест в углу окна. Есть ли способ сделать это с помощью managed кода?


Смотря что понимать под managed. Импорт WinApi функции это managed? Тогда импортировать SetConsoleCtrlHandler, зарегистрировать свой обработчик и реагировать в нём на CTRL_CLOSE_EVENT = 2.
"Нормальные герои всегда идут в обход!"
Re: Как в консольной программе поймать момент закрытия окна?
От: shakm Россия  
Дата: 09.06.10 04:59
Оценка: 2 (1)
Здравствуйте, Ergo, Вы писали:

E>Есть консольная программа, в ней нужно предпринять некоторые действия в момент, когда пользователь нажимает на крест в углу окна. Есть ли способ сделать это с помощью managed кода?


Я поступаю по другому — из своего виндовозного приложения я запускаю невидимый скрытый дочерний консольный процесс для консольного приложения, переопределяя его консольный ввод и вывод, а реальный вывод и воод осуществляю в обычном виндовозном окне.
А вот если вы хотите контролировать консольное окно... хм...
Вы бы уточнили вопрос... Когда нажимает на крест в углу, или когда программа пытается завершиться, или когда она уже точно завершается, или когда окно пытается закрыться, или оно уже точно закырвается и т.д. и т.п.? Все это разные события и позволяющие делать разные вещи.
Ведь на самом деле то самое окно существует, только оно не дотсупно для управления согласно самого принципа работы консольных приложений — изначально консольное приложение ни чего не должно знать о портировании приложения в оконной операционной системе, или в что-то типа DOS... Коненчо, если приложение скомпилировано под Win32 ане под DOS, то у вас есть возможность через Win32 API или другие инструменты добраться до окна, но оно управляется самой операционной системой, а не вашим приложением.
Например, вы можете попробовать повесить хук на это ваше окно, если сумеете его идентифицировать среди других консольных окон. А там можно плясать как угодно. Я не пробовал, но думаю сработает.
Надежнее всеж ето, что написал в начале. У меня это работает даже в сервисе — я посылаю bat-скрипты на другие компы компании, они там выполняются, а результат (консольный вывод) высылаю обратно. Так же рабоатет у меня удаленная консоль.
Re[2]: AppDomain.CurrentDomain
От: _FRED_ Черногория
Дата: 09.06.10 06:49
Оценка:
Здравствуйте, BluntBlind, Вы писали:

BB>Подпишись на соответствующее событие.


И как тогда решить проблему топикстартера? Как отличить, "когда пользователь нажимает на крест в углу окна" и когда программа всё сосчитала и сама завершилась?
Help will always be given at Hogwarts to those who ask for it.
Re[3]: AppDomain.CurrentDomain
От: BluntBlind  
Дата: 09.06.10 07:38
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>И как тогда решить проблему топикстартера? Как отличить, "когда пользователь нажимает на крест в углу окна" и когда программа всё сосчитала и сама завершилась?


Ну когда программа все сосчитала — это не проблема. А вот когда ее принудительно прихлопнули, можно через событие. Просто если нужно отслеживать именно нажатие кнопки "крестика", то тут нужно смотреть в сторону WinForms или WPF и делать свой гуй с консольным интерфейсом. Я просто предположил, что топикстартеру нужно отслеживать именно закрытие приложение вообще.
Re[3]: AppDomain.CurrentDomain
От: BluntBlind  
Дата: 09.06.10 07:41
Оценка:
Здравствуйте, Ergo, Вы писали:

E>Попробовал, ни ProcessExit, ни DomainUnload не вызываются в этом случае. Вопрос все еще в силе.


DomainUnload — в MSDN пишут: This event is never raised in the default application domain
Re[4]: AppDomain.CurrentDomain
От: shakm Россия  
Дата: 09.06.10 10:45
Оценка: 4 (1)
Здравствуйте, BluntBlind, Вы писали:

BB>Здравствуйте, Ergo, Вы писали:


E>>Попробовал, ни ProcessExit, ни DomainUnload не вызываются в этом случае. Вопрос все еще в силе.


BB>DomainUnload — в MSDN пишут: This event is never raised in the default application domain


Ни какие события не должны отрабатывать, если "крестануть" по консольному окну — это киляние процесса, а не нормальное закрытие окна.
Так что, если надо "крестик отследить" (разные соыбтия закрытия окна) — то это задача нетривиальная — мыслится что-то подобное — надо найти окно виртуальной дос-машины, отображающей ввод/вывод именно твоего консольного процесса и поставить хук на этот процесс, и, возможно, в этом хуке надо еще отфильтровывать сообщения именно твоего окна (т.к. возможно, что один процесс дос-машины может рисовать много окон, не знаком с этим)
Re[5]: AppDomain.CurrentDomain
От: Jolly Roger  
Дата: 09.06.10 11:10
Оценка:
Здравствуйте, shakm, Вы писали:

S>Ни какие события не должны отрабатывать, если "крестануть" по консольному окну — это киляние процесса, а не нормальное закрытие окна.

S>Так что, если надо "крестик отследить" (разные соыбтия закрытия окна) — то это задача нетривиальная

Тривиальная — см. здесь
Автор: Jolly Roger
Дата: 09.06.10
Стоит, вероятно, только добавить, что там будет не так уж много времени, всего несколько секунд.
"Нормальные герои всегда идут в обход!"
Re[5]: AppDomain.CurrentDomain
От: BluntBlind  
Дата: 09.06.10 11:13
Оценка:
Здравствуйте, shakm, Вы писали:

S>Ни какие события не должны отрабатывать, если "крестануть" по консольному окну — это киляние процесса, а не нормальное закрытие окна.

S>Так что, если надо "крестик отследить" (разные соыбтия закрытия окна) — то это задача нетривиальная — мыслится что-то подобное — надо найти окно виртуальной дос-машины, отображающей ввод/вывод именно твоего консольного процесса и поставить хук на этот процесс, и, возможно, в этом хуке надо еще отфильтровывать сообщения именно твоего окна (т.к. возможно, что один процесс дос-машины может рисовать много окон, не знаком с этим)

Да почему же? ProcessExit отрабатывает.
Автор: BluntBlind
Дата: 09.06.10


Я думаю, если загрузить еще домен и на его Unload подписаться, тоже все сработает. А то что у главного домена не работает, так оно можно понять, мы же грохаем процесс, а событие в нем отрабатывает
Re[6]: AppDomain.CurrentDomain
От: Jolly Roger  
Дата: 09.06.10 11:28
Оценка: 4 (1)
Здравствуйте, BluntBlind, Вы писали:

BB>Да почему же? ProcessExit отрабатывает.
Автор: BluntBlind
Дата: 09.06.10


Ваш пример некорректен, так как не соответствует условиям вопроса. Попробуйте вставить в конце Console.ReadKey и закройте консоль щелчком по кресту её окна.
"Нормальные герои всегда идут в обход!"
Re[6]: AppDomain.CurrentDomain
От: shakm Россия  
Дата: 09.06.10 11:40
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Здравствуйте, shakm, Вы писали:


S>>Ни какие события не должны отрабатывать, если "крестануть" по консольному окну — это киляние процесса, а не нормальное закрытие окна.

S>>Так что, если надо "крестик отследить" (разные соыбтия закрытия окна) — то это задача нетривиальная

JR>Тривиальная — см. здесь
Автор: Jolly Roger
Дата: 09.06.10
Стоит, вероятно, только добавить, что там будет не так уж много времени, всего несколько секунд.


А, ну да, отработало. Ушло 5 мин, чтобы проверить... А мы тут стебаемся ))


using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace TestConsoleClose
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("begin");
            Native.SetConsoleCtrlHandler(new Native.d_HandlerRoutine(HandlerRoutine), true);
            Console.WriteLine("end");
            Console.ReadKey();
        }

        static bool HandlerRoutine(uint dwCtrlType)
        {
            switch (dwCtrlType)
            {
                case /*CTRL_C_EVENT*/0:
                    Console.WriteLine("CTRL_C_EVENT. \tA CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.");
                    break;
                case /*CTRL_BREAK_EVENT*/1:
                    Console.WriteLine("CTRL_BREAK_EVENT. \tA CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent.");
                    break;
                case /*CTRL_CLOSE_EVENT*/2:
                    Console.WriteLine("CTRL_CLOSE_EVENT. \tA signal that the system sends to all processes attached to a console when the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager).");
                    break;
                case /*CTRL_LOGOFF_EVENT*/5:
                    Console.WriteLine("CTRL_LOGOFF_EVENT. \tA signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made.\r\nNote that this signal is received only by services. Interactive applications are terminated at logoff, so they are not present when the system sends this signal.");
                    break;
                case /*CTRL_SHUTDOWN_EVENT*/6:
                    Console.WriteLine("CTRL_SHUTDOWN_EVENT. \tA signal that the system sends when the system is shutting down. Interactive applications are not present by the time the system sends this signal, therefore it can be received only be services in this situation. Services also have their own notification mechanism for shutdown events. For more information, see Handler.\r\nThis signal can also be generated by an application using GenerateConsoleCtrlEvent.");
                    break;
                default:
                    Console.WriteLine("??????????. \tUnknown cotrol type:" + dwCtrlType.ToString());
                    break;
            }
            Console.WriteLine("...ща закроемся и усе...");
            //немного зависнем, чтобы показать консольный вывод
            int count = 10;
            while (count-- > 0)
            {
                Thread.Sleep(500);
                Console.Write(".");
            }
            //возвращаем false - чтобы все работало так, как предусмотрено
            return false;
        }
    }

    public static class Native
    {
        public delegate bool d_HandlerRoutine(uint dwCtrlType);
        [DllImport("Kernel32.dll")]
        public static extern bool SetConsoleCtrlHandler(d_HandlerRoutine HandlerRoutine, bool Add);
    }
}
Re[7]: Понял
От: BluntBlind  
Дата: 10.06.10 02:47
Оценка:
Здравствуйте, Jolly Roger, Вы писали:
JR>Ваш пример некорректен, так как не соответствует условиям вопроса. Попробуйте вставить в конце Console.ReadKey и закройте консоль щелчком по кресту её окна.

Да, согласен, был невнимателен, прошу прощения.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.