ObjectARX программирование на C++

Автор: | 02.02.2018

Введение
Средства разработки приложений
Установка свойств проекта
Приложение “Hello World”
Итерация таблицы символов
Открытие и закрытие объектов. Использование итераторов
Создание и добавление записи в таблицу символов
Создание и добавление объекта XRecord в Named Objects Dictionary
Использование словарей расширения (extension dictionaries)
Создание примитива и управление его свойствами
Использование AcDbGroup протокола
Тексты программ

Введение

ObjectARX (AutoCAD Runtime Extension) – это набор библиотек для разработки ARX-приложений в среде программирования Microsoft Visual C++.  ARX-приложение  работает в AutoCAD, как динамически связываемая библиотека (DLL) с файловым расширением .arx и имеет прямой доступ к графической базе данных AutoCAD. Важнейшая особенность ARX приложений заключается в том, что появилась возможность расширения AutoCAD не только за счет разработки новых команд, но также и за счет создания новых типов примитивов.

ObjectARX среда состоит из следующих групп классов и функций:

  • AcRx (acad.lib, rxapi.lib, acrxlib) – классы для создания производных классов.
  • AcEd (acad.lib, rxapi.lib, acedapi.lib, acrxlib) – классы для регистрации команд AutoCAD и для уведомления о событиях AutoCAD.
  • AcDb (acad.lib, rxapi.lib, acdblib, acrx15.lib) – классы базы данных AutoCAD.
  • AcGi (acad.lib, rxapi.lib, acgiapi.lib, acrxlib) – классы для создания графических объектов AutoCAD.
  • AcGe (acad.lib, rxapi.lib, acgelib, acrx15.lib) – сервисные классы для общей линейной алгебры и геометрического объекта.

Рисунок AutoCAD – коллекция графических объектов и внутренних конструкций типа таблиц идентификаторов и словарей, сохраненных в базе данных.

Примитив (Entity) имеет графическое представление в пределах рисунка AutoCAD – строки, круги, дуги, текст, solids, области(регионы), сплайны, и эллипсы.  Пользователь может видеть его на экране и управлять им.

Таблицы идентификаторов  – контейнеры для сохранения объектов базы данных. Примеры таблиц идентификаторов – таблица слоев (AcDbLayerTable) и таблица блоков (AcDbBlockTable). Все примитивы AutoCAD принадлежат записям таблицы блоков.

Словари обеспечивают более универсальный контейнер для сохранения объектов, чем таблицы идентификаторов. Словарь может содержать любой объект типа AcDbObject или его подкласса. Когда создается новый рисунок AutoCAD создает словарь называемый Named Object Dictionary. Этот словарь может просматриваться как “оглавление” для всех словарей, связанных с базой данных. Вы можете создавать новые словари в пределах Named Object Dictionary.

ObjectARX обеспечивает ваше приложение доступом к этим структурам базы данных. Кроме того, Вы можете создавать новую базу данных объектов для вашего приложения.

Множество баз данных (рисунков) могут быть загружены в одном сеансе AutoCAD. Каждый объект в сеансе имеет метку и ID. Метка уникально идентифицирует объект в пределах специфической базы данных. ID уникально идентифицирует объект во всех базах данных, загруженных в одно время. ID сохраняется только в течение сеанса редактирования, а метка сохраняется с рисунком. В отличие от ID объекта, метка может быть неуникальна, когда множество баз данных загружены в сеансе AutoCAD. Через ID Вы можете получить указатель на фактический объект базы данных для обеспечения исполнения операций с ним.

Чтобы быть пригодной для использования, база данных должна иметь, по крайней мере, следующий набор объектов: таблицу блоков; таблицу слоев; таблицу типов линий.

Таблица блоков первоначально содержит три записи: MODEL_SPACE, и два пространства листа, называемые PAPER_SPACE и PAPER_SPACE0. Таблица слоев содержит одну запись – слой 0. Таблица типов линий содержит тип линии CONTINUES.

Предположим, что пользователь создает отрезок с параметрами (4,2 10,7)  в пространстве MODEL_SPACE. В базе данных AutoCAD создает образец класса AcDbLine и затем сохраняет его в таблице блоков.

Следующий код создает объект Line и прибавляет его к таблице блоков пространства модели:

AcDbObjectId createLine()
{
AcGePoint3d startPt(4.0, 2.0, 0.0);
AcGePoint3d endPt(10.0, 7.0, 0.0);
AcDbLine *pLine = new AcDbLine(startPt, endPt);
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable (pBlockTable, AcDb::kForRead);
AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);
pBlockTable->close();
AcDbObjectId lineId;
pBlockTableRecord->appendAcDbEntity(lineId, pLine);
pBlockTableRecord->close();
pLine->close();
return lineId;
}

Сначала получаем таблицу блоков для текущего рисунка. Затем открываем в пространстве MODEL_SPACE запись таблицы блоков и прибавляем объект к таблице, затем закрываем таблицу и объект.

Теперь, предположим, что пользователь создает окружность с параметрами ((9,3) 2). Снова AutoCAD создает образец соответствующего объекта (AcDbCircle) и прибавляет его к пространству модели.

Следующий код создает окружность и прибавляет ее к таблице блоков в пространстве модели:

pBlockTableRecord->appendAcDbEntity(circleId, pCirc);
pBAcDbObjectId createCircle()
{
AcGePoint3d center(9.0, 3.0, 0.0);
AcGeVector3d normal(0.0, 0.0, 1.0);
AcDbCircle *pCirc = new AcDbCircle(center, normal, 2.0);
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable, AcDb::kForRead);
AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,
AcDb::kForWrite);
pBlockTable->close();
AcDbObjectId circleId;
lockTableRecord->close();
pCirc->close();
return circleId;
}

Затем, пользователь создает слой mylayer, AutoCAD создает новую запись таблицы слоя и добавляет ее в таблицу слоев.

Следующий код получает таблицу идентификаторов слоя от базы данных и создает новую запись таблицы слоя ASDK_MYLAYER:

void createNewLayer()
{
AcDbLayerTable *pLayerTable;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pLayerTable, AcDb::kForWrite);
AcDbLayerTableRecord *pLayerTableRecord = new AcDbLayerTableRecord;
pLayerTableRecord->setName("ASDK_MYLAYER");
// Defaults are used for other properties of
// the layer if they are not otherwise specified.
//
pLayerTable->add(pLayerTableRecord);
pLayerTable->close();
pLayerTableRecord->close();
}

Наконец, группируем все объекты вместе (group 3,2 9,3). AutoCAD создает новую группу и прибавляет ее к словарю GROUP который содержится в объектном словаре имен (Named Object Dictionary). Новая группа содержит список ID объектов, которые составляют группу.

Cледующий код создает группу pGroup из объектов Line и Circle в методах createLine () и createCircle (), и помещает группу в словарь. Обратите внимание, как словарь открывается для записи, изменяется, и затем явно закрывается.

void createGroup(AcDbObjectIdArray& objIds, char* pGroupName)
{
AcDbGroup *pGroup = new AcDbGroup(pGroupName);
for (int i = 0; i < objIds.length(); i++) {
pGroup->append(objIds[i]);
}
// Put the group in the group dictionary that resides
// in the named object dictionary.
//
AcDbDictionary *pGroupDict;
acdbHostApplicationServices()->workingDatabase()->getGroupDictionary(pGroupDict, AcDb::kForWrite);
AcDbObjectId pGroupId;
pGroupDict->setAt(pGroupName, pGroup, pGroupId);
pGroupDict->close();
pGroup->close();
}

Все примеры кода иллюстрируют протокол для открытия и закрытия объектов, который Вы будете должны соблюсти всякий раз, когда Вы работаете с объектами резидента-базы. Этот протокол гарантирует, что объекты находятся физически в памяти, когда к ним обращаются. Прежде, чем Вы предполагаете изменять объект, Вы должны открыть его. Функции имеют параметр, который определяет, открываете ли Вы объект для чтения, записи или уведомления. В то время как объект открыт для записи, Вы можете изменять его. Когда закончите, Вы должны явно закрыть объект. Ниже приведен типовой код для изменения цвета объекта:

Acad::ErrorStatus
changeColor(AcDbObjectId entId, Adesk::UInt16 newColor)
{
AcDbEntity *pEntity;
acdbOpenObject(pEntity, entId,AcDb::kForWrite);
pEntity->setColorIndex(newColor);
pEntity->close();
return Acad::eOk;
}

Средства разработки приложений

Для каждой версии  AutoCAD выпускается соответствующая версия пакета  ObjectARX .  При этом для разработки ARX приложений для разных версий  AutoCAD требуются строго определенные версии Visual Studio. Ниже приводится список значений параметра Platform Toolset, который должен быть установлен в свойствах проекта приложения:

Platform Toolset «v100» доступен из выпадающего списка в окне свойств проекта Visual Studio 2012 если, также, и Visual Studio 2010 инсталлирован. Аналогично Platform Toolset «v110» доступен из Visual Studio 2013, если и Visual Studio 2012 инсталлирован.

Установка свойств проекта

В Visual Studio создайте пустой  Win32 проект для DLL с именем First и установите свойства проекта в соответствии с рисунками.

Приложение “Hello World

Добавьте в проект First 2 файла:  Source.cpp и Source.def.

Файл Source.cpp

#include <aced.h>
#include <rxregsvc.h>
void initApp();
void unloadApp();
void helloWorld();
void initApp()
{ // register a command with the AutoCAD command mechanism
acedRegCmds->addCommand(L"HELLOWORLD_COMMANDS",
L"Hello",
L"Bonjour",
ACRX_CMD_TRANSPARENT,
helloWorld);
}
void unloadApp()
{
acedRegCmds->removeGroup(L"HELLOWORLD_COMMANDS");
}
void helloWorld()
{
acutPrintf(L"\nHello World!");
}
extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
switch (msg)
{
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(pkt);
acrxRegisterAppMDIAware(pkt);
initApp();
break;
case AcRx::kUnloadAppMsg:
unloadApp();
break;
default:
break;
}
return AcRx::kRetOK;
}

Файл Source.def

EXPORTS
acrxEntryPoint PRIVATE
acrxGetApiVersion PRIVATE

Выберите в Visual Studio кнопки меню Build>Build First. После успешной трансляции в директории First>x64>Debug появится файл First.arx. Загрузите в AutoCAD файл First.arx (команда ARX) и запустите команду Hello (или Bonjour). В ответ получите сообщение “Hello World!”.

initApp – функция вызывается, когда приложение загружается;В приложении (см. файл Source.cpp) вначале подключаются ObjetARX основные файлы: aced.h (определенные редактором услуги) и rxregsvc.h (для сервисных ARX функций). Затем объявляются три функции:

unloadApp – функция вызывается, когда приложение выгружается;

helloWorld – функция, которая обеспечивает печать “Hello World!”.

Далее определяется функция initApp. Эта функция регистрирует новую команду в системе команд AutoCAD. Информацию относительно acedRegCmds макроса и addCommand () метода (AcEdCommandStack класса), можно получить из ObjectARX справки.

Первый аргумент addCommand () – название группы команд (в нашем случае в группу включена только одна команда). Второй аргумент – глобальное имя команды. Третий аргумент – местное имя для той же самой команды. Четвертый аргумент – флаг команды (определяется прозрачная команда – может быть вызвана, когда другая команда активна). Последний аргумент – указатель на вызываемую нашей командой функцию.

Следующей определяется функция unloadApp. Эта функция удалит группу команд «HELLOWORLD_COMMANDS» (а вместе с ней и команду Hello), когда приложение выгружается из AutoCAD.

После этого в коде программы определяется функция helloWorld. В теле данной функции используется функция acutPrintf, которая является эквивалентом LISP-функции printf.

Далее определяется наиболее важная для ObjectARX приложений функция acrxEntryPoint. AutoCAD вызывает acrxEntryPoint функцию, чтобы передать сообщения приложению. AutoCAD звонит в ObjectARX модуль через acrxEntryPoint (), которая заменяет main() программы C++.

Первый параметр acrxEntryPoint () – элемент данных AcRx класса (называемого msg), который представляет сообщение, посланное от ObjectARX ядра к приложению (обратитесь к справке, чтобы получить более подробную информацию о различных сообщениях, которые ObjectARX приложение может получать от AutoCAD). В нашем простейшем примере приложение должно быть уведомлено, когда оно загружено и выгружено, чтобы регистрировать и «вычеркивать из списка» команду hello. В первом случае вызывается initApp функция; во втором случае вызывается unloadApp функция.

Второй параметр acrxEntryPoint () управляет различными функциями доступа к данным (типа lock и unlock) – в зависимости от сообщения, которое поступает от AutoCAD. По умолчанию приложения замкнуты, т.е. после загрузки они не могут быть выгружены.

Так как наше приложение очень простое (оно не определяет объекты, на которые AutoCAD и другие приложения ссылаются) мы можем без опасений определять его незамкнутым. Это позволяет выгружать наше приложение с помощью функции unloadApp. Также по умолчанию, ObjectARX приложения  не используют MDI (обратитесь к справке для детальной информации по проблемам MDI). Для регистрации MDI в приложении используется глобальная функция acrxRegisterAppMDIAware.

Чтобы AutoCAD смог получить доступ к функции acrxEntryPoint необходимо экспортировать её. Для этого определяется файл с расширением .def. Все ObjectARX приложения должны экспортировать, по крайней мере, две функции: acrxEntryPoint и acrxGetApiVersion (см. файл Source.def).

Итерация таблицы символов

Ниже приводится приложение, которое демонстрирует итерацию таблицы типов полилинии. Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текстовку из файла  2_tbliter_dg.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Запустите команду ITERATE.

 

Открытие и закрытие объектов. Использование итераторов

Ниже приводится приложение, которое демонстрирует итерацию по вершинам  примитива AcDb2dPolyline. При этом реализуется открытие и закрытие объектов – полилинии и ее вершин.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текстовку из файла  3_pliniter_dg.txt.

Для тестирования приложения выполните следующие шаги:

  1. Установите системную переменную PLINETYPE=0.
  2. Создайте полилинию.
  3. Выгрузите предыдущую и загрузите обновленную библиотеку First.arx.
  4. Запустите команду ITERATE.

 

Создание и добавление записи в таблицу символов

Ниже приводится приложение, которое демонстрирует создание и добавление записи в  таблицу слоев.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текстовку из файла  4_tablerec_dg.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Запустите команду ADDLAYER и раскройте диалоговое окно “Диспетчер свойств слоев”.

Создание и добавление объекта XRecord в Named Objects Dictionary

Ниже приводится приложение, которое демонстрирует создание и добавление объекта XRecord в словарь объектов и возможность просмотра этого объекта из словаря объектов.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текстовку из файла    5_XRecord.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Запустите команды ASDK_CREATE и ASDK_LISTXREC.

Использование словарей расширения (extension dictionaries)

Ниже приводится приложение, которое демонстрирует создание и добавление объекта XRecord в словарь расширения выбранного пользователем объекта.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текст из файла  6_extension dictionaries.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Нарисуйте любой примитив, например, окружность. Запустите команду CREATE и укажите на  нарисованный примитив. При этом будет создан словарь расширений и в нем будет размещена запись о выбранном примитиве.  Запустите команду LISTXREC, укажите на  нарисованный примитив,  При этом будет напечатана запись о выбранном примитиве из словаря расширений.

Создание примитива и управление его свойствами

Ниже приводится приложение, которое демонстрирует создание mesh объекта с ячейками сети различного цвета. В приложении создается класс, производный от класса AcDbEntity, в нем переопределяются виртуальные функции.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текст из файла  7_ASDKMAKEMESH.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Запустите команду ASDKMAKEMESH.

 

Использование AcDbGroup протокола

Ниже приводится приложение, которое демонстрирует использование AcDbGroup протокола.

Модифицируйте проект приложения First. Для этого замените код файла Source.cpp  на текст из файла  8_ASDK_GROUPTEST.txt.

Для тестирования приложения выгрузите из чертежа предыдущую и загрузите обновленную библиотеку  First.arx. Выполните чертеж из нескольких примитивов, включая отрезки. Запустите команду GROUPTST. На запрос команды выберите набор объектов, который включает, по крайней мере, один отрезок. Из выбранного набора отрезки должны выделиться красным цветом.

При запуске команды GROUPTST подсказка предлагает пользователю выбрать несколько примитивов, которые помещаются в группу «ASDK_GROUPTEST». Затем в программе вызывается функция removeAllButLines(), чтобы провести итерацию группы и удалить все примитивы, которые не являются отрезками. Для оставшихся в группе примитивов устанавливается красный цвет.

Тексты программ

2_tbliter_dg.txt

#include <stdlib.h>
#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbsymtb.h>
#include <dbapserv.h>
#include <adslib.h>
#include "tchar.h"
void iterateLinetypes();
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// Opens the linetype table and iterates through all the
// entries printing the name of each linetype.
// 
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
//
void
iterateLinetypes()
{
 AcDbLinetypeTable *pLinetypeTbl;
 acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pLinetypeTbl, AcDb::kForRead);
// Create a new iterator that starts at table
 // beginning and skips deleted.
 //
 AcDbLinetypeTableIterator *pLtIterator;
 pLinetypeTbl->newIterator(pLtIterator);
// Walk the table, getting every table record and
 // printing the linetype name.
 //
 AcDbLinetypeTableRecord *pLtTableRcd;
 const TCHAR *pLtName;
 for (; !pLtIterator->done(); pLtIterator->step()) {
 pLtIterator->getRecord(pLtTableRcd, AcDb::kForRead);
 pLtTableRcd->getName(pLtName);
 pLtTableRcd->close();
 acutPrintf(_T("\nLinetype name is: %s"), pLtName);
 }
 delete pLtIterator;
 pLinetypeTbl->close();
}
// END CODE APPEARING IN SDK DOCUMENT.
// Initialization function called from acrxEntryPoint during
// kInitAppMsg case. This function is used to add commands
// to the command stack.
// 
void
initApp()
{
 acedRegCmds->addCommand(_T("ASDK_TABLETEST_COMMANDS"),
 _T("ASDK_ITERATE"), _T("ITERATE"), ACRX_CMD_MODAL,
 iterateLinetypes);
}
// Clean up function called from acrxEntryPoint during the
// kUnloadAppMsg case. This function removes this apps
// command set from the command stack.
// 
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_TABLETEST_COMMANDS"));
}
// ARX entry point
//
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

3_pliniter_dg.txt

#include <stdlib.h>
#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbents.h>
#include <adslib.h>
#include <geassign.h>
#include "tchar.h"
void listPline();
void iterate(AcDbObjectId id);
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// This is the main function of this app. It allows the
// user to select an entity. It then checks to see if the
// entity is a 2d-polyline. If so, then it calls iterate
// passing in the objectId of the pline.
// 
void
listPline()
{
 int rc;
 ads_name en;
 AcGePoint3d pt;
 rc = acedEntSel(_T("\nSelect a polyline: "), en,
 asDblArray(pt));
if (rc != RTNORM) {
 acutPrintf(_T("\nError during object selection"));
 return;
 }
AcDbObjectId eId;
 acdbGetObjectId(eId, en);
AcDbObject *pObj;
 acdbOpenObject(pObj, eId, AcDb::kForRead);
 if (pObj->isKindOf(AcDb2dPolyline::desc())) {
 pObj->close();
 iterate(eId);
 }
 else {
 pObj->close();
 acutPrintf(_T("\nSelected entity is not an AcDb2dPolyline. \nMake sure the setvar PLINETYPE is set to 0 before createing a polyline"));
 }
}
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
// Accepts the object ID of an AcDb2dPolyline, opens it, and gets
// a vertex iterator. It then iterates through the vertices,
// printing out the vertex location.
// 
void
iterate(AcDbObjectId plineId)
{
 AcDb2dPolyline *pPline;
 acdbOpenObject(pPline, plineId, AcDb::kForRead);
AcDbObjectIterator *pVertIter = pPline->vertexIterator();
 pPline->close(); // Finished with the pline header.
AcDb2dVertex *pVertex;
 AcGePoint3d location;
 AcDbObjectId vertexObjId;
 for (int vertexNumber = 0; !pVertIter->done();
 vertexNumber++, pVertIter->step())
 {
 vertexObjId = pVertIter->objectId();
 acdbOpenObject(pVertex, vertexObjId,
 AcDb::kForRead);
 location = pVertex->position();
 pVertex->close();
acutPrintf(_T("\nVertex #%d's location is")
 _T(" : %0.3f, %0.3f, %0.3f"), vertexNumber,
 location[X], location[Y], location[Z]);
 }
 delete pVertIter;
}
// END CODE APPEARING IN SDK DOCUMENT.
// Initialization function called from acrxEntryPoint during
// kInitAppMsg case. This function is used to add commands
// to the command stack.
// 
void
initApp()
{
 acedRegCmds->addCommand(_T("ASDK_PLINETEST_COMMANDS"),
 _T("ASDK_ITERATE"), _T("ITERATE"), ACRX_CMD_MODAL,
 listPline);
}// Clean up function called from acrxEntryPoint during the
// kUnloadAppMsg case. This function removes this apps
// command set from the command stack.
// 
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_PLINETEST_COMMANDS"));
}
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

4_tablerec_dg.txt

#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbsymtb.h>
#include <dbapserv.h>
#include <adslib.h>
#include "tchar.h"
void addLayer();
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// This function creates a new AcDbLayerTableRecord, fills
// it in, and adds it to the layer table
// 
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
//
void
addLayer()
{
 AcDbLayerTable *pLayerTbl;
 acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pLayerTbl, AcDb::kForWrite);
if (!pLayerTbl->has(_T("ASDK_TESTLAYER"))) {
 AcDbLayerTableRecord *pLayerTblRcd
 = new AcDbLayerTableRecord;
 pLayerTblRcd->setName(_T("ASDK_TESTLAYER"));
 pLayerTblRcd->setIsFrozen(0);// layer to THAWED
 pLayerTblRcd->setIsOff(0); // layer to ON
 pLayerTblRcd->setVPDFLT(0); // viewport default
 pLayerTblRcd->setIsLocked(0);// un-locked
AcCmColor color;
 color.setColorIndex(1); // set color to red
 pLayerTblRcd->setColor(color);
// For linetype, we need to provide the object ID of
 // the linetype record for the linetype we want to
 // use. First, we need to get the object ID.
 //
 AcDbLinetypeTable *pLinetypeTbl;
 AcDbObjectId ltId;
 acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pLinetypeTbl, AcDb::kForRead);
 if ((pLinetypeTbl->getAt(_T("DASHED"), ltId))
 != Acad::eOk)
 {
 acutPrintf(_T("\nUnable to find DASHED")
 _T(" linetype. Using CONTINUOUS"));
// CONTINUOUS is in every drawing, so use it.
 //
 pLinetypeTbl->getAt(_T("CONTINUOUS"), ltId);
 }
 pLinetypeTbl->close();
pLayerTblRcd->setLinetypeObjectId(ltId);
 pLayerTbl->add(pLayerTblRcd);
 pLayerTblRcd->close();
 pLayerTbl->close();
 }
 else {
 pLayerTbl->close();
 acutPrintf(_T("\nlayer already exists"));
 }
}
// END CODE APPEARING IN SDK DOCUMENT.
// Initialization function called in acrxEntryPoint during
// the kInitAppMsg case. This is where commands are added
// to the AcEd command stack.
// 
void
initApp()
{
 acedRegCmds->addCommand(_T("ASDK_TABLETEST_COMMANDS"),
 _T("ASDK_ADDLAYER"), _T("ADDLAYER"), ACRX_CMD_MODAL,
 addLayer);
}
// Clean up function called in acrxEntryPoint during the
// kUnloadAppMsg case. This app's command group is removed
// from the AcEd command stack.
// 
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_TABLETEST_COMMANDS"));
}
// ARX entry point.
//
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

5_XRecord.txt

#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbsymtb.h>
#include <dbapserv.h>
#include <adslib.h>
#include "tchar.h"
void addLayer();
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// This function creates a new AcDbLayerTableRecord, fills
// it in, and adds it to the layer table
// 
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
//
void
addLayer()
{
 AcDbLayerTable *pLayerTbl;
 acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pLayerTbl, AcDb::kForWrite);
if (!pLayerTbl->has(_T("ASDK_TESTLAYER"))) {
 AcDbLayerTableRecord *pLayerTblRcd
 = new AcDbLayerTableRecord;
 pLayerTblRcd->setName(_T("ASDK_TESTLAYER"));
 pLayerTblRcd->setIsFrozen(0);// layer to THAWED
 pLayerTblRcd->setIsOff(0); // layer to ON
 pLayerTblRcd->setVPDFLT(0); // viewport default
 pLayerTblRcd->setIsLocked(0);// un-locked
AcCmColor color;
 color.setColorIndex(1); // set color to red
 pLayerTblRcd->setColor(color);
// For linetype, we need to provide the object ID of
 // the linetype record for the linetype we want to
 // use. First, we need to get the object ID.
 //
 AcDbLinetypeTable *pLinetypeTbl;
 AcDbObjectId ltId;
 acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pLinetypeTbl, AcDb::kForRead);
 if ((pLinetypeTbl->getAt(_T("DASHED"), ltId))
 != Acad::eOk)
 {
 acutPrintf(_T("\nUnable to find DASHED")
 _T(" linetype. Using CONTINUOUS"));
 // CONTINUOUS is in every drawing, so use it.
 //
 pLinetypeTbl->getAt(_T("CONTINUOUS"), ltId);
 }
 pLinetypeTbl->close();
pLayerTblRcd->setLinetypeObjectId(ltId);
 pLayerTbl->add(pLayerTblRcd);
 pLayerTblRcd->close();
 pLayerTbl->close();
 } else {
 pLayerTbl->close();
 acutPrintf(_T("\nlayer already exists"));
 }
}
// END CODE APPEARING IN SDK DOCUMENT.
// Initialization function called in acrxEntryPoint during
// the kInitAppMsg case. This is where commands are added
// to the AcEd command stack.
// 
void
initApp()
{
 acedRegCmds->addCommand(_T("ASDK_TABLETEST_COMMANDS"),
 _T("ASDK_ADDLAYER"), _T("ADDLAYER"), ACRX_CMD_MODAL,
 addLayer);
}
// Clean up function called in acrxEntryPoint during the
// kUnloadAppMsg case. This app's command group is removed
// from the AcEd command stack.
// 
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_TABLETEST_COMMANDS"));
}
// ARX entry point.
//
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

6_extension dictionaries.txt

#include <stdlib.h>
#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbsymtb.h>
#include <adslib.h>
#include <dbxrecrd.h>
#include <acestext.h>
#include "tchar.h"
void createXrecord();
void listXrecord();
AcDbObject* selectObject(AcDb::OpenMode);
void printList(struct resbuf* pBuf);
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// The createXrecord() functions creates an xrecord object, 
// adds data to it, and then adds the xrecord to the extension 
// dictionary of a user selected object.
// 
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
//
void
createXrecord()
{
 AcDbXrecord *pXrec = new AcDbXrecord;
 AcDbObject *pObj;
 AcDbObjectId dictObjId, xrecObjId;
 AcDbDictionary* pDict;
pObj = selectObject(AcDb::kForWrite);
 if (pObj == NULL) {
 return;
 }
// Try to create an extension dictionary for this
 // object. If the extension dictionary already exists,
 // this will be a no-op.
 // 
 pObj->createExtensionDictionary();
// Get the object ID of the extension dictionary for the
 // selected object.
 // 
 dictObjId = pObj->extensionDictionary();
 pObj->close();
// Open the extension dictionary and add the new
 // xrecord to it.
 //
 acdbOpenObject(pDict, dictObjId, AcDb::kForWrite);
 pDict->setAt(_T("ASDK_XREC1"), pXrec, xrecObjId);
 pDict->close();
// Create a resbuf list to add to the xrecord.
 //
 struct resbuf* head;
 ads_point testpt = {1.0, 2.0, 0.0};
 head = acutBuildList(AcDb::kDxfText,
 _T("This is a test Xrecord list"),
 AcDb::kDxfXCoord, testpt,
 AcDb::kDxfReal, 3.14159,
 AcDb::kDxfAngle, 3.14159,
 AcDb::kDxfColor, 1,
 AcDb::kDxfInt16, 180,
 0);
// Add the data list to the xrecord. Notice that this
 // member function takes a reference to a resbuf NOT a
 // pointer to a resbuf, so you must dereference the
 // pointer before sending it.
 // 
 pXrec->setFromRbChain(*head);
 pXrec->close();
 acutRelRb(head);
}
// The listxrecord() functions gets the xrecord associated with the 
// key "ASDK_XREC1" and lists out its contents by passing the resbuf 
// list to the function printList().
// 
void
listXrecord()
{
 AcDbObject *pObj;
 AcDbXrecord *pXrec;
 AcDbObjectId dictObjId;
 AcDbDictionary *pDict;
pObj = selectObject(AcDb::kForRead);
 if (pObj == NULL) {
 return;
 }
 // Get the object ID of the object's extension dictionary.
 //
 dictObjId = pObj->extensionDictionary();
 pObj->close();
// Open the extension dictionary and get the xrecord
 // associated with the key ASDK_XREC1.
 // 
 acdbOpenObject(pDict, dictObjId, AcDb::kForRead);
 pDict->getAt(_T("ASDK_XREC1"), (AcDbObject*&)pXrec,
 AcDb::kForRead);
 pDict->close();
// Get the xrecord's data list and then close the xrecord.
 //
 struct resbuf *pRbList;
 pXrec->rbChain(&pRbList);
 pXrec->close();
printList(pRbList);
 acutRelRb(pRbList);
}
// END CODE APPEARING IN SDK DOCUMENT.
// The selectObject() function prompts the user to select an 
// entity or enter an object's handle. It then proceeds to 
// open the object/entity and return a pointer to it.
// 
AcDbObject*
selectObject(AcDb::OpenMode openMode)
{
 ads_name en;
 ads_point pt;
 TCHAR handleStr[132];
 AcDbObjectId eId;
Acad::ErrorStatus retStat;
 int ss;
// Allow user to either pick an entity,
 // or type in the object handle.
 //
 acedInitGet(RSG_OTHER, _T("Handle _Handle"));
 ss = acedEntSel(_T("\nSelect an Entity or enter")
 _T(" 'H' to enter its handle: "), en, pt);
switch (ss) {
 case RTNORM: // got it!
 break;
 case RTKWORD:
 if ((acedGetString(Adesk::kFalse,
 _T("Enter Valid Object Handle: "),
 handleStr) == RTNORM)
 && (acdbHandEnt(handleStr, en) == RTNORM))
 {
 break;
 }
 // Fall-through intentional
 //
 default:
 acutPrintf(_T("Nothing Selected, Return Code==%d\n"),
 ss);
 return NULL;
 }
// Now, exchange the ads_name for the object Id...
 //
 retStat = acdbGetObjectId(eId, en);
 if (retStat != Acad::eOk) {
 acutPrintf(_T("\nacdbGetObjectId failed"));
 acutPrintf(_T("\nen==(%lx,%lx), retStat==%d\n"),
 en[0], en[1], eId.asOldId());
 return NULL;
 }
AcDbObject* pObj;
if ((retStat = acdbOpenObject(pObj, eId, openMode))
 != Acad::eOk)
 {
 acutPrintf(_T("acdbOpenEntity failed: ename:")
 _T("(%lx,%lx), mode:%d retStat:%d"), en[0],
 en[1], openMode, retStat);
 return NULL;
 }
 return pObj;
}
// The printList() function takes a linked list of resbufs 
// as an argument. Walks the list printing out the restypes 
// and resval values one set per line.
// 
void
printList(struct resbuf* pBuf)
{
 int rt, i;
 TCHAR buf[133];
for (i = 0;pBuf != NULL;i++, pBuf = pBuf->rbnext) {
 if (pBuf->restype < 0)
 rt = pBuf->restype;
 else if (pBuf->restype < 10)
 rt = RTSTR;
 else if (pBuf->restype < 38)
 rt = RT3DPOINT;
 else if (pBuf->restype < 60)
 rt = RTREAL;
 else if (pBuf->restype < 80)
 rt = RTSHORT;
 else if (pBuf->restype < 100)
 rt = RTLONG;
 else if (pBuf->restype < 106)
 rt = RTSTR;
 else if (pBuf->restype < 148)
 rt = RTREAL;
 else if (pBuf->restype < 290)
 rt = RTSHORT;
 else if (pBuf->restype < 330)
 rt = RTSTR;
 else if (pBuf->restype < 370)
 rt = RTENAME;
 else if (pBuf->restype < 999)
 rt = RT3DPOINT;
 else
 rt = pBuf->restype;
switch (rt) {
 case RTSHORT:
 if (pBuf->restype == RTSHORT)
 acutPrintf(_T("RTSHORT : %d\n"),
 pBuf->resval.rint);
 else
 acutPrintf(_T("(%d . %d)\n"), pBuf->restype,
 pBuf->resval.rint);
 break;
 case RTREAL:
 if (pBuf->restype == RTREAL)
 acutPrintf(_T("RTREAL : %0.3f\n"),
 pBuf->resval.rreal);
 else
 acutPrintf(_T("(%d . %0.3f)\n"), pBuf->restype,
 pBuf->resval.rreal);
 break;
 case RTSTR:
 if (pBuf->restype == RTSTR)
 acutPrintf(_T("RTSTR : %s\n"),
 pBuf->resval.rstring);
 else
 acutPrintf(_T("(%d . \"%s\")\n"), pBuf->restype,
 pBuf->resval.rstring);
 break;
 case RT3DPOINT:
 if (pBuf->restype == RT3DPOINT)
 acutPrintf(
 _T("RT3DPOINT : %0.3f, %0.3f, %0.3f\n"),
 pBuf->resval.rpoint[X],
 pBuf->resval.rpoint[Y],
 pBuf->resval.rpoint[Z]);
 else
 acutPrintf(
 _T("(%d %0.3f %0.3f %0.3f)\n"),
 pBuf->restype,
 pBuf->resval.rpoint[X],
 pBuf->resval.rpoint[Y],
 pBuf->resval.rpoint[Z]);
 break;
 case RTLONG:
 acutPrintf(_T("RTLONG : %dl\n"),
 pBuf->resval.rlong);
 break;
 case -1:
 case RTENAME:
 acutPrintf(_T("(%d . <Entity name: %8lx>)\n"),
 pBuf->restype, pBuf->resval.rlname[0]);
 break;
 case -3:
 acutPrintf(_T("(-3)\n"));
 }
if ((i == 23) && (pBuf->rbnext != NULL)) {
 i = 0;
 acedGetString(0,
 _T("Press <ENTER> to continue..."), buf);
 }
 }
 return;
}
// Initialization function called in acrxEntryPoint
// during the kInitAppMsg case. This is where commands
// are added to the AcEd command stack.
// 
void
initApp()
{
 acedRegCmds->addCommand(_T("ASDK_EXTDICT_COMMANDS"),
 _T("ASDK_CREATE"), _T("CREATE"), ACRX_CMD_MODAL,
 createXrecord);
 acedRegCmds->addCommand(_T("ASDK_EXTDICT_COMMANDS"),
 _T("ASDK_LISTXREC"), _T("LISTXREC"), ACRX_CMD_MODAL,
 listXrecord);
}
// Clean up function called in acrxEntryPoint during the
// kUnloadAppMsg case. This app's command group is
// removed from the AcEd command stack.
// 
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_EXTDICT_COMMANDS"));
}
// ARX entry point.
//
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

7_ASDKMAKEMESH.txt

#include "aced.h"
#include "dbsymtb.h"
#include "dbapserv.h"
#include "acgi.h"
#include "tchar.h"
// Helpful Color constants for setting attributes:
//
static const Adesk::UInt16 kColorByBlock = 0;
static const Adesk::UInt16 kRed = 1;
static const Adesk::UInt16 kYellow = 2;
static const Adesk::UInt16 kGreen = 3;
static const Adesk::UInt16 kCyan = 4;
static const Adesk::UInt16 kBlue = 5;
static const Adesk::UInt16 kMagenta = 6;
static const Adesk::UInt16 kWhite = 7;
static const Adesk::UInt16 kColorByLayer = 256;
class AsdkMeshSamp: public AcDbEntity
{
public:
 ACRX_DECLARE_MEMBERS(AsdkMeshSamp);
 AsdkMeshSamp(); 
 ~AsdkMeshSamp();
protected:
 virtual Adesk::Boolean subWorldDraw(AcGiWorldDraw *);
 Acad::ErrorStatus subTransformBy(const AcGeMatrix3d &);
};
ACRX_DXF_DEFINE_MEMBERS(AsdkMeshSamp, AcDbEntity, 
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0,\
 ASDKMESHSAMP, AcGiMesh Sample);
AsdkMeshSamp::AsdkMeshSamp()
{}
AsdkMeshSamp::~AsdkMeshSamp()
{}
Acad::ErrorStatus
AsdkMeshSamp::subTransformBy(const AcGeMatrix3d &xfm)
{
 return Acad::eOk;
}
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT. 
Adesk::Boolean
AsdkMeshSamp::subWorldDraw(AcGiWorldDraw* pW)
{
 Adesk::UInt32 i, j, k;
 Adesk::UInt32 numRows = 4;
 Adesk::UInt32 numCols = 4;
 AcGePoint3d *pVerts =
 new AcGePoint3d[numRows * numCols];
for (k = 0, i = 0; i < numRows; i++) {
 for (j = 0; j < numCols; j++, k++) {
 pVerts[k].x = (double)j;
 pVerts[k].y = (double)i;
 pVerts[k].z = 0.;
 }
 }
// Construct an array of colors to be applied to each
 // edge of the mesh. Here, let the rows be cyan and
 // the columns be green.
 //
 AcGiEdgeData edgeInfo;
 Adesk::UInt32 numRowEdges = numRows * (numCols - 1);
 Adesk::UInt32 numColEdges = (numRows - 1) * numCols;
 Adesk::UInt32 numEdges = numRowEdges + numColEdges;
 short *pEdgeColorArray = new short[numEdges];
 for (i = 0; i < numEdges; i++) {
 pEdgeColorArray[i] = 
 i < numRowEdges ? kCyan : kGreen;
 }
 edgeInfo.setColors(pEdgeColorArray);
// Make the first face transparent and the rest
 // different colors.
 //
 Adesk::UInt32 numFaces = (numRows - 1) 
 * (numCols - 1);
 Adesk::UInt8 *pFaceVisArray =
 new Adesk::UInt8[numFaces];
 short *pFaceColorArray = new short[numFaces];
 AcGiFaceData faceInfo;
 faceInfo.setVisibility(pFaceVisArray);
for (i = 0; i < numFaces; i++) {
 pFaceVisArray[i] =
 i ? kAcGiVisible : kAcGiInvisible;
 pFaceColorArray[i] = (short)(i + 1);
 }
 faceInfo.setColors(pFaceColorArray);
// If the fill type is kAcGiFillAlways, then a shell,
 // mesh, or polygon will be interpreted as faces;
 // otherwise, they will be interpreted as edges.
// Output mesh as faces.
 //
 pW->subEntityTraits().setFillType(kAcGiFillAlways);
 pW->geometry().mesh(numRows, numCols, pVerts, NULL,
 &faceInfo);
// Output mesh as edges over the faces.
 //
 pW->subEntityTraits().setFillType(kAcGiFillNever);
 pW->geometry().mesh(numRows, numCols, pVerts,
 &edgeInfo);
delete [] pVerts;
 delete [] pEdgeColorArray;
 delete [] pFaceColorArray;
 delete [] pFaceVisArray;
 return Adesk::kTrue;
}
// END CODE APPEARING IN SDK DOCUMENT.
static void
addAsdkMeshSampObject()
{
 Acad::ErrorStatus es;
 AcDbBlockTable *pBlockTable;
 es = acdbHostApplicationServices()->workingDatabase()
 ->getSymbolTable(pBlockTable, AcDb::kForRead);
 if (es != Acad::eOk)
 return;
AcDbBlockTableRecord *pBlock;
 es = pBlockTable->getAt(ACDB_MODEL_SPACE, pBlock,
 AcDb::kForWrite);
 if (es != Acad::eOk)
 return;
AcDbObjectId objId;
 AsdkMeshSamp *pNewObj = new AsdkMeshSamp;
 es = pBlock->appendAcDbEntity(objId, pNewObj);
 if (es != Acad::eOk) {
 delete pNewObj;
 return;
 }
es = pBlock->close();
 if (es != Acad::eOk)
 acrx_abort(_T("\nUnable to close block table record"));
es = pBlockTable->close();
 if (es != Acad::eOk) 
 acrx_abort(_T("\nUnable to close block table"));
es = pNewObj->close();
 if (es != Acad::eOk) 
 acrx_abort(_T("\nUnable to close new entity"));
}
static void
initAsdkMeshSamp()
{
 AsdkMeshSamp::rxInit();
 acrxBuildClassHierarchy();
acedRegCmds->addCommand(_T("ACGI_MESH_SAMP"),
 _T("ASDKMAKEMESH"),
 _T("MAKEMESH"),
 ACRX_CMD_TRANSPARENT,
 addAsdkMeshSampObject);
}
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId) 
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initAsdkMeshSamp();
 break;
 case AcRx::kUnloadAppMsg:
 acedRegCmds->removeGroup(_T("ACGI_MESH_SAMP"));
 deleteAcRxClass(AsdkMeshSamp::desc());
 }
 return AcRx::kRetOK;
}

8_ASDK_GROUPTEST.txt

#include <stdlib.h>
#include <string.h>
#include <rxobject.h>
#include <rxregsvc.h>
#include <aced.h>
#include <dbgroup.h>
#include <dbsymtb.h>
#include <dbents.h>
#include <dbapserv.h>
#include <adslib.h>
#include "tchar.h"
void groups();
void makeGroup(AcDbObjectId groupId);
void removeAllButLines(AcDbObjectId groupId);
void initApp();
void unloadApp();
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode, void*);
// This is the main function of this app. It will first
// create a new AcDbGroup object and add it to the groups
// dictionary with the key "grouptest". Then it will call
// makeGroup() to prompt the user to select some entities
// which it will place into the "grouptest" group. Then it
// will call the function removeAllButLines() to iterate
// over the group created removing all entities that are
// not AcDbLines and change all remaining entities in the
// group to color red.
//
// THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
//
void groups()
{
 AcDbGroup *pGroup = new AcDbGroup(_T("grouptest"));
 AcDbDictionary *pGroupDict;
 acdbHostApplicationServices()->workingDatabase()
 ->getGroupDictionary(pGroupDict, AcDb::kForWrite);
 AcDbObjectId groupId;
 pGroupDict->setAt(_T("ASDK_GROUPTEST"), pGroup, groupId);
 pGroupDict->close();
 pGroup->close();
 makeGroup(groupId);
 removeAllButLines(groupId);
}
// Prompts the user to select objects to add to the group,
// opens the group identified by "groupId" passed in as
// an argument, then adds the selected objects to the group.
//
void makeGroup(AcDbObjectId groupId)
{
 ads_name sset;
 int err = acedSSGet(NULL, NULL, NULL, NULL, sset);
 if (err != RTNORM) {
 return;
 }
 AcDbGroup *pGroup;
 acdbOpenObject(pGroup, groupId, AcDb::kForWrite);
 // Traverse the selection set, exchanging each ads_name
 // for an object ID, then adding the object to the group.
 //
 AdInt32 i, length;
 ads_name ename;
 AcDbObjectId entId;
 acedSSLength(sset, &length);
 for (i = 0; i < length; i++) {
 acedSSName(sset, i, ename);
 acdbGetObjectId(entId, ename);
 pGroup->append(entId);
 }
 pGroup->close();
 acedSSFree(sset);
}
// Accepts an object ID of an AcDbGroup object, opens it,
// then iterates over the group, removing all entities that
// are not AcDbLines and changing all remaining entities in
// the group to color red.
//
void removeAllButLines(AcDbObjectId groupId)
{
 AcDbGroup *pGroup;
 acdbOpenObject(pGroup, groupId, AcDb::kForWrite);
 AcDbGroupIterator *pIter = pGroup->newIterator();
 AcDbObject *pObj;
 for (; !pIter->done(); pIter->next()) {
 pIter->getObject(pObj, AcDb::kForRead);
 // If it is not a line or descended from a line,
 // close it and remove it from the group. Otherwise,
 // just close it.
 //
 if (!pObj->isKindOf(AcDbLine::desc())) {
 // AcDbGroup::remove() requires that the object
 // to be removed be closed, so close it now.
 //
 pObj->close();
 pGroup->remove(pIter->objectId());
 } else {
 pObj->close();
 }
 }
 delete pIter;
 // Now change the color of all the entities in the group
 // to red (AutoCAD color index number 1).
 //
 pGroup->setColorIndex(1);
 pGroup->close();
}
// END CODE APPEARING IN SDK DOCUMENT.
// Initialization function called from acrxEntryPoint during
// kInitAppMsg case. This function is used to add commands
// to the command stack.
//
void initApp()
{
 acedRegCmds->addCommand(_T("ASDK_GROUP_TEST"),
 _T("ASDK_GROUPTST"),_T("GROUPTST"), ACRX_CMD_MODAL, groups);
}
// Clean up function called from acrxEntryPoint during the
// kUnloadAppMsg case. This function removes this app's
// command set from the command stack.
//
void
unloadApp()
{
 acedRegCmds->removeGroup(_T("ASDK_GROUP_TEST"));
}
// ARX entry point
//
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
 switch (msg) {
 case AcRx::kInitAppMsg:
 acrxDynamicLinker->unlockApplication(appId);
 acrxDynamicLinker->registerAppMDIAware(appId);
 initApp();
 break;
 case AcRx::kUnloadAppMsg:
 unloadApp();
 }
 return AcRx::kRetOK;
}

 

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *