Как известно, accoreconsole.exe
всегда был и до сих пор остаётся достаточно кривым... Один из неприятных
аспектов его поведения, присутствующий по сей день, заключается в том,
что если завершать работу приложения кликом мышки по кнопке закрытия
консольного окна в верхнем правом углу, либо выбирая соответствующий
пункт из контекстного меню консольного окна, то приложение завершает свою работу через
задницу - не выполняя код методов Terminate(), а так же код зарегистрированных событий, таких например, как AppDomain.CurrentDomain.ProcessExit.
Однако обозначенная проблема гораздо глубже и не ограничивается рамками кода ваших расширений: при таком способе закрытия AutoCAD так же не выполняет и свой собственный код, который он обычно выполняет при завершении работы приложения (код корректного освобождения ресурсов, сохранения настроек и т.п.). Например, не происходит восстановление настроек в реестре, которые временно были изменены accoreconsole.exe под свои нужды. Это сразу бросается в глаза на напримере переменной FILEDIA, на время работы консольного приложения устанавливается в 0: при очередном запуске acad.exe для неё приходится вручную восстанавливать значение 1 (в противном случае вместо диалоговых окон AutoCAD будет использовать свою консоль).
Если завершать работу accoreconsole.exe путём вызова команд quit и exit, то завершение работы приложения происходит так, как это должно было происходить (т.е. выполняется весь необходимый код). Однако никто не застрахован от клика мышкой по обозначенной выше кнопке, а пользователи с вероятностью 100% будут клацать как раз именно по ней, когда потребуется завершить работу приложения, потому как такой способ завершения работы - самый простой.
В качестве "лекарства" против обозначенной выше проблемы я блокирую кнопку закрытия консольного окна и соответствующий её пункт контекстного меню:
Однако по факту я вижу, что кнопка закрытия окна заблокирована, а вот контекстное меню - нет... Конечно, можно попросту вовсе удалить этот пункт из контекстного меню и не заморачиваться на эту тему (в обозначенном выше примере кода это успешно делает последняя закомментированная строчка).
Однако мне всё же интересно: почему не блокируется пункт меню?
Оказалось, что обозначенная проблема свойственна не только accoreconsole.exe, но и любому консольному приложению в Windows 7 x64, а так же в Windows Server 2003. А вот в Windows 10 x64 всё работает корректно...
Т.о. то, что контекстное меню не блокируется в некоторых версиях Windows - очень похоже на баг WinAPI.
В этой же теме сразу размещаю код примера того, как можно скрывать или отображать консольное окно (например всё тот же accoreconsole.exe):
Длительная, нередко печальная практика показывает, что лозунг Autodesk касательно данного продукта, к сожалению, выглядит как-то так:
Однако обозначенная проблема гораздо глубже и не ограничивается рамками кода ваших расширений: при таком способе закрытия AutoCAD так же не выполняет и свой собственный код, который он обычно выполняет при завершении работы приложения (код корректного освобождения ресурсов, сохранения настроек и т.п.). Например, не происходит восстановление настроек в реестре, которые временно были изменены accoreconsole.exe под свои нужды. Это сразу бросается в глаза на напримере переменной FILEDIA, на время работы консольного приложения устанавливается в 0: при очередном запуске acad.exe для неё приходится вручную восстанавливать значение 1 (в противном случае вместо диалоговых окон AutoCAD будет использовать свою консоль).
Если завершать работу accoreconsole.exe путём вызова команд quit и exit, то завершение работы приложения происходит так, как это должно было происходить (т.е. выполняется весь необходимый код). Однако никто не застрахован от клика мышкой по обозначенной выше кнопке, а пользователи с вероятностью 100% будут клацать как раз именно по ней, когда потребуется завершить работу приложения, потому как такой способ завершения работы - самый простой.
В качестве "лекарства" против обозначенной выше проблемы я блокирую кнопку закрытия консольного окна и соответствующий её пункт контекстного меню:
- const uint MF_BYCOMMAND = 0x00000000;
- const uint MF_GRAYED = 0x00000001;
- const uint SC_CLOSE = 0xF060;
- const uint MF_DISABLED = 0x00000002;
- [DllImport("kernel32.dll")]
- static extern IntPtr GetConsoleWindow();
- [DllImport("user32.dll")]
- static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
- [DllImport("User32.dll", SetLastError = true)]
- static extern uint EnableMenuItem(IntPtr hMenu, uint itemId, uint uEnable);
- [DllImport("user32.dll")]
- static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
- ...
- // Disable the Close ("X") button and "Close" context menu item of the Console window
- IntPtr hwnd = GetConsoleWindow();
- IntPtr hmenu = GetSystemMenu(hwnd, false);
- uint hWindow = EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
- // Also it is possible to delete "Close" context menu item
- // instead of disabling it.
- // DeleteMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
Однако по факту я вижу, что кнопка закрытия окна заблокирована, а вот контекстное меню - нет... Конечно, можно попросту вовсе удалить этот пункт из контекстного меню и не заморачиваться на эту тему (в обозначенном выше примере кода это успешно делает последняя закомментированная строчка).
Однако мне всё же интересно: почему не блокируется пункт меню?
Оказалось, что обозначенная проблема свойственна не только accoreconsole.exe, но и любому консольному приложению в Windows 7 x64, а так же в Windows Server 2003. А вот в Windows 10 x64 всё работает корректно...
Т.о. то, что контекстное меню не блокируется в некоторых версиях Windows - очень похоже на баг WinAPI.
В этой же теме сразу размещаю код примера того, как можно скрывать или отображать консольное окно (например всё тот же accoreconsole.exe):
- [DllImport("kernel32.dll")]
- static extern IntPtr GetConsoleWindow();
- [DllImport("user32.dll")]
- static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
- const int SW_HIDE = 0;
- const int SW_SHOW = 5;
- IntPtr hwnd = GetConsoleWindow();
- // Hide window
- ShowWindow(hwnd, SW_HIDE);
- // Show window
- ShowWindow(hwnd, SW_SHOW);
Длительная, нередко печальная практика показывает, что лозунг Autodesk касательно данного продукта, к сожалению, выглядит как-то так:
`accoreconsole.exe` - мы заставим Вас работать через задницу!
Комментариев нет:
Отправить комментарий