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

24/02/2015

Получение значений свойств из COM-обертки примитива

Когда создаём AutoCAD-приложение, достаточно просто получить свойства примитива без использования COM-обертки примитива. Но когда создается приложение RealDWG, может быть необходимым получить свойства примитива именно из COM-обертки. 

Если вы используете .NET-языки, то можно воспользоваться «отражением». Вот эта статья может помочь:

Получение свойств и методов класса ActiveX/COM из .NET

Если вы используете C++ вы можете таким образом изменить пример DumpDwg из RealDWG SDK. В этом примере мы получаем свойства примитива, используя интерфейс IDispatch его COM-обертки. Например, если чертеж содержит примитив "AsdkPoly" из примера "ObjectARX 2015\samples\entity\polysampPolySamp".

Код - C++: [Выделить]
  1. // Информация о каждом экземпляре IDispatch
  2. struct  stringdispid
  3. {
  4.   CComBSTR bstr;
  5.   int  nLen;
  6.   DISPID id;
  7. };
  8.  
  9. // DispId связь для получения свойств
  10. static  stringdispid* m_pMap;
  11. static  int  m_nMapLen;
  12. static  int  m_nCount;
  13.  
  14. // Вспомогательный метод для конвертации VARIANT в ads_point
  15. static  HRESULT get_PointFromVariant(VARIANT &variant, ads_point &pt)
  16. {
  17.   if  (V_VT(&variant) != VT_EMPTY)
  18.   {
  19.     if  (V_VT(&variant) == (VT_ARRAY | VT_R8))
  20.     {
  21.       SAFEARRAY *psa = variant.parray;
  22.       long  lStartIndex = 0;
  23.       long  lEndIndex = 0;
  24.       SafeArrayGetLBound(psa, 1, &lStartIndex);
  25.       SafeArrayGetUBound(psa, 1, &lEndIndex);
  26.  
  27.       if (lEndIndex == 2)
  28.       {
  29.         AcAxPoint3d tmpPt(variant);
  30.         pt[X] = tmpPt[X];
  31.         pt[Y] = tmpPt[Y];
  32.         pt[Z] = tmpPt[Z];
  33.       }
  34.  
  35.       if (lEndIndex == 1)
  36.       {
  37.         AcAxPoint2d tmpPt(variant);
  38.         pt[X] = tmpPt[X];
  39.         pt[Y] = tmpPt[Y];
  40.         pt[Z] = 0.0;
  41.       }
  42.  
  43.       return  S_OK;
  44.     }
  45.   }
  46.   return  E_INVALIDARG; 
  47. }
  48.  
  49. // Вспомогательный метод для получения COM-обертки для примитива
  50. static  IAcadBaseObject* get_com_wrapper (AcDbEntity* entity)
  51. {
  52.   AcAxOleLinkManager* manager = AcAxGetOleLinkManager();
  53.   if  (!manager)
  54.     return  NULL;
  55.  
  56.   IUnknown* unknown = manager->GetIUnknown(entity);
  57.   if  (!unknown)
  58.   {
  59.     CLSID class_id;
  60.     if  (Acad::eOk != entity->getClassID(&class_id))
  61.       return  NULL;
  62.  
  63.     HRESULT res = CoCreateInstance(
  64.       class_id,
  65.       NULL,
  66.       CLSCTX_ALL,
  67.       IID_IUnknown,
  68.       (LPVOID*) &unknown);
  69.  
  70.     if  (FAILED(res))
  71.       return  NULL;
  72.  
  73.     IAcadBaseObject* base = NULL;
  74.     res = unknown->QueryInterface(__uuidof (IAcadBaseObject), (VOID**) &base);
  75.  
  76.     if  (FAILED(res))
  77.       return  NULL;
  78.  
  79.     if  (!manager->SetIUnknown(entity, unknown))
  80.       return  FALSE;
  81.  
  82.     base->SetObjectId(entity->objectId());
  83.     base->Release();
  84.   }
  85.  
  86.   // Вызывающая функция должна позаботиться об освобождении интерфейса
  87.   IAcadBaseObject* wrapper = NULL;
  88.   HRESULT res = unknown->QueryInterface(__uuidof (IAcadBaseObject), (VOID**) &wrapper);
  89.  
  90.   if  (FAILED(res))
  91.     return  NULL;
  92.  
  93.   return  wrapper;
  94. }
  95.  
  96. // Вспомогательный метод для получения описания функции
  97. // из typeinfo и помещение её в связь
  98. static  HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
  99. {
  100.   TYPEATTR* pta;
  101.   HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
  102.   if  (SUCCEEDED(hr))
  103.   {
  104.     m_nCount = 0;
  105.     m_nMapLen = pta->cFuncs;
  106.     m_pMap = NULL;
  107.  
  108.     if (m_nMapLen > 0)
  109.       m_pMap =  new  stringdispid[m_nMapLen];
  110.  
  111.     for  (int  i=0; i<m_nMapLen; i++)
  112.     {
  113.       FUNCDESC* pfd;
  114.       if  (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
  115.       {
  116.         CComBSTR bstrName;
  117.         if  (SUCCEEDED(pTypeInfo->GetDocumentation(
  118.           pfd->memid,
  119.           &bstrName,
  120.           NULL,
  121.           NULL,
  122.           NULL)))
  123.         {
  124.           if (pfd->invkind == DISPATCH_PROPERTYGET)
  125.           {
  126.             m_pMap[m_nCount].bstr.
  127.               Attach(bstrName.Detach());
  128.             m_pMap[m_nCount].nLen
  129.               = SysStringLen(m_pMap[i].bstr);
  130.             m_pMap[m_nCount].id = pfd->memid;
  131.             m_nCount++;
  132.           }
  133.         }
  134.         pTypeInfo->ReleaseFuncDesc(pfd);
  135.       }
  136.     }
  137.     pTypeInfo->ReleaseTypeAttr(pta);
  138.   }
  139.   return  S_OK;
  140. }
  141.  
  142. // Получение свойств примитива при помощи
  143. // IDispatch интерфейса его COM-обертки
  144. HRESULT dumPolyProps(AcDbEntity *pEntity)
  145. {
  146.   ::CoInitialize(NULL);
  147.  
  148.   IAcadBaseObject *pAcadObj = get_com_wrapper(pEntity);
  149.  
  150.   CComQIPtr<ITypeLib> pTypeLib(pAcadObj);
  151.   CComQIPtr<ITypeInfo> pTypeInfo(pAcadObj);
  152.  
  153.   TCHAR full_app_file_name[512] = L"" ;
  154.   int  nBufferLength = 512;
  155.   TCHAR* filePart;
  156.   DWORD result;
  157.   result = SearchPath(NULL, _T("asdkcompoly.dbx" ),
  158.     _T(".dbx" ), 512, full_app_file_name, &filePart);
  159.   if  (result && result < (DWORD)nBufferLength)
  160.   {
  161.     HRESULT hr = LoadTypeLib
  162.       (full_app_file_name, &pTypeLib);
  163.  
  164.     if  (FAILED(hr))
  165.       return  hr;
  166.  
  167.     UINT iCount = pTypeLib->GetTypeInfoCount();
  168.     for  (UINT i=0; i < iCount ; i++)
  169.     {
  170.       hr = pTypeLib->GetTypeInfo(i, &pTypeInfo);
  171.       if  (FAILED(hr))
  172.         return  hr;
  173.  
  174.       LoadNameCache(pTypeInfo);
  175.  
  176.       CComQIPtr<IDispatch> pDisp(pAcadObj);
  177.  
  178.       // Получение свойств
  179.       for (int  index = 0; index < m_nCount; index++)
  180.       {
  181.         OLECHAR *sMember = m_pMap[index].bstr;
  182.         DISPID dispId;
  183.  
  184.         hr = pDisp->GetIDsOfNames(
  185.           IID_NULL,
  186.           &sMember,
  187.           1,
  188.           LOCALE_SYSTEM_DEFAULT,
  189.           &dispId);
  190.  
  191.         if (SUCCEEDED(hr))
  192.         {
  193.           unsigned  int  puArgErr = 0;
  194.  
  195.           VARIANT VarResult;
  196.           VariantInit(&VarResult);
  197.  
  198.           EXCEPINFO pExcepInfo;
  199.  
  200.           DISPPARAMS pParams;
  201.           memset(&pParams, 0, sizeof (DISPPARAMS));
  202.           pParams.cArgs = 0;
  203.  
  204.           hr = pDisp->Invoke(
  205.             dispId,
  206.             IID_NULL,
  207.             LOCALE_USER_DEFAULT,
  208.             DISPATCH_PROPERTYGET,
  209.             &pParams,
  210.             &VarResult,
  211.             &pExcepInfo,
  212.             NULL);
  213.  
  214.           if (V_VT(&VarResult)
  215.             == (VT_ARRAY | VT_R8))
  216.           {
  217.             // Преобразуем в ads_point
  218.             ads_point pt;
  219.  
  220.             get_PointFromVariant(VarResult, pt);
  221.  
  222.             _print(_T("%s : %lf %lf %lf\\n" ),
  223.               sMember, pt[0], pt[1], pt[2]);
  224.           }
  225.           else  if (VarResult.vt == VT_DISPATCH)
  226.           {
  227.             _print(_T("%s : VT_DISPATCH\\n" ),
  228.               sMember);
  229.             //IDispatchPtr pDispatch 
  230.             //                 = VarResult.pdispVal;
  231.           }
  232.           else
  233.           {
  234.             hr = VariantChangeType(
  235.               &VarResult,
  236.               &VarResult,
  237.               0,
  238.               VT_BSTR);
  239.             _print(_T("%s : %s\\n" ),
  240.               sMember,
  241.               VarResult.bstrVal);
  242.           }
  243.           VariantClear(&VarResult); 
  244.         }
  245.       }
  246.  
  247.       delete [] m_pMap;
  248.       m_pMap = NULL;
  249.     }
  250.   }
  251.  
  252.   CoUninitialize();
  253.  
  254.   return  S_OK;
  255. }
  256.  
  257. // Вызываем метод dumpEntity
  258. void  dumpEntity(AcDbEntity *pEnt)
  259. {
  260.   if  (_tcscmp(p, _T("AsdkPoly" )) == 0)
  261.     dumPolyProps(pEnt);
  262.  
  263.   // ... Ну и дальнейший код
  264. }

Вот скриншот полученных свойств:

 

Источник: http://adndevblog.typepad.com/autocad/2014/12/retrieving-property-values-from-entitys-com-wrapper-.html

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

Опубликовано 24.02.2015
Отредактировано 24.02.2015 в 21:12:20