Тема: Как из реактора вызвать LISP-функцию?

Есть реактор на ARX (AcDbDatabaseReactor). Он активируется внутри транзакции, открывающейся в реакторе AcEditorReactor при вызове команд модификации. Он должен менять слой модифицируемых объектов. Если это делать из ARX, все замечательно. А если вызывать LISP - функцию - все плохо.
Делаю так:

void DBaseReactor::objectModified(const AcDbDatabase * dwg, const AcDbObject * dbObj)
{
if (DocVars.docData().isModifyCommandActive==false && DocVars.docData().isVBACommandActive==false )
    {
    return;
    }
AcDbBlockReference *pInsert=AcDbBlockReference::cast(dbObj);
if (!pInsert) return;
resbuf *xdataList=NULL;
xdataList=pInsert->xData(NULL);
if(xdataList==NULL)
    {
    acutRelRb(xdataList);
    return;
    }
AcDbHandle h;
pInsert->getAcDbHandle(h);
if (!h) return;
char *str=new char;
h.getIntoAsciiBuffer(str);
resbuf *SComm;
int i;
SComm=acutBuildList(RTSTR, "changelayertoobject",RTSTR, str,RTSTR, "user",RTNONE);
pInsert->upgradeOpen();
resbuf *reslist=NULL;
i=acedInvoke(SComm,&reslist);
acutRelRb(reslist);
acutRelRb(SComm);
if (xdataList) acutRelRb(xdataList);
}

а LISP-функция такая:

(defun changeLayerToObject (handleObj nameLayer)
  (if (and (tblsearch "LAYER" nameLayer) (handent handleObj))
    (progn    (vla-put-Layer
     (vlax-ename->vla-object
        (cdr (assoc -1 (entget (handent  handleObj ))))
    
       nameLayer )
       )
       t
    )
    nil
  )
  (princ)
 )
(vl-acad-defun 'changeLayerToObject)

А в ответ мне говорят lentityp nil
Лидеры, что посоветуете?
Неохота уйму LISP-функций на ARX переписывать...
Все спасибо

Re: Как из реактора вызвать LISP-функцию?

char *str=new char;
Это что такое? Похоже что вместо метки примитива ты передаешь черт знает что.

Re: Как из реактора вызвать LISP-функцию?

Для начала исключим всю лабуду

(defun changeLayerToObject (handleObj nameLayer/)
  (if (and (tblsearch "LAYER" nameLayer) (handent handleObj))
    (progn (vla-put-Layer
         (vlax-ename->vla-object
           (handent handleObj)
           nameLayer
         )
       )
       t
    )
    nil
  )
)

Ни и будем думать дальше.

Re: Как из реактора вызвать LISP-функцию?

> BP
тоже не получается. Говорит:
error: Automation Error. Description was
not provided.
>Ривилис

char *str=new char;

А это я так str инициализирую. Иначе не получаецца

h.getIntoAsciiBuffer(str);

(AutoCAD 2005)
Видимо, если я в ARX внутри трансакции открыл объект и передался в AutoLISP, который тоже его пытается открыть, сбой происходит. Как бы их обмануть? Я могу перед вызовом LISPа объект закрыть или трансакцию закрыть, но быстродействие!!! Тогда уж обратно в VBA залезать...

Re: Как из реактора вызвать LISP-функцию?

Попробуем для начала прочитать какое-нибудь свойство.

(defun readLayerToObject (handleObj /)
  (if (handent handleObj)
    (vla-get-Layer
      (vlax-ename->vla-object
    (handent handleObj)
      )
    )
  )
)

Re: Как из реактора вызвать LISP-функцию?

> Зигмус
1) Неправильно инициализируешь:

char str[17];
h.getIntoAsciiBuffer(&str);

2) Есть четкие правила работы с объектами - второй раз нельзя открыть примитив для записи если он уже был открыт. Вывод - закрывать.

Re: Как из реактора вызвать LISP-функцию?

<Ривилис
Пробовал. Брал из какого-то примера на форуме: Ошибка:
AcDbHandle::getIntoAsciiBuffer' : cannot convert parameter 1 from 'char (*__w64 )[17]' to 'char *'
<BP
тот же результат : Automation Error.
Придется, видимо, LISP-функции переписывать sad

Re: Как из реактора вызвать LISP-функцию?

> Зигмус

char str[17];
h.getIntoAsciiBuffer(str);

Re: Как из реактора вызвать LISP-функцию?

> Зигмус
Проверь все-таки в lisp-программе что возвращает (handent handleObj) - поставь отладочную печать.

Re: Как из реактора вызвать LISP-функцию?

(defun readLayerToObject (handleObj /)
  (if (princ (handent handleObj))
    (vla-get-Layer
      (vlax-ename->vla-object
    (handent handleObj)
      )
    )
  )
)

Протокол в студию.

Re: Как из реактора вызвать LISP-функцию?

> BP
Имя lisp-функции ему менять нельзя! Т.е. должно остаться имя changeLayerToObject иначе arx-функция его не вызовет. Или придется менять в C++ коде и еще и в вызове (vl-acad-defun ...)

Re: Как из реактора вызвать LISP-функцию?

> Александр Ривилис
Да я думаю, что сообразит. Ну на всякий случАй

(defun changeLayerToObject (handleObj /)
  (if (princ (handent handleObj))
    (vla-get-Layer
      (vlax-ename->vla-object
         (handent handleObj)
      )
    )
  )
)

Re: Как из реактора вызвать LISP-функцию?

readLayerToObject - читает
changeLayerToObject - не работает, если upgradeOpen();
вылетает, если объект в ARX открыт для чтения и работает, если объект закрыть до вызова LISP функции.
ARX+LISP - плохо.
LISP+ARX хорошо.
Посмотрим, как ARX+VBA: можно ли из ARX передавать не метки или имена, а сами объекты: AcDbBlockReference или AcDbEntity

Re: Как из реактора вызвать LISP-функцию?

Так у объекта, открытого в ARX, в LISP-е свойства читаются?

Re: Как из реактора вызвать LISP-функцию?

читаются
<Entity name: 7ef74e18>
если объект открыт для чтения
Читаются с руганью, если объект открыт для записи
<Entity name: 7ef79e18>; error:
Automation Error. Description was not provided.
Читается без проблем, если объект перед запуском LISP закрыть. pInsert->close();
<Entity name: 7ef74e18>
Функция:

(defun changeLayerToObject (handleObj nameLayer /)
  (princ handleObj)
  (vl-load-com)
  (if (and (tblsearch "LAYER" nameLayer) (handent handleObj))
    (progn (vla-put-Layer
         (vlax-ename->vla-object (handent handleObj))      nameLayer    )
      t    )
    nil  )
  )
(vl-acad-defun 'changeLayerToObject)

Re: Как из реактора вызвать LISP-функцию?

> Зигмус
Это вообще очень плохой тон модифицировать объект в реакторе на модификацию объекта. Развалить AutoCAD или испортить механизм работы Undo/Redo - раз плюнуть.

Re: Как из реактора вызвать LISP-функцию?

А так пойдет - создать в реакторе БД массив Id или handle'ов - а затем в реакторе редактора на commandEnded его обработать?

Re: Как из реактора вызвать LISP-функцию?

> Зигмус
Именно так и следует делать!

Re: Как из реактора вызвать LISP-функцию?

> Ривилис
Большое спасибо за совет, теперь вырисовывается.
Но есть следующая проблема: каким способом можно отследить, как именно в базе данных появился новый объект: создали новый или он появился в результате копирования исходного. Как можно получить ID исходного?

Re: Как из реактора вызвать LISP-функцию?

> Зигмус
Копии исходных появляются в результате клонирования примитивов. Поэтому посмотри сюда:

AcEditorReactor::beginDeepCloneXlation()
AcEditorReactor::endDeepClone()
AcEditorReactor::beginWblockObjects ()
AcEditorReactor::otherInsert()
AcEditorReactor::otherWblock()
и т.д.

Во всех этих функциях присутствует параметр - член класса AcDbIdMap. Вот он тебя и интересует. Здесь пример того как им пользоваться для получения ID-исходного примитива.