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

16/07/2015

Преобразование из .NET в COM с использованием управляемого (Managed) C++

После выбора объекта при помощи .NET (управляемый C++), как его преобразовать в COM-объект? Сначала нужно получить IUnknow-указатель из свойства AcadObject объекта, а затем преобразовать его в COM-объект. Эта процедура позволяет вам сохранить счетчик ссылок COM объекта.

Следующий код показывает как это сделать и как получить его имя типа. Напоминаю, что нужно установить для проекта свойство Mixed mode. Это легко сделать создав проект при помощи ObjectARX Wizard и указав ему использовать .NET.

Код - C++: [Выделить]
  1. static void MgdFunction()
  2. {
  3.   // Получаем коллекцию документов (MDI-интерфейс)
  4.  
  5.   Autodesk::AutoCAD::ApplicationServices::DocumentCollection ^docMgr =
  6.     Autodesk::AutoCAD::ApplicationServices::Application::DocumentManager;
  7.  
  8.   // Получаем активный документ
  9.  
  10.   Autodesk::AutoCAD::ApplicationServices::Document ^acadDoc =
  11.     docMgr->MdiActiveDocument;
  12.  
  13.   // Получаем редактор (Editor)
  14.  
  15.   Autodesk::AutoCAD::EditorInput::Editor ^ed = acadDoc->Editor;
  16.  
  17.   // Объект транзакции
  18.   Autodesk::AutoCAD::DatabaseServices::Transaction ^trans = nullptr;
  19.  
  20.   try
  21.   {
  22.     // Стартуем транзакцию
  23.  
  24.     trans = acadDoc->Database->TransactionManager->StartTransaction();
  25.  
  26.     // Выбираем примитив при помощи .NET API
  27.  
  28.     Autodesk::AutoCAD::EditorInput::PromptEntityResult ^promptEntRes =
  29.       ed->GetEntity(_T("\nВыберите примитив: "));
  30.  
  31.     if (promptEntRes->Status != Autodesk::AutoCAD::EditorInput::PromptStatus::OK)
  32.       return;
  33.  
  34.     // Открываем примитив для чтения
  35.  
  36.     Autodesk::AutoCAD::DatabaseServices::Entity ^mgdEntity =
  37.       (Autodesk::AutoCAD::DatabaseServices::Entity^)
  38.       trans->GetObject(promptEntRes->ObjectId,
  39.       Autodesk::AutoCAD::DatabaseServices::OpenMode::ForRead);
  40.  
  41.     // Получаем COM-объект из .NET-объекта
  42.  
  43.     System::Object ^acadObj = mgdEntity->AcadObject;
  44.  
  45.     System::IntPtr ptr = System::Runtime::InteropServices::Marshal::GetIUnknownForObject(acadObj);
  46.  
  47.     IUnknown* iunk = static_cast<IUnknown *>(ptr.ToPointer());
  48.  
  49.     CComQIPtr<IAcadEntity> acadEntity = iunk;
  50.  
  51.     iunk->Release();
  52.  
  53.     // Получаем имя примитива из COM-объекта
  54.     // Это будет имя класса типа AcDbLine для отрезка
  55.     // или AcDbCircle для окружности, и т.д.
  56.  
  57.     CComBSTR entityName;
  58.  
  59.     acadEntity->get_EntityName(&entityName);
  60.  
  61.     // Если мы сделаем правильное преобразование, например в IAcadLine для отрезка,
  62.     // тогда мы можем вызвать любой другой метод этого COM-объекта
  63.     // Сейчас получим имя COM-интерфейса объекта
  64.     // Это будет что-то типа IAcadLine, IAcadCircle, и т.д.
  65.  
  66.     CComPtr<ITypeInfo> typeInfo;
  67.  
  68.     acadEntity->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&typeInfo);
  69.  
  70.     CComBSTR interfaceName;
  71.  
  72.     typeInfo->GetDocumentation(-1,&interfaceName, 0,0,0);
  73.  
  74.     // и печатаем при помощи .NET
  75.  
  76.     ed->WriteMessage(_T("\nВыбран примитив: {0} ({1})"),
  77.       gcnew System::String(entityName),
  78.       gcnew System::String(interfaceName));
  79.  
  80.     trans->Commit();
  81.  
  82.   }
  83.  
  84.   catch(System::Exception^ e)
  85.   {
  86.  
  87.     // Что-то пошло не так
  88.  
  89.     ed->WriteMessage(e->Message);
  90.  
  91.   }
  92.  
  93.   __finally
  94.   {
  95.     // Освобождаем транзакцию
  96.     trans->~Transaction();
  97.   }
  98.  
  99. }

 

Источник: http://adndevblog.typepad.com/autocad/2013/01/cast-from-net-to-com-using-managed-c.html

Автор перевода: Александр Ривилис

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

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