Как удалить команду из списка доступных команд AutoCAD
Это экзотическая ситуация, но может возникнуть необходимость полностью запретить команду AutoCAD. Один из вариантов – выполнение метода veto() в событии DocumentLockModeChanged. Но при этом команда есть в списке доступных команд и её выполнение начинается, а затем прерывается.
Есть более радикальный метод – использование метода RemoveCommand недокументированного класса Utils из пространства имён Autodesk.AutoCAD.Internal. Этот метод – обертка для метода AcEdCommandStack::removeCmd из ObjectARX. Ему передаются два параметра – имя группы команд и имя команды. Обычно достаточно передать глобальное имя команды, но бывают и исключения. Поэтому мы удалим команду и по глобальному и по локальному имени. Так как мы не знаем в какой локализации AutoCAD будет выполняться код, то нам нужно получить имя локализованной команды по её глобальному имени. Для этой цели в ObjectARX есть функция acedGetCName которая в версиях AutoCAD до 2012 включительно содержится в acad.exe, а позднее в accore.dll Мы воспользуемся P/Invoke для вызова её из .NET
Результирующий код выглядит так:
- using System;
- using System.Runtime.InteropServices;
- using Autodesk.AutoCAD.Runtime;
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.Internal;
- [assembly: ExtensionApplication(typeof(UndefCommand.MyPlugin))]
- namespace UndefCommand
- {
- public class MyPlugin : IExtensionApplication
- {
- string[] cmd_undef_main_list = new string[] {
- "LINE",
- "PLINE",
- "ARC",
- "SPLINE"
- };
- void IExtensionApplication.Initialize()
- {
- foreach (string cmd in cmd_undef_main_list) {
- if (Utils.IsCommandDefined(cmd))
- {
- string cmdLocal = GetCName("_" + cmd);
- Utils.RemoveCommand("ACAD_MAIN", cmdLocal);
- if (cmdLocal != cmd) Utils.RemoveCommand("ACAD_MAIN", cmd);
- }
- }
- }
- void IExtensionApplication.Terminate()
- {
- }
- #region PInvoke
- [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
- EntryPoint = "?acedGetCName@@YAHPB_WPAPA_W@Z")]
- private extern static Int32 acedGetCName32R18(string Name, out IntPtr otherName);
- [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
- EntryPoint = "?acedGetCName@@YAHPEB_WPEAPEA_W@Z")]
- private extern static Int32 acedGetCName64R18(string Name, out IntPtr otherName);
- [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
- EntryPoint = "?acedGetCName@@YAHPB_WPAPA_W@Z")]
- private extern static Int32 acedGetCName32R19(string Name, out IntPtr otherName);
- [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
- EntryPoint = "?acedGetCName@@YAHPEB_WPEAPEA_W@Z")]
- private extern static Int32 acedGetCName64R19(string Name, out IntPtr otherName);
- private static string GetCName(string Name)
- {
- IntPtr ptr = IntPtr.Zero;
- if (Application.Version.Major > 18)
- {
- if (IntPtr.Size == 4) acedGetCName32R19(Name, out ptr);
- else acedGetCName64R19(Name, out ptr);
- }
- else
- {
- if (IntPtr.Size == 4) acedGetCName32R18(Name, out ptr);
- else acedGetCName64R18(Name, out ptr);
- }
- return Marshal.PtrToStringUni(ptr);
- }
- #endregion
- }
- }
Обратите внимание на несколько моментов:
- Мы рассматривали команды из ядра AutoCAD, которые присутствуют в нём всегда после того, как AutoCAD запущен. Если это не так, то следует сначала загрузить модуль, который выполняет команду, а затем уже удалить её.
- Команды, которые находятся в ядре AutoCAD, входят в группу ACAD_MAIN. Но если нам нужно заблокировать команду не из ядра, то следует предварительно посмотреть к какой группе относится команда. Для этой цели нужно воспользоваться командой _ARX с опцией _Command. Например, команда ЛЕНТА (_RIBBON) содержится в группе RIBBON, а команда СЛОЙ (_LAYER) содержится в группе AcLayerCommands.
Обсуждение: http://adn-cis.org/forum/index.php?topic=7450
Опубликовано 14.11.2016Отредактировано 15.11.2016 в 00:18:59