IFeature::ModelObjects. Не могу получить доступ к данным SAFEARRAY

Автор aleras85, 14.10.22, 11:33:26

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

aleras85

Хочу получить массив граней у объекта feature класса IFeature
_variant_t facesVariant = feature->GetModelObjects(ksObjectFace);

// 1 face returned
if (facesVariant.GetVARIANT().vt == VT_DISPATCH) {
IDispatch* faceDisp = facesVariant.GetVARIANT().pdispVal;
if (faceDisp) {
IFacePtr face (faceDisp);
if (face) {
// do something
}
}
}//
// many faces returned
if (facesVariant.GetVARIANT().vt == (VT_DISPATCH | VT_ARRAY)) {
SAFEARRAY* facesSafearray = facesVariant.GetVARIANT().parray;
IDispatch* facesBegin = NULL;
HRESULT hr = SafeArrayAccessData(facesSafearray, (void**)(&facesBegin));
if (SUCCEEDED(hr) && facesBegin) {
long lBound, uBound;
if (SUCCEEDED(SafeArrayGetLBound(facesSafearray, 1, &lBound))) {
if (SUCCEEDED(SafeArrayGetUBound(facesSafearray, 1, &uBound))) {
for (int i = 0; i < uBound - lBound + 1; ++i) {
if (facesBegin + i) {
IFacePtr face(facesBegin + i);
if (face) {
// do something
}
}
}
}
}
SafeArrayUnaccessData(facesSafearray);
}
}//
Однако, на этапе доступа к данным по указателю facesBegin (при создании IFacePtr через QueryInterface) выбрасывается исключение access violation executing location, при том что указатель на данные не NULL.
В чем может быть проблема?

Slaviation

objects - это Ваш facesVariant

else if (objects.vt == (VT_ARRAY | VT_DISPATCH))
{
    SAFEARRAY *psa(objects.parray);
    long iUBound(0), iLBound(0);
    if (FAILED(SafeArrayGetUBound(psa, 1, &iUBound)) || FAILED(SafeArrayGetLBound(psa, 1, &iLBound)))
        return FALSE;

    const long count(iUBound - iLBound);
    if (!count)
        return TRUE;

    for (long i(0); i <= count; ++i)
    {
        IDispatchPtr val;
        if (FAILED(SafeArrayGetElement(psa, &i, &val)))
            continue;
    }
}

aleras85

Спасибо, теперь при получении IFacePtr исключение не выбрасывается. НО:
1. IFacePtr создается пустым (NULL)
IDispatchPtr val;
if (FAILED(SafeArrayGetElement(facesSafearray, &i, &val)))
continue;
IFacePtr face (val); // always NULL
2. Поэлементный доступ ко всем данным массива функцией SafeArrayGetElement существенно дольше, чем полный доступ функцией SafeArrayAccessData


aleras85

14.10.22, 12:54:14 #4 Последнее редактирование: 14.10.22, 13:05:16 от aleras85 Причина: update
val, конечно же, не NULL. Установлено, что результат HRESULT при вызове QueryInterface (от IDispatch к IFace) получается E_NOINTERFACE. Поэтому IFace пуст. Но такого ведь не должно быть, я же запрашивал грани:
_variant_t facesVariant = feature->GetModelObjects(ksObjectFace);

UPD: val преобразовался в IModelObject, откуда я посмотрел имена объектов массива, который мне вернулся на запрос массива граней. И имена этих объектов: Плоскость XY, Плоскость ZX, Плоскость ZY, Ось X, Ось Y, Ось Z, Начало координат...

Slaviation

Ок, хорошо, тогда можно посмотреть откуда Вы взяли feature в первой строчке ?
_variant_t facesVariant = feature->GetModelObjects(ksObjectFace);

aleras85

Сюда попадают feature, полученые от корневой детали сборки и от ее поддеталей посредством QueryInterface. У корневой детали граней конечно нет, но есть у ее поддеталей. Я ожидал следующее поведение: если у детали нет граней, то тип варианта будет VT_EMPTY, и код получения граней в таком случае не будет выполняться. Вместо этого почему-то получаю что угодно, но не грани.

Slaviation

Может feature нужно брать от формообразующих операций детали (выдавливание, вырезание и т. п.)?
+ Благодарностей: 1

aleras85

Буду пробовать брать feature от всякого... Начну с тела: IBody7

Slaviation

14.10.22, 14:12:25 #9 Последнее редактирование: 14.10.22, 14:31:09 от Slaviation
#~ Cмоделировал на Python:
#~ Создал в новой детали призму, взял формообразующую операцию, ее фичу и ее коллекцию граней

# -*- coding: utf-8 -*-
import pythoncom
from win32com.client import Dispatch, gencache
kompas6_constants_3d = gencache.EnsureModule("{2CAF168C-7961-4B90-9DA2-701419BEEFE3}", 0, 1, 0).constants
kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
kompas_api_object = kompas_api7_module.IKompasAPIObject(Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(kompas_api7_module.IKompasAPIObject.CLSID, pythoncom.IID_IDispatch))
application = kompas_api_object.Application
kompas_document = application.ActiveDocument
kompas_document_3d = kompas_api7_module.IKompasDocument3D(kompas_document)
part7 = kompas_document_3d.TopPart
model_container = kompas_api7_module.IModelContainer(part7)
extrusions = model_container.Extrusions
extrusion = extrusions.Extrusion(0) # взял формообразующую операцию
feature = kompas_api7_module.IFeature7(extrusion) # ее фичу
objects = feature.ModelObjects(kompas6_constants_3d.o3d_face) # и ее коллекцию граней
for item in objects:
    print(item)
   
# Результат:
#~ win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502423984>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502424080>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502424176>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502424272>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502424368>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2328502424464>

#~ И упростил тест
#~ Создал в новой детали призму, взял  фичу парта  и ее коллекцию граней
#~ Похоже проблема была в константе ksObjectFace

# -*- coding: utf-8 -*-
import pythoncom
from win32com.client import Dispatch, gencache
kompas6_constants_3d = gencache.EnsureModule("{2CAF168C-7961-4B90-9DA2-701419BEEFE3}", 0, 1, 0).constants
kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
kompas_api_object = kompas_api7_module.IKompasAPIObject(Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(kompas_api7_module.IKompasAPIObject.CLSID, pythoncom.IID_IDispatch))
application = kompas_api_object.Application
kompas_document = application.ActiveDocument
kompas_document_3d = kompas_api7_module.IKompasDocument3D(kompas_document)
part7 = kompas_document_3d.TopPart
feature = kompas_api7_module.IFeature7(part7) # взял  фичу парта
objects = feature.ModelObjects(kompas6_constants_3d.o3d_face) # и ее коллекцию граней
for item in objects:
    print(item)
   
# Результат:
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500496608>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500496704>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500496800>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500496896>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500496992>
#~ <win32com.gen_py.69AC2981-37C0-4379-84FD-5DD2F3C0A520x0x1x0.IFace instance at 0x2191500497088>
+ Благодарностей: 1

Vi2

Цитата: aleras85 от 14.10.22, 11:33:26IDispatch* facesBegin = NULL;
HRESULT hr = SafeArrayAccessData(facesSafearray, (void**)(&facesBegin));
В чем может быть проблема?
Ну как же так не аккуратно! Нужно определять указатель на тип, передаваемый в массиве. Если там double, то double* p и доступ к элементу *(p+i). Если там сложный тип, типа интерфейса IDispatch*, то IDispatch* *p и доступ *(p+i). *** не могу передать обращение к элементу массива в виде квадратных скобок, но см. в коде ниже.
Т.е.
IDispatch* *facesBegin = NULL;
HRESULT hr = SafeArrayAccessData(facesSafearray, (void**)(&facesBegin));
И тогда получение
IFacePtr face(facesBegin[i]);
+ Благодарностей: 1

aleras85

Действительно невнимательность. Спасибо, теперь получается корректно обращаться к данным