Тема: LISP из ARX

Доброго времени суток. Такой вопрос:
Есть файл с LISP-кодом.
(defun Sasha_is_the_best_programmer ( / str)
   (setq str 2)
)
Который возвращает просто число 2.
На С++ в виде АРХ модуля написан код, который вызывает окно типа "Ок/Cancel". По нажатии кнопки "ОК" вызывается следующий код:
int ret = ads_queueexpr("(load C:\\ObjectARX 2007\\Visual Studio Projects\\modal\\modal\"tmp.lsp\")");
    wchar_t str[16];
    //int t = ads_queueexpr("(Sasha_is_the_best_programmer)");
    MessageBoxW(_itow(t, str, 10), _T("Сообщение"), MB_OK | MB_ICONEXCLAMATION);
Данный код я создрал из темы https://www.caduser.ru/forum/topic5638.html
Как сделать так, что бы результат LISP кода т.е. число 2, выводилось в MessageBox? И что точно делает функция ads_queueexpr

Re: LISP из ARX

> Doglexx
В LISP-выражении добавить "(setq xx (Sasha...))", а затем прочитать переменную xx с помощью acedGetSym("xx", ...) и использовать, как хочется.

Re: LISP из ARX

Уважаемый Николай Николаевич! Спасибо за быстрый ответ. Завтра отпишусь о результатах.

Re: LISP из ARX

> Doglexx
1. Использование вызова lisp-функции из arx-приложение - это признак плохого стиля. Причин несколько:
a) аналогичная lisp-функции arx-функция будет выполняться значительно (возможно на несколько порядков) быстрее.
б) передача данных и получение результатов из arx в lisp достаточно затруднено. Если arx-приложение работает в контексте приложения, а не в контексте документа, то lisp-функциями вообще непонятно что будет делать.
2. Если доводы пункта 1. показались не убедительными или нет возможности переписать lisp-функцию (функции) с использование arx, то:
а) использование функции ads_queueexpr(...) в такой ситуации обычно бессмысленно, так как она выполняется ассинхронно к выполнению arx-приложения (т.е. она будет выполнена только тогда, когда arx-команда/функция завершится и AutoCAD получит управление; соответственно получить результат ее выполнения в текущей arx-функции/команде будет невозможно).
б) Есть альтернативы (которые выполняются синхронно): https://www.caduser.ru/forum/topic15242.html

Re: LISP из ARX

> Александр Ривилис
Асинхронность ветвей на разных языках - большая проблема. Мои коллеги пишут на смеси VBA и LISP и часто жалуются, что не могут преодолеть ее.

Re: LISP из ARX

> Н.Н.Полещук
Из всех известных мне интерфейсов (языков программирования) в среде AutoCAD мне кажется (!) оправданным использование двух смесей:
1) lisp->arx (т.е. вызов arx-функция из lisp-функция с возможностью возврата значений)
2) lisp->.NET (и то только начиная с AutoCAD 2007)
Оба интерфейса односторонние, т.е. вызвать lisp-функцию из ARX/.NET достаточно проблематично, а вызов ARX/.NET-функции из lisp-функции не представляет труда.
Когда создавался ADS (прародитель ARX) он был "заточен" на создание на C++ функций, которые можно было вызывать из lisp-программ. Теперь аналогичная ситуация складывается и с .NET.
Все остальные смеси достаточно неустойчивы и (IMHO) не имеют никаких перспектив.

Re: LISP из ARX

> Александр Ривилис
Взяв кусок кода из Вашего примера получил следующее:
struct resbuf *rb;
wchar_t strres[16];
resbuf *rb_in = cutBuildList(RTSTR,"f1",RTNONE);
resbuf *rb_out = NULL;
int rc = acedInvoke(rb_in,&rb_out);
acutRelRb(rb_in); acutRelRb(rb_out);
acedGetSym(_T("str"),&rb_out);
_itow(RSRSLT, strres, 10);
acedAlert(strres);
В результате данной код выдаёт постоянно "1".
ЛИСП функция имеет слудующий вид:
(defun f1 ( / )
  (setq str 5)
)
(vl-acad-defun 'f1)
В чём проблема?

Re: LISP из ARX

> Doglexx
Так ведь RSRSLT, который Вы выводите, и есть 1.

Re: LISP из ARX

> Doglexx
Хммм. А где это у меня такой пример был? :)
P.S. Может быть так:

//....................
acedGetSym(_T("str"),&rb_out);
_itow(rb_out->resval.rint, strres, 10);
acedAlert(strres);
//....................

Re: LISP из ARX

P.S. Хотя в данном случае все могло быть намного проще:

;;; Lisp'овский код
(defun f1 ( / )
 5 ; Или люб
)
(vl-acad-defun 'f1)
struct resbuf *rb;
wchar_t strres[16];
resbuf *rb_in = acutBuildList(RTSTR,"f1",RTNONE);
resbuf *rb_out = NULL;
int rc = acedInvoke(rb_in,&rb_out);
acutRelRb(rb_in);
if (rb_out) {
 rc = rb_out->resvar.rint;
 acutRelRb(rb_out);
 AcString s; s.Format("%i",rc);
 acedAlert(s);
}

Если необходимо вернуть одно значение, то нет смысла записывать его в lisp-переменную, достаточно вернуть это значение и проанализировать rb_out. Если же значений несколько и их лень объяединять в список и потом его анализировать, то можно воспользоваться lisp-переменными, не забывая делать их имена уникальными (например, при помощи префикса с  именем arx-файла: _T("firstArx_f1") и в lisp-функции (setq fistArx_f1 5)

Re: LISP из ARX

> Александр Ривилис

> Н.Н.Полещук
Спасибо за ответы!
Александр такой вопрос: Lisp-код я должен загрузить вручную из АВТОкада с помощью appload?
Если да, то какая может быть причина того, что при проверке условия "if (rb_out) {..." из Вашего кода, возвращается "ложь" и вывода не происходит?

Re: LISP из ARX

> Doglexx
1) Загружать lisp-файл ты можешь любым способом (командой APPLOAD, с использованием автозагрузки, lisp-функцией (load ...) и т.д.). Важно чтобы в момент вызова acedInvoke этот код был уже загружен.
2) Причин того, что rb_out остался NULL, может быть несколько:
а) Функция f1 в этот момент не определена.
b) acedInvoke вызвана из контекста приложения, а не контекста документа.
c) произошла ошибка в функции f1
d) ... и т.д
Проверь значение rc - если оно не RTNORM значит lisp-функция или не вызвана или в ней произошла ошибка.

Re: LISP из ARX

> Александр Ривилис
Значение rc - RTERROR:(

Re: LISP из ARX

> Doglexx
Ты работаешь с AutoCAD 2007 и ObjectARX 2007? Тогда код должен выглядеть так:

resbuf *rb_in = acutBuildList(RTSTR,_T("f1"),RTNONE);
resbuf *rb_out = NULL;
int rc = acedInvoke(rb_in,&rb_out);
acutRelRb(rb_in);
if (rb_out) {
 rc = rb_out->resvar.rint;
 acutRelRb(rb_out);
 AcString s; s.Format("%i",rc);
 acedAlert(s);
}

Обрати внимание на _T("f1") в вызове функции acutBuildList - из-за того что ты передал не уникодовскую строку AutoCAD не в состоянии найти lisp-функцию f1.

Re: LISP из ARX

Александр Наумович! Спасибо большое, что помогли мне бестолковому:) разобраться!
Позволю себе сделать небольшие замечания по Вашему коду. Я использую VS 2005, AutoCAD & ObjectARX 2007.
1) rb_out->resvar.rint - следует заменить в слове resvar на resval.
2) s.Format("%i",rc) - format следует писать с маленькой буквы т.к. метода Format нету у класса AcString. "%i" - нужно обрамить _T().
acutBuildList(RTSTR,_T("f1"),RTNONE) - Интересно, что компилятор на выдавал ошибки по поводу того, что нет преобразования второй переменной функции acutBuildList т.е. "f1" в Юникод.
В общем, ещё раз спасибо!

Re: LISP из ARX

> Doglexx
Увы, но на этот раз я писал код без проверки, так что прошу прощения за ошибки... :)

acutBuildList(RTSTR,_T("f1"),RTNONE) — Интересно, что компилятор на выдавал ошибки по поводу того, что нет преобразования второй переменной функции acutBuildList т.е. "f1" в Юникод.

Увы, но компилятор принципиально не в состоянии выловить здесь ошибку - т.к. эта функция с переменным числом аргументов и он (компилятор) не знает типы аргументов, которые могут быть любыми. Это же замечание относится к функциям acutBuildList, acedCommand, acutPrintf и т.д. Так что с ними нужно быть очень осторожным!

Re: LISP из ARX

Пытался переделать, чтобы LISP-код загружался из программы. Использовал слудующую команду:
acDocManager->sendStringToExecute(acDocManager->curDocument(), _T("(load \"C:\\ObjectARX 2007\\Visual Studio Projects\\modal\\modal\\tmp.lst\") "));
Столкнулся с проблемой, которая была описана Полещуком Н.Н. выше: вызов команды load происходит только после завершения arx-приложения.
Однако AutoCAD почему-то выдаёт ошибку, что
Command: (load "C:\ObjectARX 2007\Visual Studio Projects\modal\modal\tmp.lst")
; error: LOAD failed: "C:ObjectARX 2007Visual Studio Projectsmodalmodal\tmp.lst"

Re: LISP из ARX

В предыдущем сообщении опечатался название файла вместо "tmp.lst" следует читать "tmp.lsp".

Re: LISP из ARX

В общем с ошибкой разобрались. В С++ следовало заменить все \\ на /.

Re: LISP из ARX

> Doglexx
Все палки надо еще раз удвоить, а то пока дойдет до среды LISP, ничего не останется... (\\\\)

Re: LISP из ARX

> Н.Н.Полещук
К сожелению удвоение палок почему-то ничего не давало. Теперь буду разбираться с синхронностью.