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

22/10/2015

Обновление Палитры Внешних ссылок при помощи Microsoft UI Automation

В этой статье мы рассмотрим процедуру обновления Палитры Внешних Ссылок AutoCAD. Прежде, чем мы углубимся в детали, вот некоторая справочная информация о том, почему может потребоваться обновлять эту палитру.

Палитра внешних ссылок AutoCAD превращается в расширенное стандартное окно (ESW) в том случае если установлен плагин Vault для AutoCAD. Поскольку статус возврата / получения файлов отображаются в Палитре Внешних Ссылок, необходимо обновление палитры для отображения текущего состояния в том случае, когда статус изменён извне при помощи клиента Vault.

В силу того, что нет никакого публичного API для этого, мы рассмотрим использование Microsoft UI Automation для имитации нажатия кнопки Обновить. Пожалуйста, обратите внимание, что подход, предложенный здесь не поддерживается Autodesk, а опирается на Win32 и UI Automation API. Если вы будете  использовать этот подход, пожалуйста, проверить его более детально в своем приложении.

Чтобы нажать на кнопку Обновить в Microsoft UI Automation имеется все необходимое. К сожалению, природа кнопки Обновить в Палитре Внешних Ссылок AutoCAD такова, что это сделать затруднительно. Глядя на макет Палитры Внешних Ссылок палитре с помощью утилиты Spy ++, становится очевидным, что кнопка Обновить является частью панели инструментов внутри палитры. Кроме того, кнопка Обновить является раскрывающимся меню с вариантами Перезагрузить и Обновить. При использовании паттерна Invoke UI Automation невозможно симулировать нажатие кнопки мыши на кнопке  Обновить.

Чтобы обойти это, мы можем прибегнуть к методу Win32 API SendInput для имитации щелчка мыши, а собрать необходимые материалы по этому методу с использованием Microsoft UI Automation API. Вот пример кода, который работает нормально в AutoCAD 2016. Для других версий AutoCAD вам возможно потребуется определить идентификатор элемента управления кнопки Обновить, при помощи утилиты Spy ++ и изменить соответствующим образом код.

Код - C#: [Выделить]
  1. // Добавим ссылку на UIAutomationClient.dll 
  2. // и UIAutomationTypes.dll
  3. using  System.Windows.Automation;
  4. using  System.Diagnostics;
  5. using  System.Runtime.InteropServices;
  6.  
  7. using  Autodesk.AutoCAD.Runtime;
  8. using  Autodesk.AutoCAD.EditorInput;
  9. using  Autodesk.AutoCAD.DatabaseServices;
  10. using  Autodesk.AutoCAD.ApplicationServices;
  11.  
  12.  
  13. // Основано на http://www.pinvoke.net
  14. // /default.aspx/user32/SendInput.html
  15. // /default.aspx/Structures/MOUSEINPUT.html
  16. // /default.aspx/user32/mouse_event.html
  17.  
  18. [DllImport("user32.dll" , SetLastError = true )]
  19. static  extern  uint SendInput(uint nInputs,
  20.             INPUT[] pInputs, int  cbSize);
  21.  
  22. [StructLayout(LayoutKind.Sequential)]
  23. internal  struct  MOUSEINPUT
  24. {
  25.     public  int  dx;
  26.     public  int  dy;
  27.     public  uint mouseData;
  28.     public  uint dwFlags;
  29.     public  uint time;
  30.     public  IntPtr dwExtraInfo;
  31. }
  32.  
  33. [StructLayout(LayoutKind.Sequential)]
  34. internal  struct  INPUT
  35. {
  36.     public  int  type;
  37.     public  MOUSEINPUT mi;
  38.     public  INPUT(uint flag)
  39.     {
  40.         type = 0; // Мышиный ввод
  41.         mi.dx = 0;
  42.         mi.dy = 0;
  43.         mi.mouseData = 0;
  44.         mi.time = 0;
  45.         mi.dwExtraInfo = IntPtr.Zero;
  46.         mi.dwFlags = flag;
  47.     }
  48. }
  49.        
  50. private  const  int  MOUSEEVENTF_LEFTDOWN = 0x0002;
  51. private  const  int  MOUSEEVENTF_LEFTUP = 0x0004;
  52.  
  53. [CommandMethod("XRefPalRefresh" )]
  54. public  void  XRefPalRefresh()
  55. {
  56.     Editor ed =
  57.                         Application.DocumentManager.MdiActiveDocument.Editor;
  58.     try
  59.     {
  60.         System.Diagnostics.Process p
  61.                                    = Process.GetCurrentProcess();
  62.         AutomationElement acadAutoElem =
  63.                                    AutomationElement.RootElement.FindFirst(
  64.                                    TreeScope.Children,
  65.             new  PropertyCondition(
  66.                                    AutomationElement.ProcessIdProperty, p.Id));
  67.  
  68.         // Идентификатор элемента управления кнопки Обновить
  69.                         // в AutoCAD 2016 полученный из Spy++
  70.         string btnRefreshhexID = "000075FB" ;
  71.         string btnRefreshdecimalID =
  72.                                    System.Convert.ToInt32(btnRefreshhexID, 16)
  73.                                    .ToString();
  74.         AutomationElement refreshBtnAutoElem
  75.                                    = acadAutoElem.FindFirst(
  76.             TreeScope.Descendants,
  77.             new  PropertyCondition(
  78.                                    AutomationElement.AutomationIdProperty,
  79.                                    btnRefreshdecimalID));
  80.  
  81.         if  (refreshBtnAutoElem == null)
  82.         {
  83.             ed.WriteMessage("Кнопка Обновить в
  84.                                                Палитре Внешних Ссылок
  85.                                                Не найдена !");
  86.             return ;
  87.         }
  88.                
  89.         // Использование шаблона UI's Invoke
  90.         // Работает для обычных простых кнопок, но не работает 
  91.                         // для кнопки Обновить в Палитре Внешних Ссылок
  92.         //InvokePattern ipClickRefreshBtn = 
  93.                         // (InvokePattern)refreshBtnAutoElem.GetCurrentPattern
  94.                         // (InvokePattern.Pattern);
  95.         //ipClickRefreshBtn.Invoke();
  96.  
  97.         // Щелкаем по местоположению.
  98.         System.Windows.Point point
  99.                                    = refreshBtnAutoElem.GetClickablePoint();
  100.         System.Windows.Forms.Cursor.Position
  101.             = new  System.Drawing.Point(
  102.                                    (int )point.X, (int )point.Y);
  103.  
  104.         INPUT input1 = new  INPUT(MOUSEEVENTF_LEFTDOWN);
  105.         INPUT input2 = new  INPUT(MOUSEEVENTF_LEFTUP);
  106.         SendInput(2, new [] { input1, input2 },
  107.                                    Marshal.SizeOf(typeof(INPUT)));
  108.     }
  109.     catch  (System.Exception ex)
  110.     {
  111.         ed.WriteMessage(ex.Message);
  112.     }
  113. }


Источник: http://adndevblog.typepad.com/autocad/2015/09/refreshing-external-references-palette-using-microsoft-ui-automation.html
Автор перевода: Александр Ривилис

Обсуждение: http://adn-cis.org/forum/index.php?topic=3124

Опубликовано 22.10.2015