Получение значений свойств из COM-обертки примитива
Когда создаём AutoCAD-приложение, достаточно просто получить свойства примитива без использования COM-обертки примитива. Но когда создается приложение RealDWG, может быть необходимым получить свойства примитива именно из COM-обертки.
Если вы используете .NET-языки, то можно воспользоваться «отражением». Вот эта статья может помочь:
Получение свойств и методов класса ActiveX/COM из .NET
Если вы используете C++ вы можете таким образом изменить пример DumpDwg из RealDWG SDK. В этом примере мы получаем свойства примитива, используя интерфейс IDispatch его COM-обертки. Например, если чертеж содержит примитив "AsdkPoly" из примера "ObjectARX 2015\samples\entity\polysampPolySamp".
- // Информация о каждом экземпляре IDispatch
- struct stringdispid
- {
- CComBSTR bstr;
- int nLen;
- DISPID id;
- };
- // DispId связь для получения свойств
- static stringdispid* m_pMap;
- static int m_nMapLen;
- static int m_nCount;
- // Вспомогательный метод для конвертации VARIANT в ads_point
- static HRESULT get_PointFromVariant(VARIANT &variant, ads_point &pt)
- {
- if (V_VT(&variant) != VT_EMPTY)
- {
- if (V_VT(&variant) == (VT_ARRAY | VT_R8))
- {
- SAFEARRAY *psa = variant.parray;
- long lStartIndex = 0;
- long lEndIndex = 0;
- SafeArrayGetLBound(psa, 1, &lStartIndex);
- SafeArrayGetUBound(psa, 1, &lEndIndex);
- if (lEndIndex == 2)
- {
- AcAxPoint3d tmpPt(variant);
- pt[X] = tmpPt[X];
- pt[Y] = tmpPt[Y];
- pt[Z] = tmpPt[Z];
- }
- if (lEndIndex == 1)
- {
- AcAxPoint2d tmpPt(variant);
- pt[X] = tmpPt[X];
- pt[Y] = tmpPt[Y];
- pt[Z] = 0.0;
- }
- return S_OK;
- }
- }
- return E_INVALIDARG;
- }
- // Вспомогательный метод для получения COM-обертки для примитива
- static IAcadBaseObject* get_com_wrapper (AcDbEntity* entity)
- {
- AcAxOleLinkManager* manager = AcAxGetOleLinkManager();
- if (!manager)
- return NULL;
- IUnknown* unknown = manager->GetIUnknown(entity);
- if (!unknown)
- {
- CLSID class_id;
- if (Acad::eOk != entity->getClassID(&class_id))
- return NULL;
- HRESULT res = CoCreateInstance(
- class_id,
- NULL,
- CLSCTX_ALL,
- IID_IUnknown,
- (LPVOID*) &unknown);
- if (FAILED(res))
- return NULL;
- IAcadBaseObject* base = NULL;
- res = unknown->QueryInterface(__uuidof (IAcadBaseObject), (VOID**) &base);
- if (FAILED(res))
- return NULL;
- if (!manager->SetIUnknown(entity, unknown))
- return FALSE;
- base->SetObjectId(entity->objectId());
- base->Release();
- }
- // Вызывающая функция должна позаботиться об освобождении интерфейса
- IAcadBaseObject* wrapper = NULL;
- HRESULT res = unknown->QueryInterface(__uuidof (IAcadBaseObject), (VOID**) &wrapper);
- if (FAILED(res))
- return NULL;
- return wrapper;
- }
- // Вспомогательный метод для получения описания функции
- // из typeinfo и помещение её в связь
- static HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
- {
- TYPEATTR* pta;
- HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
- if (SUCCEEDED(hr))
- {
- m_nCount = 0;
- m_nMapLen = pta->cFuncs;
- m_pMap = NULL;
- if (m_nMapLen > 0)
- m_pMap = new stringdispid[m_nMapLen];
- for (int i=0; i<m_nMapLen; i++)
- {
- FUNCDESC* pfd;
- if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
- {
- CComBSTR bstrName;
- if (SUCCEEDED(pTypeInfo->GetDocumentation(
- pfd->memid,
- &bstrName,
- NULL,
- NULL,
- NULL)))
- {
- if (pfd->invkind == DISPATCH_PROPERTYGET)
- {
- m_pMap[m_nCount].bstr.
- Attach(bstrName.Detach());
- m_pMap[m_nCount].nLen
- = SysStringLen(m_pMap[i].bstr);
- m_pMap[m_nCount].id = pfd->memid;
- m_nCount++;
- }
- }
- pTypeInfo->ReleaseFuncDesc(pfd);
- }
- }
- pTypeInfo->ReleaseTypeAttr(pta);
- }
- return S_OK;
- }
- // Получение свойств примитива при помощи
- // IDispatch интерфейса его COM-обертки
- HRESULT dumPolyProps(AcDbEntity *pEntity)
- {
- ::CoInitialize(NULL);
- IAcadBaseObject *pAcadObj = get_com_wrapper(pEntity);
- CComQIPtr<ITypeLib> pTypeLib(pAcadObj);
- CComQIPtr<ITypeInfo> pTypeInfo(pAcadObj);
- TCHAR full_app_file_name[512] = L"" ;
- int nBufferLength = 512;
- TCHAR* filePart;
- DWORD result;
- result = SearchPath(NULL, _T("asdkcompoly.dbx" ),
- _T(".dbx" ), 512, full_app_file_name, &filePart);
- if (result && result < (DWORD)nBufferLength)
- {
- HRESULT hr = LoadTypeLib
- (full_app_file_name, &pTypeLib);
- if (FAILED(hr))
- return hr;
- UINT iCount = pTypeLib->GetTypeInfoCount();
- for (UINT i=0; i < iCount ; i++)
- {
- hr = pTypeLib->GetTypeInfo(i, &pTypeInfo);
- if (FAILED(hr))
- return hr;
- LoadNameCache(pTypeInfo);
- CComQIPtr<IDispatch> pDisp(pAcadObj);
- // Получение свойств
- for (int index = 0; index < m_nCount; index++)
- {
- OLECHAR *sMember = m_pMap[index].bstr;
- DISPID dispId;
- hr = pDisp->GetIDsOfNames(
- IID_NULL,
- &sMember,
- 1,
- LOCALE_SYSTEM_DEFAULT,
- &dispId);
- if (SUCCEEDED(hr))
- {
- unsigned int puArgErr = 0;
- VARIANT VarResult;
- VariantInit(&VarResult);
- EXCEPINFO pExcepInfo;
- DISPPARAMS pParams;
- memset(&pParams, 0, sizeof (DISPPARAMS));
- pParams.cArgs = 0;
- hr = pDisp->Invoke(
- dispId,
- IID_NULL,
- LOCALE_USER_DEFAULT,
- DISPATCH_PROPERTYGET,
- &pParams,
- &VarResult,
- &pExcepInfo,
- NULL);
- if (V_VT(&VarResult)
- == (VT_ARRAY | VT_R8))
- {
- // Преобразуем в ads_point
- ads_point pt;
- get_PointFromVariant(VarResult, pt);
- _print(_T("%s : %lf %lf %lf\\n" ),
- sMember, pt[0], pt[1], pt[2]);
- }
- else if (VarResult.vt == VT_DISPATCH)
- {
- _print(_T("%s : VT_DISPATCH\\n" ),
- sMember);
- //IDispatchPtr pDispatch
- // = VarResult.pdispVal;
- }
- else
- {
- hr = VariantChangeType(
- &VarResult,
- &VarResult,
- 0,
- VT_BSTR);
- _print(_T("%s : %s\\n" ),
- sMember,
- VarResult.bstrVal);
- }
- VariantClear(&VarResult);
- }
- }
- delete [] m_pMap;
- m_pMap = NULL;
- }
- }
- CoUninitialize();
- return S_OK;
- }
- // Вызываем метод dumpEntity
- void dumpEntity(AcDbEntity *pEnt)
- {
- if (_tcscmp(p, _T("AsdkPoly" )) == 0)
- dumPolyProps(pEnt);
- // ... Ну и дальнейший код
- }
Вот скриншот полученных свойств:
Обсуждение: http://adn-cis.org/forum/index.php?topic=1892
Опубликовано 24.02.2015Отредактировано 24.02.2015 в 21:12:20