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

17/01/2014

Выгрузка и удаление внешней ссылки при помощи .NET

В  приложении ObjectARX чтобы получить уведомление  после того, как внешняя ссылка выгружена или удалена необходимо переопределить методы "AcEditorReactor::xrefSubcommandUnloadItem" и "AcEditorReactor::xrefSubcommandDetachItem" класса реактора редактора. К сожалению, в AutoCAD .Net API нет соответствующих методов. 

В качестве «обходного метода» можно использовать следующий проект, который можно использовать в .NET.

Полный код можете посмотреть в конце. Шаги, относящиеся к этому коду, следующие: 

1) Экспортируем метод из .arx, который принимает указатель на функцию для уведомления.

Код - C++: [Выделить]
  1. // Указатель на функцию, который буде хранится в реакторе редактора
  2. typedef void (__stdcall *PTRFN_Notify)(int xrefUnloadType);
  3.  
  4. // Экспортируем метод, который будет вызываться из .Net
  5. extern "C" DLLIMPEXP
  6.             void SetXrefEventNotifyCB(PTRFN_Notify callBack);

2) Реализуем реактор редактора в ObjectARX-модуле.

Код - C++: [Выделить]
  1. // asdkMyEdReactor.h
  2.  
  3. class asdkMyEdReactor : public AcEditorReactor
  4. {
  5. protected:
  6.     // Переопределяем функции уведомления о выгрузке/удалении Xref
  7.     virtual void xrefSubcommandUnloadItem(
  8.                                            AcDbDatabase* pHost,
  9.                                            int activity,
  10.                                            AcDbObjectId blockId
  11.                                          );
  12.  
  13.     virtual void xrefSubcommandDetachItem(
  14.                                            AcDbDatabase* pHost,
  15.                                            int activity,
  16.                                            AcDbObjectId blockId
  17.                                           );
  18.  
  19. public:
  20.     static PTRFN_Notify mXrefCB;
  21.  
  22.     //...
  23. } ;
  24.  
  25.  
  26. // asdkMyEdReactor.cpp
  27.  
  28. PTRFN_Notify asdkMyEdReactor::mXrefCB = NULL;
  29.  
  30. void asdkMyEdReactor::xrefSubcommandUnloadItem(
  31.                                         AcDbDatabase* pHost,
  32.                                         int activity,
  33.                                         AcDbObjectId blockId)
  34. {
  35.     acutPrintf(ACRX_T("\nC++ : XRef выгружен."));
  36.  
  37.     // Проверяем не нулевой ли указатель на функцию уведомления
  38.     if(mXrefCB != NULL)
  39.     {
  40.         // Уведомляем наш C#-модуль о выгрузке
  41.         (mXrefCB)(1);
  42.     }
  43.     AcEditorReactor::xrefSubcommandUnloadItem(pHost, activity, blockId);
  44. }
  45.  
  46. void asdkMyEdReactor::xrefSubcommandDetachItem(
  47.                                         AcDbDatabase* pHost,
  48.                                         int activity,
  49.                                         AcDbObjectId blockId)
  50. {
  51.     acutPrintf(ACRX_T("\nC++ : XRef удалён."));
  52.  
  53.     // Проверяем не нулевой ли указатель на функцию уведомления
  54.     if(mXrefCB != NULL)
  55.     {
  56.         // Уведомляем наш C#-модуль об удалении
  57.         (mXrefCB)(2);
  58.     }
  59.     AcEditorReactor::xrefSubcommandDetachItem(pHost, activity, blockId);
  60. }
  61.  
  62. // Сохраняем указатель для последующего использования
  63. // Он будет использоваться для уведомления о выгрузке/удалении Xref.
  64. void SetXrefEventNotifyCB(PTRFN_Notify callBack)
  65. {
  66.     asdkMyEdReactor::mXrefCB = callBack;
  67. }

3) Реализуем функцию обратного вызова в .NET-плагине и вызовем экспортированный метод при помощи делегата, инициализированного методом обратного вызова.

Код - C#: [Выделить]
  1. // Нужно для dllimport
  2. using System.Runtime.InteropServices;
  3.  
  4. public delegate void XrefUnloadDelegate(int xrefUnloadType);
  5.  
  6. // Делегат, который передается в .arx-модуль
  7. static XrefUnloadDelegate _xrefUnloadCB = null;
  8.  
  9. // Получаем метод, экспортированный из .arx-модуля
  10. [DllImport("AdskXrefUnloadTest.arx", CharSet = CharSet.Auto)]
  11. public static extern void
  12.             SetXrefEventNotifyCB(MulticastDelegate callback);
  13.  
  14. // Функция обратного вызова, вызываемая из .arx-модуля, когда
  15. // Xref выгружается / удаляется
  16. // xrefUnloadType = 1 означает выгрузку
  17. // xrefUnloadType = 2 означает удаление
  18. public void xrefCB(int xrefUnloadType)
  19. {
  20.     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  21.     if (xrefUnloadType == 1)
  22.         ed.WriteMessage("\nC# : XRef выгружен.");
  23.     else if (xrefUnloadType == 2)
  24.         ed.WriteMessage("\nC# : XRef удален.");
  25.     else
  26.         ed.WriteMessage("\nC# : XRef CB. Неизвестный тип выгрузки.");
  27. }
  28.  
  29. void IExtensionApplication.Initialize()
  30. {
  31.     if (_xrefUnloadCB == null)
  32.         _xrefUnloadCB = new XrefUnloadDelegate(xrefCB);
  33.  
  34.     // Передаем функцию обратного вызова .arx-модулю
  35.     SetXrefEventNotifyCB(_xrefUnloadCB);
  36. }

А вот и проект: Загрузить XrefUnloadDetach

Источник: http://adndevblog.typepad.com/autocad/2013/07/xref-unload-detach-event-in-net.html

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

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