Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как перехватить закрытие консольного приложение 
:(
    Опции темы
semibug
Дата 30.5.2009, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Каким образом лучше организовать перехват события закрытия консольного окна пользователем (клик по крестику).

PM   Вверх
azesmcar
Дата 30.5.2009, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Код

void atexit_handler()
{
}

int main()
{
    atexit(atexit_handler);
    //...
}

PM   Вверх
semibug
Дата 30.5.2009, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Срабатывает при нормальном завершении приложения (окончании функции main), 
если же закрывать мышкой по крестику - не входит в atexit_handler.
Сама консоль создаётся в оконном приложении (VS2005 C++) сразу после запуска.
Попробовал создать глобальный объект, с бряком в деструкторе. При нормальном завершении программы деструктор отрабатывает как положено, при закрытии по крестику нет.
PM   Вверх
azesmcar
Дата 30.5.2009, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  30.5.2009,  16:18 Найти цитируемый пост)
если же закрывать мышкой по крестику - не входит в atexit_handler.

Смотря как закрывается, если terminate - то не войдет, если приложение нормально завершается - тогда обработчки сработает.
PM   Вверх
semibug
Дата 30.5.2009, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Цитата(azesmcar @  30.5.2009,  16:21 Найти цитируемый пост)
Смотря как закрывается, если terminate - то не войдет, если приложение нормально завершается - тогда обработчки сработает. 

Дело в том, что специально я не обрабатываю никак закрытие консольного окна по клику на крестик.
Программа просто terminate-тится. По Alt-F4 ничего не происходит.
Вот и думаю, где же вставить обработчик, для события, когда юзер закроет окошко мышью (сбрасываю некоторые данные на диск перед завершением проги).

PM   Вверх
azesmcar
Дата 30.5.2009, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  30.5.2009,  16:49 Найти цитируемый пост)
Программа просто terminate-тится. 

terminate не перехватывается из самой программы. Если ваша консоль зависла и не может быть нормально закрыта - тогда конечно atexit не поможет, в остальных случаях, если программу не терминейтят, atexit срабатывает.
PM   Вверх
semibug
Дата 30.5.2009, 17:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Цитата(azesmcar @  30.5.2009,  17:05 Найти цитируемый пост)
terminate не перехватывается из самой программы. Если ваша консоль зависла и не может быть нормально закрыта - тогда конечно atexit не поможет, в остальных случаях, если программу не терминейтят, atexit срабатывает. 

Ну тогда скажем так: как отучить Windows терминэйтить программы без предупреждения по нажатию крестика.
( при этом консоль не зависла, никаких предупреждений о принудительном закрытии процесса винда не показывает)
PM   Вверх
azesmcar
Дата 30.5.2009, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



проверьте этот код
Код

#include <windows.h>
#include <iostream>

void atexit_handler()
{
    MessageBoxA(0, "G", "B", MB_OK);
}

int main()
{
    atexit(atexit_handler);
    while (true)
    {
        Sleep(1000);
    }
    return 0;
}

У меня работает.

Это сообщение отредактировал(а) azesmcar - 30.5.2009, 17:47
PM   Вверх
semibug
Дата 30.5.2009, 18:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Цитата(azesmcar @  30.5.2009,  17:45 Найти цитируемый пост)
У меня работает.

Попробуйте с Runtime Library Multi-threaded Debug (not DLL)
PM   Вверх
azesmcar
Дата 30.5.2009, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  30.5.2009,  18:29 Найти цитируемый пост)
Попробуйте с Runtime Library Multi-threaded Debug (not DLL) 

Ну...работает..вы проверили этот код?
вот что говорит MSDN по этой функции. 
Цитата

The atexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to atexit create a register of functions that are executed in last-in, first-out (LIFO) order. The functions passed to atexit cannot take parameters. atexit and _onexit use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.



Это сообщение отредактировал(а) azesmcar - 30.5.2009, 19:10
PM   Вверх
semibug
Дата 30.5.2009, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



c Runtime Library Multi-threaded Debug atexit не срабатывает. (с Runtime Library Multi-threaded Debug DLL) работает нормально. Visual Studio 2005.
PM   Вверх
azesmcar
Дата 30.5.2009, 19:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  30.5.2009,  19:17 Найти цитируемый пост)
c Runtime Library Multi-threaded Debug atexit не срабатывает. (с Runtime Library Multi-threaded Debug DLL) работает нормально. Visual Studio 2005. 

Не нашел отличий.

Добавлено через 1 минуту и 40 секунд
У меня так и стоит (VS2008) и работает. Вот опции проекта.
Цитата

/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt


Добавлено через 2 минуты и 5 секунд
Скиньте проект куда нибудь, гляну.
PM   Вверх
semibug
Дата 30.5.2009, 19:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Странно. В моем случае стоит переключить на Runtime Library Multi-threaded Debug как перестаёт работать.
Попробую собрать проект на другой системе..



Это сообщение отредактировал(а) semibug - 30.5.2009, 19:35

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  terminate.rar 4,07 Kb
PM   Вверх
azesmcar
Дата 30.5.2009, 20:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



semibug

Проверил, действительно не работает.
Создал новый проект Win32 с дефолт настройками, проверил - работает. Я не знаю что вы там в настройках проекта изменили. Надо проверить, но по дефолту стоит Runtime Library Multi-threaded Debug DLL и работает..проверьте, я посмотрю разницу в настройках. Интересно в чем дело.
PM   Вверх
semibug
Дата 30.5.2009, 20:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



azesmcar
Так же создал новый проект,
из настроек поменял только Runtime Library (стояло DLL, поставил без ). После чего перестал срабатывать atexit (до изменения работал).
Под перестал работать имею ввиду что не срабатывает, когда окно закрываем щелчком по крестику.

Это сообщение отредактировал(а) semibug - 30.5.2009, 20:25
PM   Вверх
azesmcar
Дата 30.5.2009, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



semibug

я и не замечал что там изменено..вроде то же самое, DLL слово маленькое, практически незаметное smile так вы CRT линкуете.
А зачем это надо если не секрет?

Добавлено через 1 минуту и 20 секунд
MSDN по этому поводу говорит вот что
Цитата

Using the statically linked CRT implies that any state information saved by the C runtime library will be local to that instance of the CRT. For example, if you use strtok, _strtok_l, wcstok, _wcstok_l, _mbstok, _mbstok_l when using a statically linked CRT, the position of the strtok parser is unrelated to the strtok state used in code in the same process (but in a different DLL or EXE) that is linked to another instance of the static CRT. In contrast, the dynamically linked CRT shares state for all code within a process that is dynamically linked to the CRT. This concern does not apply if you use the new more secure versions of these functions; for example, strtok_s does not have this problem.

Because a DLL built by linking to a static CRT will have its own CRT state, it is not recommended to link statically to the CRT in a DLL unless the consequences of this are specifically desired and understood. For example, if you call _set_se_translator in an executable that loads the DLL linked to its own static CRT, any hardware exceptions generated by the code in the DLL will not be caught by the translator, but hardware exceptions generated by code in the main executable will be caught.

при статической линковке может и не сработать. Тут C++ не виноват..зачем статически линковать CRT?
PM   Вверх
jonie
Дата 30.5.2009, 20:41 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 7
Всего: 118



т.к. винда то читайте про SetConsoleCtrlHandler и SetConsoleMode наверно...


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
azesmcar
Дата 30.5.2009, 20:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



есть еще microsoft extension _onexit, но я сомневаюсь что он сработает. При статической линковке надо подумать какие могут возникать проблемы и от чего, насчет atexit, _onexit MSDN ничего не говорит, но какие-то проблемы он предполагает.

Добавлено через 10 секунд
http://msdn.microsoft.com/en-us/library/abx4dbyh(VS.80).aspx
PM   Вверх
azesmcar
Дата 30.5.2009, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(jonie @  30.5.2009,  20:41 Найти цитируемый пост)
т.к. винда то читайте про SetConsoleCtrlHandler и SetConsoleMode наверно... 

кстати да! Это идея

semibug вот ваш код.
Код

BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
    MessageBoxA(0, "handler", "test", MB_OK);
    return FALSE;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    AllocConsole();
    SetConsoleCtrlHandler(HandlerRoutine, true);
    FILE *stream;
    freopen_s( &stream, "CONOUT$", "wt", stdout );
    printf( "just terminate trick\n" );

    while ( 1 )
    {
        Sleep( 10 );
    }

    return 0;
}

PM   Вверх
semibug
Дата 30.5.2009, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Цитата(azesmcar @  30.5.2009,  20:33 Найти цитируемый пост)
так вы CRT линкуете.
А зачем это надо если не секрет?

В проекте, где наткнулся на эту особенность уже и не вспомню кто и когда переключил тип линковки CRT (надо ещё в svn поковыряться). Для нового проекта - чисто из академических соображений переключил, ибо в дефолтовых условиях все работало ).


Цитата(jonie @  30.5.2009,  20:41 Найти цитируемый пост)
т.к. винда то читайте про SetConsoleCtrlHandler

Преогромнейшее спасибо. Работает.

PM   Вверх
semibug
Дата 31.5.2009, 08:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



В выше приведенном способе c SetConsoleCtrlHandler,  Windows все равно убивает процесс через 5 секунд после нажатия на крестик (если вернуть TRUE в обработчике) . В принципе этого достаточно чтобы сохранить данные приложения на диск (не 100 процентов случаев) . Но на всякий случай отключил совсем действия крестика:

    hm = GetSystemMenu( hWnd, FALSE );
    DeleteMenu( hm, SC_CLOSE , MF_BYCOMMAND );

где hWnd- хэндл окна консольного приложения.

PM   Вверх
azesmcar
Дата 31.5.2009, 10:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  31.5.2009,  08:19 Найти цитируемый пост)
В выше приведенном способе c SetConsoleCtrlHandler,  Windows все равно убивает процесс через 5 секунд после нажатия на крестик (если вернуть TRUE в обработчике) . В принципе этого достаточно чтобы сохранить данные приложения на диск (не 100 процентов случаев) . Но на всякий случай отключил совсем действия крестика:

    hm = GetSystemMenu( hWnd, FALSE );
    DeleteMenu( hm, SC_CLOSE , MF_BYCOMMAND );

где hWnd- хэндл окна консольного приложения.

msdn почитайте.
Там же написано.
Если вы сами обрабатываете команду - возвращайте TRUE, если нет - FALSE чтобы виндоуз передал команду следующему обработчику.
Обработать команду не значит удалить свое меню а значит завешить свою программу так как указано в параметре. Просто делайте то что вам надо и всегда возвращайте FALSE.
PM   Вверх
semibug
Дата 31.5.2009, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



azesmcar,
    Дело в том, что если я не успеваю выполнить необходимые действия, Windows убивает процесс  не дожидаясь завершения обработчика (либо выводит табличку о том, что прога зависла и предложит убить её).
А отключение крестика, конечно не в обработчик закрытия вставил. А сразу после создания консоли. При этом необходимость обрабатывать закрытие окна отпадает.

Это сообщение отредактировал(а) semibug - 31.5.2009, 17:18
PM   Вверх
azesmcar
Дата 31.5.2009, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Цитата(semibug @  31.5.2009,  17:15 Найти цитируемый пост)
azesmcar,
    Дело в том, что если я не успеваю выполнить необходимые действия, Windows убивает процесс  не дожидаясь завершения обработчика (либо выводит табличку о том, что прога зависла и предложит убить её). Причем не зависимо от того, что вернет обработчик (TRUE или FALSE).

А отключение крестика, конечно не в обработчик закрытия вставил. А сразу после создания консоли. При этом необходимость обрабатывать закрытие окна отпадает.

Да..если долго думать виндоуз подумает что ваше приложение зависло..а чего вы так долго делаете то в обработчике?
PM   Вверх
semibug
Дата 31.5.2009, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 323
Регистрация: 27.3.2009

Репутация: нет
Всего: нет



Цитата(azesmcar @  31.5.2009,  17:18 Найти цитируемый пост)
Да..если долго думать виндоуз подумает что ваше приложение зависло..а чего вы так долго делаете то в обработчике? 

Да в общем то ничего особенного, сохраняю некоторые данные на диск.
Это конечно много времени не занимает, но всяко разно. У меня, например, подключен к компу внешний диск WD MyBook, так он, если его не трогать отключается, а при попытки доступа к нему разгоняется долго. Хотелось однозначно завершить операцию. Рассматривал вариант с запуском небольшого отдельного процесса, который после смерти основного приложения займется работой по сохранению, но, сами понимаете, выглядит некультурно. Поэтому и остановился на полном запрещении отрубать прогу крестиком (для нормальнго завершения предусмотрены штатные средства в самом приложении).

PM   Вверх
azesmcar
Дата 31.5.2009, 17:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



semibug

Вам надо подумать в сторону отмены закрытия приложения и закрытся самому как только все завершите
Еще как вариант, просто закрыть консоль но не сам процесс. 

Это сообщение отредактировал(а) azesmcar - 31.5.2009, 17:45
PM   Вверх
GremlinProg
Дата 31.5.2009, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(semibug @  31.5.2009,  19:15 Найти цитируемый пост)
Дело в том, что если я не успеваю выполнить необходимые действия, Windows убивает процесс  не дожидаясь завершения обработчика (либо выводит табличку о том, что прога зависла и предложит убить её).

попробуй поиграться с SetProcessShutdownParameters и флагом SHUTDOWN_NORETRY
окошко показываться не должно, а вот на счет самоотмирания процесса, тут можно с первым параметром поработать
тогда и Close затенять не придется (прикрыт процесс может быть не обязательно с кнопки)


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.1168 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.