ADN Open CIS
Сообщество программистов Autodesk в СНГ

14/11/2016

Как удалить команду из списка доступных команд AutoCAD

Это экзотическая ситуация, но может возникнуть необходимость полностью запретить команду AutoCAD. Один из вариантов – выполнение метода veto() в событии DocumentLockModeChanged. Но при этом команда есть в списке доступных команд и её выполнение начинается, а затем прерывается.

Есть более радикальный метод – использование метода RemoveCommand недокументированного класса Utils из пространства имён Autodesk.AutoCAD.Internal. Этот метод – обертка для  метода AcEdCommandStack::removeCmd из ObjectARX. Ему передаются два параметра – имя группы команд и имя команды. Обычно достаточно передать глобальное имя команды, но бывают и исключения. Поэтому мы удалим команду и по глобальному и по локальному имени. Так как мы не знаем в какой локализации AutoCAD будет выполняться код, то нам нужно получить имя локализованной команды по её глобальному имени. Для этой цели в ObjectARX есть функция acedGetCName которая в версиях AutoCAD до 2012 включительно содержится в acad.exe, а позднее в accore.dll Мы воспользуемся P/Invoke для вызова её из .NET

Результирующий код выглядит так:

Код - C#: [Выделить]
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.Internal;
  6.  
  7. [assembly: ExtensionApplication(typeof(UndefCommand.MyPlugin))]
  8.  
  9. namespace UndefCommand
  10. {
  11.   public class MyPlugin : IExtensionApplication
  12.   {
  13.     string[] cmd_undef_main_list = new string[] {
  14.         "LINE",
  15.         "PLINE",
  16.         "ARC",
  17.         "SPLINE"
  18.     };
  19.  
  20.     void IExtensionApplication.Initialize()
  21.     {
  22.       foreach (string cmd in cmd_undef_main_list) {
  23.         if (Utils.IsCommandDefined(cmd))
  24.         {
  25.           string cmdLocal = GetCName("_" + cmd);
  26.           Utils.RemoveCommand("ACAD_MAIN", cmdLocal);        
  27.           if (cmdLocal != cmd) Utils.RemoveCommand("ACAD_MAIN", cmd);
  28.         }
  29.       }
  30.     }
  31.  
  32.     void IExtensionApplication.Terminate()
  33.     {
  34.     }
  35.     #region PInvoke
  36.  
  37.     [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
  38.       EntryPoint = "?acedGetCName@@YAHPB_WPAPA_W@Z")]
  39.     private extern static Int32 acedGetCName32R18(string Name, out IntPtr otherName);
  40.     [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
  41.       EntryPoint = "?acedGetCName@@YAHPEB_WPEAPEA_W@Z")]
  42.     private extern static Int32 acedGetCName64R18(string Name, out IntPtr otherName);
  43.     [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
  44.       EntryPoint = "?acedGetCName@@YAHPB_WPAPA_W@Z")]
  45.     private extern static Int32 acedGetCName32R19(string Name, out IntPtr otherName);
  46.     [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
  47.       EntryPoint = "?acedGetCName@@YAHPEB_WPEAPEA_W@Z")]
  48.     private extern static Int32 acedGetCName64R19(string Name, out IntPtr otherName);
  49.     private static string GetCName(string Name)
  50.     {
  51.       IntPtr ptr = IntPtr.Zero;
  52.       if (Application.Version.Major > 18)
  53.       {
  54.         if (IntPtr.Size == 4) acedGetCName32R19(Name, out ptr);
  55.                   else        acedGetCName64R19(Name, out ptr);
  56.       }
  57.       else
  58.       {
  59.         if (IntPtr.Size == 4) acedGetCName32R18(Name, out ptr);
  60.                 else          acedGetCName64R18(Name, out ptr);
  61.       }
  62.       return Marshal.PtrToStringUni(ptr);
  63.     }
  64.     #endregion
  65.   }
  66. }

 

Обратите внимание на несколько моментов:

  1. Мы рассматривали команды из ядра AutoCAD, которые присутствуют в нём всегда после того, как AutoCAD запущен. Если это не так, то следует сначала загрузить модуль, который выполняет команду, а затем уже удалить её.
  2. Команды, которые находятся в ядре 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