Однако обозначенная проблема гораздо глубже и не ограничивается рамками кода ваших расширений: при таком способе закрытия 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` — мы заставим Вас работать через задницу!