• Добро пожаловать на Форум пользователей ПО АСКОН. Пожалуйста, авторизуйтесь.
 

Уважаемые пользователи,

Хотим проинформировать вас о режиме работы регистрации на нашем сайте.

Зарегистрироваться возможно в рабочие дни, с 8:00 до 20:00 (мск).

Если у вас возникнут вопросы или потребуется дополнительная информация, не стесняйтесь обращаться к нашей службе поддержки. Вы можете связаться с нами по указанным контактным данным на нашем сайте.

Благодарим вас за понимание и сотрудничество. Мы ценим ваше терпение и стремимся предоставить вам лучший опыт использования нашего сервиса.

С уважением,
Команда Ascon

Прикладная библиотека на C++ именно в VisualStudio

Автор Elisey Afanasjev, 29.03.19, 14:20:14

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

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

Elisey Afanasjev

Доброго времени суток. Я являюсь начинающим программистом с печальным опытом в создании прикладных библиотек для Компаса на C#.
Так сложились обстоятельства, что сейчас мне необходимо сделать это на С++. Прошу о помощи и инструкции, желательно подробной.
Какие головные файлы надо подключать, каким образом это делается, что добавляется в проект. В примерах SDK всё под Builder и я не могу понять почему это всё так сложно подгоняется под VIsual... Помогите, пожалуйста.

Так в SDK по нём больше всего примеров, т.к. Компас именно на нём пишется и инструкция там есть.


Denis78

Всем привет.

Начальство поставило задачу создать приложение (не dll!) на Visual C++ (не Builder!) которое бы открывало файл и "перебирало" все объекты в файле. Если использовать псевдокод, что-то вроде:

auto file = Kompas.OpenFile("C:\Users\User\Documents\qqq.m3d");
auto objects = file.GetObjects() ;
for (auto obj : objects)
{
    //что-то сделать, например, вывести в консоль
}

Посмотрел примеры. Вот одна строчка из примера Cube.cpp:
IApplicationPtr newKompasAPI;

То есть текст моего "недоприложения" таков:

#include "ksAPI7.h"

int main()
{
    IApplicationPtr newKompasAPI;
}

Хорошо, IApplicationPtr объявлен в заголовочнике ksAPI7.h, подключил его.
Компилятор выдает ошибку.

    This file requires a newer version of the header UTILCLS.H" You need to apply an update/patch to your copy of C++Builder

Какой билдер? Пр чем тут он? У меня требование под Visual C++ сделать.
В других заголовочниках IApplicationPtr не объявляется.

Как быть, подскажите, пожалуйста?

PS
Использую VS2017

Vi2

В C++ принято использовать директиву #import, для импорта содержимого библиотеки типов, например, #import "kAPI7.tlb" no_namespace named_guids.

Также есть целая папка примеров SDK\Samples\C++\Visualc, в которых можешь посмотреть примеры #include и #import.
+ Благодарностей: 1

Denis78

23.12.21, 11:56:49 #5 Последнее редактирование: 23.12.21, 12:35:43 от Rosatom
Спасибо, Vi2, #import действительно помог.
Правда, ещё пришлось путь к папке ...\SDK\lib добавить в переменную окружения PATH (что, как мне кажется, не есть хорошо, но без этого VS отказывался замечать "kAPI7.tlb", хотя в Additional Include Directory путь к нему я прописал)

После двух дней упорных, продолжительных "боев" удалось скомпилировать такую версию недопрограммы (написано по "мотивам" примера "step4")

#define _AFXDLL
#include <iostream>

#define VC_EXTRALEAN

#include <afxwin.h>

#import "ksConstants.tlb"   no_namespace named_guids
#import "ksConstants3D.tlb" no_namespace named_guids

#import "kAPI7.tlb"       rename( "KompasAPI7", "ksAPI7" ) named_guids

ksAPI7::IApplicationPtr appl;

using namespace std;

void GetNewKompasAPI()
{
    if (!(ksAPI7::IApplication*)appl)
    {
        CString filename;

        if (::GetModuleFileName(NULL, filename.GetBuffer(255), 255))
        {
            filename.ReleaseBuffer(255);
            filename = "kAPI7.dll";

            HINSTANCE hAppAuto = LoadLibrary(filename); // [1]
            if (hAppAuto)
            {
                // Указатель на функцию возвращающую интерфейс KompasApplication 
                typedef LPDISPATCH(WINAPI * FCreateKompasApplication)();

                FCreateKompasApplication pCreateKompasApplication =
                    (FCreateKompasApplication)GetProcAddress(hAppAuto, "CreateKompasApplication"); // [2]

                if (pCreateKompasApplication)
                {
                    IDispatch *p = pCreateKompasApplication();        // [3]
                    DWORD e = GetLastError();
                    cout << "Err: " << e << "\n";  // Тут печатется "Err: 0"

                    if (!p)
                        std::cout << "Nullptr\n";

                    appl = IDispatchPtr(pCreateKompasApplication(), false /*AddRef*/); // [4]
                }
                FreeLibrary(hAppAuto);
            }
        }
    }
}

int main()
{
    GetNewKompasAPI();
}


Однако радоваться было рано.
LoadLibrary() в строке [1] отрабатывает нормально.
Указатель на функцию CreateKompasApplication() в строке [2] возвращается корректно.
Но вот вызов этой функции в [3] возвращает Null вне зависимости от того, запущен Компас или нет.
Строчка [4], понятное дело, тоже бессмысленна.

Подскажите, пожалуйста, чем может быть дело?
Возможно, я сразу что-то делаю неверно, может мне, чтобы открыть Компас-файл, вообще не нужно вызывать CreateKompasApplication?

PS. Компас-3D 20.0.0.3002
Ключ защиты локальный; SL; Дата окончания лицензии 22.01.2022

3 - уже есть, в 2.
зачем - IDispatch *p = pCreateKompasApplication();        // [3] ?
Просто обрoщение к адресу p:=@pCreateKompasApplication;

Denis78

@Sabash, это вы, вероятно, на Паскале пишете?

На С++ чутка иначе, сначала получаем указатель на функцию CreateKompasApplication(), строка [2], там вызова не происходит. А уже потом вызываем эту функцию по ее указателю (по адресу), строка [3].
То есть, вызов функции происходит, но вот возвращает она NULL. Не знаю, что у нее внутри, но догадываюсь, что-то вроде:

IDispatch* CreateKompasApplication()
{
...
  if ( какое-то условие )
    return NULL;
...
}

Зайти внутрь функции и подебажится по понятным причинам нельзя.

Denis78

Небольшое дополнение.
Построил пример step4, который в SDK идет. Получил на выходе step4.rtw-файл
Попробовал добавить его в компасе, не вышло, пишет:
"Ошибка подключения приложения step4.rtw"
Никаких, естественно, подробностей больше не выдается.

Да, Паскаль.
Вроде, у Вас все правильно, но посмотрите примеры, до Step4.

Vi2

Ну вообще-то ksAPI7::IApplicationPtr appl как специализация _com_ptr_t имеет два набора методов: один (CreateInstance) создаёт экземпляр Компаса, другой (GetActiveObject) - возвращает существующий.


Хотя, если ты собрался делать rtw, то там есть какие-то стандартные операции, типа

//-----------------------------------------------------------------------------
// Провести подписку библиотеки на сообщения системы
// ---
int WINAPI LibInterfaceNotifyEntry(IDispatch * application)
{
...
}

где вот этот application и есть нужный интерфейс Компаса.

graphdark

Внезапно возникла аналогичная задача. Но ситуация обратная. Давно пишу под канпас, но плохо знаю срр. Вот для помощи нам пример: D:\C++\VisualcAUTO\kscontr\vcprj.cpp . У меня собрался, запустился, студия 2019. Пишу интерфейс кутке и свой функционал.

graphdark

Вылаживаю проект. Exe, GUI QT. По нажатию одной кнопки запускается канпас. По аналогии можно хоть небо запилить. Мне по сути надо существующий Delphi проект надо под Cрр переписать. Но описание интерфейсов ++, все эти слоты, сигналы и пр-ад после Delphi. Офигеть. Проект в zip чуть не 100Мб. Выкинул в файлошару.

Denis78

20.01.22, 15:08:01 #13 Последнее редактирование: 20.01.22, 15:21:08 от Rosatom
Я собрал и запустил проект Samples\C++\VisualcAUTO\kscontr\vcprj.sln
Появляется окно Компаса, по кнопке "Load File" есть возможность загрузить свой *.m3d файл, он открывается, это хорошо.
Напомню, что нужно "перебрать" все объекты в файле и прочитать их параметры. Если использовать псевдокод, что-то вроде:

auto objects = file.GetObjects();
for (auto obj : objects)
{
    //что-то сделать, например, вывести в консоль, записать в файл
}

Тогда я написал небольшой метод, который вызывается сразу после открытия файла, то есть

void CVcprjDlg::OnLoadFile()
{
...
    doc3D = kompas->Document3D();
    if (doc3D)
    {
        doc3D->Open((LPCTSTR)openFileDialog.GetPathName(), 0);
        OnOpen3D(doc3D);   ///////  Это мой самописный метод, который я добавил
    }
...
}

Теперь и сам метод с пояснениями внутри кода

void CVcprjDlg::OnOpen3D(ksDocument3DPtr& doc)
{
    IModelContainerPtr mCont = nullptr;
    IKompasDocument3DPtr doc3D(newKompasAPI->ActiveDocument);

    if (doc3D)
    {
        // Получаем верхний компонент
        IPart7Ptr part7(doc3D->GetTopPart());
        IModelObjectPtr mo(doc3D->GetTopPart());

        if (part7)
            mCont = IModelContainerPtr(part7);

        BSTR mat = part7->GetMaterial();                        // Здесь все хорошо, возвращается строка "Сталь 10  ГОСТ 1050-2013"
        ksObj3dTypeEnum tp = part7->GetModelObjectType();
        BSTR name = part7->GetName();                          // Здесь возвращается строка "Деталь"
        IPart7Ptr p = part7->GetPart();                        // А вот здесь плохо, p = NULL
        IPart7Ptr ps = part7->GetParts();                      // [1] Здесь тоже, ps = NULL
        ksObj3dTypeEnum tp3d = mo->ModelObjectType;
        IModelContainerPtr mos;
        HRESULT res = part7.QueryInterface(IID_IModelContainer, &mos);   // mos валидный, но как его использовать?
        ISourcePart7ParamsPtr sp7p;
        res = part7.QueryInterface(IID_ISourcePart7Params, &sp7p);       // sp7p тоже валидный, но как его использовать, я опять, не знаю

        ISurfaceContainerPtr surc;
        res = part7.QueryInterface(IID_ISurfaceContainer, &surc);       // surc валидный
       
        ICloudPointsSurfacesPtr cps = surc->GetCloudPointsSurfaces();
        if (cps)
            long cpsCnt = cps->GetCount();    // Здесь cpsCnt = 0

        IEquidistantSurfacesPtr eqs = surc->GetEquidistantSurfaces();
        if (eqs)
            long eqsCnt = eqs->GetCount();    // Здесь eqsCnt = 0

        IEvolutionPtr evs = surc->GetEvolutionSurfaces();    // Здесь evs = null
        if (evs)                                             // Соответственно, сюда не попадаем
        {
            IEdgePtr edges = evs->GetEdges();
            IPart7Ptr edgepart = edges->GetPart();
        }

        IExtensionSurfacesPtr extsur = surc->GetExtensionSurfaces();
        if (extsur)
            long extCnt = extsur->GetCount();    // extCnt = 0

        IExtrusionPtr extrsn = surc->GetExtrusionSurfaces();   // Здесь extrsn = null
        if (extrsn)
            BSTR extrsnNm = extrsn->GetName();

        ISymbols2DContainerPtr s2d;
        ISymbols3DContainerPtr s3d;
        res = part7.QueryInterface(IID_ISymbols2DContainer, &s2d);
        res = part7.QueryInterface(IID_ISymbols3DContainer, &s3d); // [2]
        if (s2d)                                                // здесь null, внутрь if на заходим
        {
            IAngleDimensionsPtr ad = s2d->GetAngleDimensions();
            IArcDimensionsPtr arcd = s2d->GetArcDimensions();
            IAxisLinesPtr axlines = s2d->GetAxisLines();
            IBasesPtr bases = s2d->GetBases();
        }
        if (s3d)                                                // [3] а вот здесь не null
        {
            IAngleDimensions3DPtr ad = s3d->GetAngleDimensions3D();     // ad валидный указатель
            IArcDimensions3DPtr arcd = s3d->GetArcDimensions3D();       // arcd валидный указатель
            IBases3DPtr bases = s3d->GetBases3D();                      // bases тоже валидный указатель
            long s3dcnt = bases->GetCount();                            // а вот s3dcnt = 0
        }

        IBilletsObsoletesPtr bo = mos->GetBilletsObsoletes();
        long boc = bo->GetCount();
        for (long i = 0; i < boc; i++)                                   // конечно, boc = 0
        {
            IBilletObsoletePtr bo1 = bo->GetBilletObsolete(i);
            BSTR boNm = bo1->GetName();
            IPart7Ptr bop = bo1->GetPart();
        }
        if (mos)
        {
            ICollectionsGeometryPtr cg = mos->GetCollectionsGeometry();
            long cnt = cg->GetCount();                                   // угадайте, чему равен cnt, правильно, нулю

            for (long i = 0; i < cnt; cnt++)
            {
                IModelObjectPtr mop = cg->GetItem(i);
                BSTR mn1 = mop->GetName();
                IPart7Ptr p7 = mop->GetPart();
                KompasAPIObjectTypeEnum tp1 = mop->GetType();
            }
        }

        IPlacement3DPtr pl = part7->GetPlacement();
        double x = -1, y = -1, z = -1;
        pl->GetVector(tp, &x, &y, &z);
        KompasAPIObjectTypeEnum ktp = pl->GetType();
        pl->GetPoint3D(2, 3, &x, &y, &z);
        ksToleranceRecalcsEnum tr = part7->GetToleranceRecalcType();
        ktp = part7->GetType();
        BSTR trn = part7->GetUserToleranceRecalcName();
        ICollectionGeometryPtr geoms = mCont->GetCollectionsGeometry();   // Указатель валидный, но полезных методов не нашел, как использовать, не знаю
        ICopiesGeometryPtr c = mCont->GetCopiesGeometry();
        long cnt = c->GetCount();
        for (long i = 0; i < cnt; i++)                                    // cnt = 0
        {
            IModelObjectPtr mo = c->GetItem(0);
            BSTR nm = mo->GetName();
            KompasAPIObjectTypeEnum t = mo->GetType();
        }
    }
}

Получается, я могу взять элемент самого верхнего уровня и он вернет какие-то осмысленные параметры, например, материал ("Сталь 10  ГОСТ 1050-2013") и название ("Деталь"). Перейти же на уровень вниз, чтобы взять другие элементы чертежа, я никак не могу. Как это можно сделать?

В справочной системе написано

Цитировать"от полученного верхнего компонента IPart7 может быть получена коллекция компонентов IParts7 с помощью свойства IPart7::Parts"

У меня в строке [1] возвращается NULL. И как дальше быть?

Цитировать"Эле­менты коллекции-компоненты могут быть получены у коллекции с помощью свойства IParts7::Part"

Это я тоже делаю, у меня этот метод тоже возвращает NULL (см на строчку выше, чем [1])

Что я делаю не так?

И, собственно о "чертеже", что я открываю. Это несколько окружностей в плоскости XZ, прямоугольник в той же плоскости и текст. Собственно, строка [2] и код внутри условия [3] был написан в надежде "выцепить" этот текст.

PS. Использую VS2017,
Компас-3D 20.0.0.3002 (64 bit)

p3452

Каша...
Цитата: Rosatom от 20.01.22, 15:08:01Появляется окно Компаса, по кнопке "Load File" есть возможность загрузить свой *.m3d файл, он открывается, это хорошо.
Напомню, что нужно "перебрать" все объекты в файле и прочитать их параметры.
Цитата: Rosatom от 20.01.22, 15:08:01И, собственно о "чертеже", что я открываю.
Разницу между 2D и 3D понимаете?
...
Цитата: Rosatom от 20.01.22, 15:08:01Собственно, строка [2] и код внутри условия [3]
У вас, что строки кода пронумерованы?
...

graphdark

Цитата: Rosatom от 20.01.22, 15:08:01Я собрал и запустил проект Samples\C++\VisualcAUTO\kscontr\vcprj.sln
Появляется окно Компаса, по кнопке "Load File" есть возможность загрузить свой *.m3d файл, он открывается, это хорошо.
Напомню, что нужно "перебрать" все объекты в файле и прочитать их параметры. Если использовать псевдокод, что-то вроде:

auto objects = file.GetObjects();
for (auto obj : objects)
{
    //что-то сделать, например, вывести в консоль, записать в файл
}

Тогда я написал небольшой метод, который вызывается сразу после открытия файла, то есть

void CVcprjDlg::OnLoadFile()
{
...
    doc3D = kompas->Document3D();
    if (doc3D)
    {
        doc3D->Open((LPCTSTR)openFileDialog.GetPathName(), 0);
        OnOpen3D(doc3D);   ///////  Это мой самописный метод, который я добавил
    }
...
}

Теперь и сам метод с пояснениями внутри кода

void CVcprjDlg::OnOpen3D(ksDocument3DPtr& doc)
{
    IModelContainerPtr mCont = nullptr;
    IKompasDocument3DPtr doc3D(newKompasAPI->ActiveDocument);

    if (doc3D)
    {
        // Получаем верхний компонент
        IPart7Ptr part7(doc3D->GetTopPart());
        IModelObjectPtr mo(doc3D->GetTopPart());

        if (part7)
            mCont = IModelContainerPtr(part7);

        BSTR mat = part7->GetMaterial();                        // Здесь все хорошо, возвращается строка "Сталь 10  ГОСТ 1050-2013"
        ksObj3dTypeEnum tp = part7->GetModelObjectType();
        BSTR name = part7->GetName();                          // Здесь возвращается строка "Деталь"
        IPart7Ptr p = part7->GetPart();                        // А вот здесь плохо, p = NULL
        IPart7Ptr ps = part7->GetParts();                      // [1] Здесь тоже, ps = NULL
        ksObj3dTypeEnum tp3d = mo->ModelObjectType;
        IModelContainerPtr mos;
        HRESULT res = part7.QueryInterface(IID_IModelContainer, &mos);   // mos валидный, но как его использовать?
        ISourcePart7ParamsPtr sp7p;
        res = part7.QueryInterface(IID_ISourcePart7Params, &sp7p);       // sp7p тоже валидный, но как его использовать, я опять, не знаю

        ISurfaceContainerPtr surc;
        res = part7.QueryInterface(IID_ISurfaceContainer, &surc);       // surc валидный
       
        ICloudPointsSurfacesPtr cps = surc->GetCloudPointsSurfaces();
        if (cps)
            long cpsCnt = cps->GetCount();    // Здесь cpsCnt = 0

        IEquidistantSurfacesPtr eqs = surc->GetEquidistantSurfaces();
        if (eqs)
            long eqsCnt = eqs->GetCount();    // Здесь eqsCnt = 0

        IEvolutionPtr evs = surc->GetEvolutionSurfaces();    // Здесь evs = null
        if (evs)                                             // Соответственно, сюда не попадаем
        {
            IEdgePtr edges = evs->GetEdges();
            IPart7Ptr edgepart = edges->GetPart();
        }

        IExtensionSurfacesPtr extsur = surc->GetExtensionSurfaces();
        if (extsur)
            long extCnt = extsur->GetCount();    // extCnt = 0

        IExtrusionPtr extrsn = surc->GetExtrusionSurfaces();   // Здесь extrsn = null
        if (extrsn)
            BSTR extrsnNm = extrsn->GetName();

        ISymbols2DContainerPtr s2d;
        ISymbols3DContainerPtr s3d;
        res = part7.QueryInterface(IID_ISymbols2DContainer, &s2d);
        res = part7.QueryInterface(IID_ISymbols3DContainer, &s3d); // [2]
        if (s2d)                                                // здесь null, внутрь if на заходим
        {
            IAngleDimensionsPtr ad = s2d->GetAngleDimensions();
            IArcDimensionsPtr arcd = s2d->GetArcDimensions();
            IAxisLinesPtr axlines = s2d->GetAxisLines();
            IBasesPtr bases = s2d->GetBases();
        }
        if (s3d)                                                // [3] а вот здесь не null
        {
            IAngleDimensions3DPtr ad = s3d->GetAngleDimensions3D();     // ad валидный указатель
            IArcDimensions3DPtr arcd = s3d->GetArcDimensions3D();       // arcd валидный указатель
            IBases3DPtr bases = s3d->GetBases3D();                      // bases тоже валидный указатель
            long s3dcnt = bases->GetCount();                            // а вот s3dcnt = 0
        }

        IBilletsObsoletesPtr bo = mos->GetBilletsObsoletes();
        long boc = bo->GetCount();
        for (long i = 0; i < boc; i++)                                   // конечно, boc = 0
        {
            IBilletObsoletePtr bo1 = bo->GetBilletObsolete(i);
            BSTR boNm = bo1->GetName();
            IPart7Ptr bop = bo1->GetPart();
        }
        if (mos)
        {
            ICollectionsGeometryPtr cg = mos->GetCollectionsGeometry();
            long cnt = cg->GetCount();                                   // угадайте, чему равен cnt, правильно, нулю

            for (long i = 0; i < cnt; cnt++)
            {
                IModelObjectPtr mop = cg->GetItem(i);
                BSTR mn1 = mop->GetName();
                IPart7Ptr p7 = mop->GetPart();
                KompasAPIObjectTypeEnum tp1 = mop->GetType();
            }
        }

        IPlacement3DPtr pl = part7->GetPlacement();
        double x = -1, y = -1, z = -1;
        pl->GetVector(tp, &x, &y, &z);
        KompasAPIObjectTypeEnum ktp = pl->GetType();
        pl->GetPoint3D(2, 3, &x, &y, &z);
        ksToleranceRecalcsEnum tr = part7->GetToleranceRecalcType();
        ktp = part7->GetType();
        BSTR trn = part7->GetUserToleranceRecalcName();
        ICollectionGeometryPtr geoms = mCont->GetCollectionsGeometry();   // Указатель валидный, но полезных методов не нашел, как использовать, не знаю
        ICopiesGeometryPtr c = mCont->GetCopiesGeometry();
        long cnt = c->GetCount();
        for (long i = 0; i < cnt; i++)                                    // cnt = 0
        {
            IModelObjectPtr mo = c->GetItem(0);
            BSTR nm = mo->GetName();
            KompasAPIObjectTypeEnum t = mo->GetType();
        }
    }
}

Получается, я могу взять элемент самого верхнего уровня и он вернет какие-то осмысленные параметры, например, материал ("Сталь 10  ГОСТ 1050-2013") и название ("Деталь"). Перейти же на уровень вниз, чтобы взять другие элементы чертежа, я никак не могу. Как это можно сделать?

В справочной системе написано

У меня в строке [1] возвращается NULL. И как дальше быть?

Это я тоже делаю, у меня этот метод тоже возвращает NULL (см на строчку выше, чем [1])

Что я делаю не так?

И, собственно о "чертеже", что я открываю. Это несколько окружностей в плоскости XZ, прямоугольник в той же плоскости и текст. Собственно, строка [2] и код внутри условия [3] был написан в надежде "выцепить" этот текст.

PS. Использую VS2017,
Компас-3D 20.0.0.3002 (64 bit)

Не совсем понял, что сделать надо. Если открыть сборку, перебрать все ее элементы и каждому присвоить или прочитать свойство, то getpart(i) где i индекс элемента в дереве от 0. Метод вернёт kspart. А у него уже куча свойств.
+ Благодарностей: 1

graphdark

Поясните, чому #import ksapi5.tlb работал, Но внезапно стал при сборке ругаться, что не нашел файл ksapi5.tlh?

graphdark

Цитата: graphdark от 23.01.22, 20:14:43Поясните, чому #import ksapi5.tlb работал, Но внезапно стал при сборке ругаться, что не нашел файл ksapi5.tlh?
PS: не вышло отредактировать, чтобы скрин приложить.Снимок.PNG

Denis78

24.01.22, 15:22:27 #18 Последнее редактирование: 24.01.22, 15:47:09 от Rosatom
Цитата: graphdark от 20.01.22, 20:55:38Не совсем понял, что сделать надо. Если открыть сборку, перебрать все ее элементы и каждому присвоить или прочитать свойство, то getpart(i) где i индекс элемента в дереве от 0. Метод вернёт kspart. А у него уже куча свойств.

Да, все правильно, Нужно открыть деталь, перебрать все ее элементы и прочитать свойства этого элемента.

Я сделал новый, с позволения сказать, чертеж. Это параллелепипед со сторонами 34х56х16, созданный путем выдавливания прямоугольника.

Затем, я переписал свой метод, дабы упростить его (поскольку там, действительно уже "каша"). Теперь выглядит он так:

void CVcprjDlg::OnOpen3D(ksDocument3DPtr& doc)
{
ksPartPtr ksp0 = doc->GetPart(0);            // И опять, к сожалению, здесь возвращается NULL
ksPartPtr ksp;
long i;

if (ksp0 == nullptr)                      // Тогда я решил перебирать все индексы, пока не "наткнусь" на валидный
{
for (i = 1; i < 100000L; ++i)
{
ksp = doc->GetPart(i);
if (ksp)
{
std::wstring dbg(L"Valid: ");
dbg += _tow(i) + L'\n';
OutputDebugStringW((LPCWSTR)dbg.data());  // Однако сюда я так и не попал
break;
}
}
}
std::wstring dbg(L"Finish: ");
dbg += _tow(i) + L'\n';
OutputDebugStringW((LPCWSTR)dbg.data());    // А здесь распечатывается i равное 100000, т.е. цикл закончился, ни одного валидного указателя не найдено
}

Что я делаю не так?
Возможно, GetPart(0) нужно от какого-то иного объекта брать, а не от ksDocument3DPtr? Но я посмотрел, больше такого метода ни у кого нет (кроме как у ksPart, но его получить не получается)

PS Пытался еще использовать метод:
ksPartCollectionPtr pcol = doc->PartCollection(true);
pcol вызвращается равным NULL (хоть true туда передавай, хоть false)

p3452

Что означает "Part" (IPart, Part, ksPart) в терминах Компаса?...
Откройте Вашу "деталь" в Компас - что написано (в скобках) в самой верхней строке Дерева (любого)?