Неудачные решения в Delphi
От: Гумеров Максим Маратович  
Дата: 07.03.13 13:57
Оценка: 85 (4) -2
Статья:
Неудачные решения в Delphi
Автор(ы): Гумеров Максим Маратович
Дата: 07.08.2012
После приобретения прав на продукт Delphi компанией Embarcadero Technologies, примерно с 2009 года предпринимаются попытки актуализировать язык, внедрив в него возможности, недостаток которых стал ощущаться особенно сильно. Вероятно, эта совокупность нововведений укрепит позиции Delphi в качестве средства разработки, выбираемого для запуска новых проектов. На основе своего опыта работы с версиями Delphi для Win32 от Borland Delphi 3.0 до Embarcadero Delphi XE автор обозначает некоторые специфичные для Delphi трудности, которые могут встретиться при разработке новых проектов, и примеры решений, которых по определенным причинам следует избегать, и открывает исследование с целью рекомендовать обходные пути и более эффективные решения.


Авторы:
Гумеров Максим Маратович

Аннотация:
После приобретения прав на продукт Delphi компанией Embarcadero Technologies, примерно с 2009 года предпринимаются попытки актуализировать язык, внедрив в него возможности, недостаток которых стал ощущаться особенно сильно. Вероятно, эта совокупность нововведений укрепит позиции Delphi в качестве средства разработки, выбираемого для запуска новых проектов. На основе своего опыта работы с версиями Delphi для Win32 от Borland Delphi 3.0 до Embarcadero Delphi XE автор обозначает некоторые специфичные для Delphi трудности, которые могут встретиться при разработке новых проектов, и примеры решений, которых по определенным причинам следует избегать, и открывает исследование с целью рекомендовать обходные пути и более эффективные решения.
Re: Неудачные решения в Delphi
От: hattab  
Дата: 07.03.13 16:24
Оценка:
Здравствуйте, Гумеров Максим Маратович, Вы писали:

Неверная предпосылка:

Простой пример: все интерфейсы наследуют IUnknown, значит, если класс реализует два разных интерфейса I1 и I2, ни один из которых не является потомком другого, то и таблица методов для I1, и таблица для I2 начинаются с таблицы методов IUnknown.


Неверный вывод:

Теперь, если есть переменные unk: IUnknown, ip1: I1, ip2: I2, то присваивания unk:=ip1 и unk:=ip2 дадут в unk разные указатели. А должны, согласно требованиям COM, давать один и тот же!


Автору читать Inside COM, там все понятно, с картинками (стр. 39, PDF). Дальше читать не стал, раз с самого начала такие перлы.
avalon 1.0rc3 build 432, zlib 1.2.5
Re: Неудачные решения в Delphi
От: baranovda Российская Империя  
Дата: 07.03.13 18:10
Оценка:
Здравствуйте, Гумеров Максим Маратович, Вы писали:

Проблема с отладчиком по крайней мере в D6/7 — если я и автор имеют в виду одно и то же — решается http://exodus.googlecode.com/svn-history/r5062/branches/5.4.0/trunk/jopl/NTDLLFixup.pas
Re: Неудачные решения в Delphi
От: butcha Россия  
Дата: 09.03.13 01:36
Оценка:
Здравствуйте, Гумеров Максим Маратович, Вы писали:

ГММ>Статья:

ГММ>Неудачные решения в Delphi
Автор(ы): Гумеров Максим Маратович
Дата: 07.08.2012
После приобретения прав на продукт Delphi компанией Embarcadero Technologies, примерно с 2009 года предпринимаются попытки актуализировать язык, внедрив в него возможности, недостаток которых стал ощущаться особенно сильно. Вероятно, эта совокупность нововведений укрепит позиции Delphi в качестве средства разработки, выбираемого для запуска новых проектов. На основе своего опыта работы с версиями Delphi для Win32 от Borland Delphi 3.0 до Embarcadero Delphi XE автор обозначает некоторые специфичные для Delphi трудности, которые могут встретиться при разработке новых проектов, и примеры решений, которых по определенным причинам следует избегать, и открывает исследование с целью рекомендовать обходные пути и более эффективные решения.


По моему это неудачный опыт общения с Delphi. Абзац про вредность "ProcessMessages" вообще шедевр:

Точное предназначение этой функции неясно. Косвенно выводы сделать можно из ее описания: «In lengthy operations, calling ProcessMessages periodically allows the application to respond to paint and other messages» ...


Наверное создатели VCL всё же полагали что пользователям (программистам Windows!) знакомы понятия "Messages, Message Queues, Message Loop и Window Procedure" и главный поток. И сделали простое решение, позволяющее не выделять долгие операции в отдельный поток, а выполнять в основном и давать возможность среагировать к примеру на кнопку Cancel или отрисовывать прогресс-бар

или:

...пользователь может, пока выборка сообщений продолжается, снова войти в меню и запустить какую-то другую операцию или воспользоваться другой «горячей клавишей». Вплоть до того, чтобы скомандовать выход из программы – пока запустившая ProcessMessages операция еще не закончилась.


ну если уж пользователь(программист!) умудрится так напрограмировать, то ему пожалуй и кухонный нож доверять не стоит, а то он начнет вместо резки хлеба резать себе живот, доставать печень и интересоваться как устроен мочевой пузырь.
Re[2]: Неудачные решения в Delphi
От: wildwind Россия  
Дата: 11.03.13 13:14
Оценка:
Здравствуйте, hattab, Вы писали:

H>Неверная предпосылка:

H>

Простой пример: все интерфейсы наследуют IUnknown, значит, если класс реализует два разных интерфейса I1 и I2, ни один из которых не является потомком другого, то и таблица методов для I1, и таблица для I2 начинаются с таблицы методов IUnknown.


H>Неверный вывод:

H>

Теперь, если есть переменные unk: IUnknown, ip1: I1, ip2: I2, то присваивания unk:=ip1 и unk:=ip2 дадут в unk разные указатели. А должны, согласно требованиям COM, давать один и тот же!


Что конкретно неверно?

H>Автору читать Inside COM, там все понятно, с картинками (стр. 39, PDF). Дальше читать не стал, раз с самого начала такие перлы.

Ты всерьез полагаешь, что автор не читал "Inside COM"?
Re[3]: Неудачные решения в Delphi
От: hattab  
Дата: 11.03.13 15:11
Оценка:
Здравствуйте, wildwind, Вы писали:

w> H>Неверная предпосылка:

w> H>

Простой пример: все интерфейсы наследуют IUnknown, значит, если класс реализует два разных интерфейса I1 и I2, ни один из которых не является потомком другого, то и таблица методов для I1, и таблица для I2 начинаются с таблицы методов IUnknown.


w> H>Неверный вывод:

w> H>

Теперь, если есть переменные unk: IUnknown, ip1: I1, ip2: I2, то присваивания unk:=ip1 и unk:=ip2 дадут в unk разные указатели. А должны, согласно требованиям COM, давать один и тот же!


w> Что конкретно неверно?


То и неверно, что vtbl любого COM-интерфейса хоть и начинается с IUnknown, но у разных интерфейсов (одного класса, разумеется) она может быть расположена в разных адресах. И это ни как не противоречит COM т.к. по QueryInterface(IUnknown...) отдаваться будет всегда один и тот же адрес. Учите матчасть, господа.

w> H>Автору читать Inside COM, там все понятно, с картинками (стр. 39, PDF). Дальше читать не стал, раз с самого начала такие перлы.


w> Ты всерьез полагаешь, что автор не читал "Inside COM"?


Судя по тому что пишет, да не читал. А что я должен был увидеть по тому, что ты показал? Раздвоение ников?
avalon 1.0rc3 build 432, zlib 1.2.5
Re[4]: Неудачные решения в Delphi
От: wildwind Россия  
Дата: 11.03.13 16:08
Оценка:
Здравствуйте, hattab, Вы писали:

H>То и неверно, что vtbl любого COM-интерфейса хоть и начинается с IUnknown, но у разных интерфейсов (одного класса, разумеется) она может быть расположена в разных адресах. И это ни как не противоречит COM т.к. по QueryInterface(IUnknown...) отдаваться будет всегда один и тот же адрес.


Автор пишет об интерфейсах, полученных через присваивание, а не через QueryInterface. И приводит это как пример недоработки в данной реализации. Ты не согласен?
Re[5]: Неудачные решения в Delphi
От: hattab  
Дата: 11.03.13 18:11
Оценка:
Здравствуйте, wildwind, Вы писали:

w> Автор пишет об интерфейсах, полученных через присваивание, а не через QueryInterface. И приводит это как пример недоработки в данной реализации. Ты не согласен?


Конечно не согласен. Он говорит о присваивании и считает, что оно должно быть эквивалентно вызову QueryInterface. А потом еще перл о том, что большинство подпрограмм рассчитывают именно на такое поведение. Что, якобы, в InterfaceList сохранили интерфейс, а найти нам нужно объект. Что за бред? Может просто освоить средства предлагаемые языком? Есть оператор As, например...
avalon 1.0rc3 build 432, zlib 1.2.5
Re: Неудачные решения в Delphi
От: Jack128  
Дата: 11.03.13 20:26
Оценка:
Здравствуйте, Гумеров Максим Маратович, Вы писали:

наиболее эпичен ИМХО раздел "Неудачное решение: генерализованная система событий и подписки".
Сначала описывается абстракция Publish–subscribe, указывается, что наивная её реализация через интерфейсы геморойна и неудобна. И делается вывод: наиболее удобны встроенные в язык события, как в Дельфи/С#.
У мя вопрос, где здесь неудачные решения в Delphi?
Re: Неудачные решения в Delphi
От: Chaa  
Дата: 12.03.13 03:20
Оценка:
У Delphi конечно же есть проблемы, но совсем не те, что описаны в статье.

Реальные проблемы находятся в плохой поддержке, неработающем Quality Central, медленном исправлении ошибок, неясных перспективах развития.

Например, я написал об ошибке компилятора в Quality Central: Compiler bug when using generics and forward declaration in Delphi XE2.
Через два месяца для ошибки поставили статус Fixed. Но никаких обновлений для XE2 больше на выходило и уже не будет, чтобы получить компилятор с исправленной ошибкой нужно купить версию XE3.
Re[6]: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 03:50
Оценка:
Здравствуйте, hattab, Вы писали:

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

w>> Автор пишет об интерфейсах, полученных через присваивание, а не через QueryInterface. И приводит это как пример недоработки в данной реализации. Ты не согласен?
H>Конечно не согласен. Он говорит о присваивании и считает, что оно должно быть эквивалентно вызову QueryInterface.
Да, я говорю о том, что присваивание с изменением интерфейса должно работать эквивалентно QueryInterface. Точнее, не то чтобы "должно" — скорее, я как раз предупреждаю о том, что оно так не работает, а важнее тут не сам этот факт, а его следствие — момент про сравнение указателей.

H>А потом еще перл о том, что большинство подпрограмм рассчитывают именно на такое поведение. Что, якобы, в InterfaceList сохранили интерфейс, а найти нам нужно объект.

Такого там не было. Была речь о том, что сохранили один указатель на интерфейс-предок, а найти пытаются другой интерфейс-предок, когда оба взяты от одного и того же интерфейса-потомка. А получается такая ситуация как раз из-за неравенства этих указателей.
H>Что за бред? Может просто освоить средства предлагаемые языком? Есть оператор As, например...
А что, я не пишу ничего про As? Как раз и отметил, что один из выходов — понатыкать везде As.

Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re[2]: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 03:54
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, Гумеров Максим Маратович, Вы писали:


B>Проблема с отладчиком по крайней мере в D6/7 — если я и автор имеют в виду одно и то же — решается http://exodus.googlecode.com/svn-history/r5062/branches/5.4.0/trunk/jopl/NTDLLFixup.pas

Спасибо, но это не та проблема. Отладчик не останавливается на вызове отладочного прерывания, а умирает с непрекращающимися (если не повезет) сообщениями об External Error.

Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re[2]: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 04:02
Оценка:
Здравствуйте, butcha, Вы писали:

B>Здравствуйте, Гумеров Максим Маратович, Вы писали:


ГММ>>Статья:

ГММ>>Неудачные решения в Delphi
Автор(ы): Гумеров Максим Маратович
Дата: 07.08.2012
После приобретения прав на продукт Delphi компанией Embarcadero Technologies, примерно с 2009 года предпринимаются попытки актуализировать язык, внедрив в него возможности, недостаток которых стал ощущаться особенно сильно. Вероятно, эта совокупность нововведений укрепит позиции Delphi в качестве средства разработки, выбираемого для запуска новых проектов. На основе своего опыта работы с версиями Delphi для Win32 от Borland Delphi 3.0 до Embarcadero Delphi XE автор обозначает некоторые специфичные для Delphi трудности, которые могут встретиться при разработке новых проектов, и примеры решений, которых по определенным причинам следует избегать, и открывает исследование с целью рекомендовать обходные пути и более эффективные решения.

B>По моему это неудачный опыт общения с Delphi.
Одно от другого отстоит недалеко. Приведенные мной проблемы — это проблемы вполне реально коммерческого проекта. Вряд ли все его участники — идиоты.

B> Абзац про вредность "ProcessMessages" вообще шедевр:

B>

B>Точное предназначение этой функции неясно. Косвенно выводы сделать можно из ее описания: «In lengthy operations, calling ProcessMessages periodically allows the application to respond to paint and other messages» ...

B>Наверное создатели VCL всё же полагали что пользователям (программистам Windows!) знакомы понятия "Messages, Message Queues, Message Loop и Window Procedure" и главный поток. И сделали простое решение, позволяющее не выделять долгие операции в отдельный поток, а выполнять в основном и давать возможность среагировать к примеру на кнопку Cancel или отрисовывать прогресс-бар
И что же следует из ваших слов? Кто гарантирует, что реакция будет именно на кнопку Cancel, а никакие другие, нежелательные нам на данном этапе, действия пользователь осуществить не сможет?

B>

B>...пользователь может, пока выборка сообщений продолжается, снова войти в меню и запустить какую-то другую операцию или воспользоваться другой «горячей клавишей». Вплоть до того, чтобы скомандовать выход из программы – пока запустившая ProcessMessages операция еще не закончилась.

B>ну если уж пользователь(программист!) умудрится так напрограмировать, то ему пожалуй и кухонный нож доверять не стоит, а то он начнет вместо резки хлеба резать себе живот, доставать печень и интересоваться как устроен мочевой пузырь.
Это с вашей стороны всего лишь популизм. Или укажите конкретный способ использования ProcessMessages, гарантирующий отсутствие подобных ошибок, — люди вам спасибо скажут, — или согласимся на том, что есть-таки опасность получить и такой эффект, если пользоваться ProcessMessages.
Специалист — это варвар, невежество которого не всесторонне :)
Re[2]: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 04:11
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Здравствуйте, Гумеров Максим Маратович, Вы писали:


J>наиболее эпичен ИМХО раздел "Неудачное решение: генерализованная система событий и подписки".

J>Сначала описывается абстракция Publish–subscribe, указывается, что наивная её реализация через интерфейсы геморойна и неудобна. И делается вывод: наиболее удобны встроенные в язык события, как в Дельфи/С#.
J>У мя вопрос, где здесь неудачные решения в Delphi?
В этом разделе, с одной стороны, описано неудачное решение (никто не говорил, что оно обязано быть проблемой Delphi), с другой, относительно него делается вывод, имеющий прямое отношение к Delphi.

Цель была не в том, чтобы раскритиковать Delphi, а в том, чтобы люди прочитали о различных граблях, для кого-то более очевидных, для кого-то менее. Так что можно рассматривать этот раздел как бонус к остальному материалу, который уже связан со спецификой Delphi.

Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re[2]: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 04:17
Оценка:
Здравствуйте, Chaa, Вы писали:

C>У Delphi конечно же есть проблемы, но совсем не те, что описаны в статье.

C>Реальные проблемы находятся в плохой поддержке, неработающем Quality Central, медленном исправлении ошибок, неясных перспективах развития.
Конечно, вы говорите о вещах более фундаментальных и необоримых, но на них и жаловаться бесполезно, и предостерегать смысла нет. А о том, с чем столкнулся я — смысл есть.

C>Например, я написал об ошибке компилятора в Quality Central: Compiler bug when using generics and forward declaration in Delphi XE2.

C>Через два месяца для ошибки поставили статус Fixed. Но никаких обновлений для XE2 больше на выходило и уже не будет, чтобы получить компилятор с исправленной ошибкой нужно купить версию XE3.
Совершенно аналогично, у меня там то ли пять, то ли семь багрепортов, два из них просто тихо спустили на тормозах и на запросы не отвечают, а по остальным написали, дескать, в новых версиях это исправлено. Особенно весело было, когда переход на новые версии означал вдобавок проход по всему проекту для контроля, что переход на уникодные string/char будет сделан правильно.

Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re: Неудачные решения в Delphi
От: Slicer [Mirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 12.03.13 04:30
Оценка: +1
Если кто-то уверен, что он-то уж точно никогда подобных глупостей не совершит — ну и прекрасно. Статья не ругает недостатки Делфи — статья суммирует часть отрицательного опыта разработки, связанного с определенными особенностями (и недостатками) Делфи. Не пригодится одним — пригодится другим.

Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re: Неудачные решения в Delphi
От: Chaa  
Дата: 12.03.13 04:35
Оценка:
ГММ>Статья:
ГММ>Неудачные решения в Delphi
Автор(ы): Гумеров Максим Маратович
Дата: 07.08.2012
После приобретения прав на продукт Delphi компанией Embarcadero Technologies, примерно с 2009 года предпринимаются попытки актуализировать язык, внедрив в него возможности, недостаток которых стал ощущаться особенно сильно. Вероятно, эта совокупность нововведений укрепит позиции Delphi в качестве средства разработки, выбираемого для запуска новых проектов. На основе своего опыта работы с версиями Delphi для Win32 от Borland Delphi 3.0 до Embarcadero Delphi XE автор обозначает некоторые специфичные для Delphi трудности, которые могут встретиться при разработке новых проектов, и примеры решений, которых по определенным причинам следует избегать, и открывает исследование с целью рекомендовать обходные пути и более эффективные решения.


Зря вы назвали статью "Неудачные решения в Delphi".
Это просто особенности, которые нужно знать. Там таких еще очень много, как и в любой сложной среде разработки. Например выравнивание полей записей: Запись в качестве ключа TDictionary.

ГММ>ProcessMessages

Лучше не использовать совсем. А если нужна кнопка "Отмена" и прогресс выполнения, то есть IProgressDialog. Тоже конечно без проблем не обойтись, но решения описаны: The progress dialog box object.
Кстати, сообщения WM_PAINT теперь и COM-рантайм в новых версиях Windows присылает: WM_PAINT во время ожидания вызова COM-сервера.
Re[7]: Неудачные решения в Delphi
От: hattab  
Дата: 12.03.13 06:23
Оценка:
Здравствуйте, Slicer [Mirkwood], Вы писали:

SM> H>Конечно не согласен. Он говорит о присваивании и считает, что оно должно быть эквивалентно вызову QueryInterface.


SM> Да, я говорю о том, что присваивание с изменением интерфейса должно работать эквивалентно QueryInterface. Точнее, не то чтобы "должно" — скорее, я как раз предупреждаю о том, что оно так не работает, а важнее тут не сам этот факт, а его следствие — момент про сравнение указателей.


А нет никакого изменения интерфейса т.к. любой интерфейс есть надмножество IUnknown. Такое поведение абсолютно корректно и ожидаемо. Тут, как раз, все выглядит логичным и не делается лишней работы там, где она не нужна т.к. если пользователю нужен конкретный интерфейс его можно получить через QueryInterface или оператор приведения As.

SM> H>А потом еще перл о том, что большинство подпрограмм рассчитывают именно на такое поведение. Что, якобы, в InterfaceList сохранили интерфейс, а найти нам нужно объект.


SM> Такого там не было. Была речь о том, что сохранили один указатель на интерфейс-предок, а найти пытаются другой интерфейс-предок, когда оба взяты от одного и того же интерфейса-потомка. А получается такая ситуация как раз из-за неравенства этих указателей.


Еще как было:

Например, поиск элемента в IInterfaceList принимает IUnknown и сравнивает его с уже имеющимися в массиве IUnknown. С учетом усечения возможна ситуация, когда в массив поместили интерфейс ip1, усеченный до IUnknown, а потом пытаются искать тот же самый объект, и тоже через IUnknown, но уже полученный из ip2, – и будет сделан вывод, что объекта в массиве нет.


SM> H>Что за бред? Может просто освоить средства предлагаемые языком? Есть оператор As, например...


SM> А что, я не пишу ничего про As? Как раз и отметил, что один из выходов — понатыкать везде As.


Только про As там говорится в другом контексте, а именно, как средстве борьбы с преждевременным освобождением объекта. Хотя это не неудачное решение, это особенность необходимая для реализации делегирования интерфейсов.
avalon 1.0rc3 build 432, zlib 1.2.5
Re[2]: Неудачные решения в Delphi
От: hattab  
Дата: 12.03.13 06:23
Оценка:
Здравствуйте, Slicer [Mirkwood], Вы писали:

SM> Если кто-то уверен, что он-то уж точно никогда подобных глупостей не совершит — ну и прекрасно. Статья не ругает недостатки Делфи — статья суммирует часть отрицательного опыта разработки, связанного с определенными особенностями (и недостатками) Делфи. Не пригодится одним — пригодится другим.


Тогда так и нужно было называть статью: "Мой отрицательный опыт разработки, связанный с определенными особенностями (и недостатками) Делфи."
avalon 1.0rc3 build 432, zlib 1.2.5
Re[3]: Неудачные решения в Delphi
От: butcha Россия  
Дата: 12.03.13 16:22
Оценка:
Здравствуйте, Slicer [Mirkwood], Вы писали:

SM>Это с вашей стороны всего лишь популизм. Или укажите конкретный способ использования ProcessMessages, гарантирующий отсутствие подобных ошибок, — люди вам спасибо скажут, — или согласимся на том, что есть-таки опасность получить и такой эффект, если пользоваться ProcessMessages.


Конкретный способ:

Программа при старте загружает последний открытый файл (сотню файлов). Если определяем что загрузка может занять время (файлов много), показываем модальное окошко с прогресс-баром и кнопкой "Cancel". Без периодического вызова "ProcessMessages" не будет прорисовываться не прогресс-бар ни работать кнопка.
Модальное окно гарантирует что пользователь не полезет от скуки в меню или закроет программу или запустит "какой-то таймер сыпящий зачем то куда то сообщения".

B>>Наверное создатели VCL всё же полагали что пользователям (программистам Windows!) знакомы понятия "Messages, Message Queues, Message Loop и Window Procedure" и главный поток. И сделали простое решение, позволяющее не выделять долгие операции в отдельный поток, а выполнять в основном и давать возможность среагировать к примеру на кнопку Cancel или отрисовывать прогресс-бар


SM>И что же следует из ваших слов? Кто гарантирует, что реакция будет именно на кнопку Cancel, а никакие другие, нежелательные нам на данном этапе, действия пользователь осуществить не сможет?


Из моих слов следует то что что функция предназначена для тех кто способен прочитать и понять слова:

«In lengthy operations, calling ProcessMessages periodically allows the application to respond to paint and other messages»

и представляет себе процесс обработки сообщений в главном потоке и не будет совать функцию с непонятным ему предназначением туда куда не надо.

Гарантировать должен программист, вызывать её только при "lengthy operations" в основном потоке, обеспечивая модальный режим, при котором невозможно предпринимать никакие другие действия со стороны пользователя, но иметь возможность корректно среагировать к примеру на принудительное завершение, выключение виндовс ...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.