Тема: Ожидание окончания выполнения LISP-команды.

Доброго времени суток, уважаемые!
Пролистав посты на форуме
https://www.caduser.ru/forum/topic23530.html
https://www.caduser.ru/forum/topic31519.html
https://www.caduser.ru/forum/topic15242.html
и попробовав некоторые примеры, так и не смог решить мою задачу, поэтому обращаюсь к ВАМ дорогие знатоки.
Суть в следующем:
У меня работает внешнее приложение (модальное), которое через определенный интервал времени проверяет есть ли в папке "Х" файлы с расширением "*.ххх". Как только такие файлы программа находит, она, с помощью Sendcommand("(myfunc)\n") выполняет LISP-функцию "myfunc" в AutoCADе, закрывает созданный чертеж, открывает новый и удаляет прочитаный файл, причем ARX-код дожидается выполнения LISP-команды и при этом блокируются даже кнопки внешнего приложения до окончания выполнения функции. Видимо проблема потоков и т.д., я до такого еще не дорос. :)
И так процесс повторяется пока не обработаются все файлы в папке "Х".
Вот сама функция:

void CCADBATDlg::SendCommand(CString send_str)
{
    AutoCAD::IAcadApplicationPtr pAcadApp;    // AutoCAD-Application
    pAcadApp.GetActiveObject(clsid);    // Active AutoCAd-Application
    AutoCAD::IAcadDocumentsPtr pDocs = NULL;// Documents
    AutoCAD::IAcadDocumentPtr pDoc = NULL;    // Document
    
    if (pAcadApp != NULL)
    {
        pAcadApp->get_Documents(&pDocs);
        pAcadApp->get_ActiveDocument(&pDoc);
        if(pDoc != NULL)
        {
            _bstr_t str;
                        
            str = send_str;
                        // Здесь рааботает LISP-функция, ARX ожидает окончания работы LISP.
            pDoc->SendCommand(str);
                        // ARX закрывает документ и открывает новый.
            CloseDoc("");
            OpenDoc("");
        }
    }
}

Теперь я решил написать внутреннее приложение для AutoCADа(НЕмодальное) и для вызова той же LISP-функции "myfunc" использую

acDocManager->sendStringToExecute(acDocManager->curDocument(), _T("(myfunc) "));

И вот здесь как раз и начались проблемы.
ARX-код выполняется дальше и в какой-то момент, с задержкой, вдруг выполняется LISP-функция.
Мой вопрос: Как дождаться выполнения LISP-функции, а потом продолжить выполнение ARX-кода дальше?
И еще один вопрос, как правильно, после создания чертежа, закрыть его и открыть новый?
Заранее спасибо за помощь!

Re: Ожидание окончания выполнения LISP-команды.

Для синхронного выполнения: acedEvaluateLisp

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Спасибо за ответ!
В принципе Вашего ответа и ждал. ;)
Не могли бы Вы какой-нибудь пример подкинуть.
Что-то я со вторым аргументом не могу разобраться. :(

Re: Ожидание окончания выполнения LISP-команды.

Для AutoCAD 2007,2008:

int __cdecl acedEvaluateLisp(wchar_t const *,struct resbuf * &)

Для AutoCAD 2005,2006:

int __cdecl acedEvaluateLisp(char const *,struct resbuf * &)

Во втором параметре возвращается вычисленное значение в виде связанного списка resbuf.

Re: Ожидание окончания выполнения LISP-команды.

static void TestLisp(void)
{
  ACHAR buf[1024];
  int rc = acedGetString(TRUE,_T("\nВведите lisp-выражение: ") ,buf);
  resbuf *rb = NULL;
  acedEvaluateLisp(buf,rb);
  // print_rb(rb); // Здесь уже можно анализировать значение, которое возвращает lisp-функция
}

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Спасибо, буду пробовать.

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
При компиляции выдает ошибку "C3861 'identifier': identifier not found"
Как я понимаю нужно подключить библиотеку, или я ошибаюсь.
Подскажите, пожалуйста, что нужно сделать.

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Это относится к

acedEvaluateLisp

Re: Ожидание окончания выполнения LISP-команды.

> Serghei
Нужно просто вставить описание (например, в stdafx.h). Для AutoCAD 2005-2006:

int acedEvaluateLisp(char const *,struct resbuf * &);

Для AutoCAD 2007-2008:

int acedEvaluateLisp(wchar_t const *,struct resbuf * &);

Наверно подойдет и такое описание для всех версий:

int acedEvaluateLisp(ACHAR const *,struct resbuf * &);

Больше ничего не нужно. Функция недокументированная и содержится в acad.lib

Re: Ожидание окончания выполнения LISP-команды.

Доброго времени суток!
Снова обращаюсь к Вам. Казалось бы куда уже проще, ан нет, никак из этих 3-х строчек не вылезу.
Вот LISP-функция, которую я вызываю:

(defun myfunc ( / myfunret)
    
    (command "_line" '(0 0) '(100 100) "")
    (command "_zoom" "_e")
    
    (princ (strcat "\nГотово!!!\t" (rtos  (getvar "CDATE")) "\n"))
    (setq myfunret 123)
)
 (vl-acad-defun 'myfunc)

А вот 2 ARX-функции, одна как LISP, другая как AutoCAD-функция:

// - ArxTest._MyArx command (do not rename)
static void ArxTest_MyArx(void)
    {
        // Add your code for command ArxTest._MyArx here
      ACHAR buf[1024];
      int rc = acedGetString(TRUE,_T("\nВведите lisp-выражение: ") ,buf);
      resbuf *rb = NULL;
      acedEvaluateLisp(buf,rb);
    }
// ----- ads_myf symbol (do not rename)
    static int ads_myf(void)
    {
        //----- Remove the following line if you do not expect any argument for this ADS function
        //struct resbuf *pArgs =acedGetArgs () ;
        // TODO: add your code here        
        resbuf *rb = NULL;
        acedEvaluateLisp(_T("(myfunc)\n"),rb);
        // TODO: Replace the following line by your returned value if any
        acedRetVoid () ;
        return (RSRSLT) ;
    }

Но в обоих функция на строке

 acedEvaluateLisp(хх, rb);

AutoCAD виснет и помогает только отключение процесса и новый старт AutoCAD.
Что я делаю не правильно?

Re: Ожидание окончания выполнения LISP-команды.

1) попробуй: acedEvaluateLisp(_T("(myfunc)"),rb);
2) (vl-acad-defun 'myfunc) ;; <- это в данном случае не нужно

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Пробовал, не помогает :(
Пробовал и c:myfunc в различных комбинациях, тоже самое.
Вот что я заметил. Если не использовать (command ...) в myfunc, то функция обрабатывается.
Может есть по этому поводу какие-нибудь идеи?

Re: Ожидание окончания выполнения LISP-команды.

> Serghei
Есть идеи. Не использовать (command ...) smile
Если серьезно, то у тебя остался еще вариант с acedInvoke и (vl-acad-defun 'myfunc). Я его использую в этой программе: ObjectARX. Отслеживание и рисование

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Доброго дня!
Хочу поделиться своими исследованиями по наболевшей теме и заодно задать еще вопрос.
Благодаря твоему совету, использовать acedInvoke, смог запустить LISP-функции с (command ...).
НО!!! Это было только начало, рано начал радоваться :(
Если использовать acedInvoke из Немодального окна (с модальным не пробовал), то LISP-функция прорабатывает до
(command ...),
а дальше
Fehler: invalid AutoCAD command: nil
Есть ли еще варианты использования acedInvoke (или других функций) из Немодального окна?
Старые условия (Ожидание окончания выполнения LISP-команды), остаются в силе!
Спасибо.

Re: Ожидание окончания выполнения LISP-команды.

> Serghei
Из немодального окна нельзя запускать команды используя (command ...) или acedCommand (т.е. синхронно).

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Очередное спасибо за ответ!
И 1000 извинений за назойливость :)
А какие еще есть варианты для вызова LISP-функций с (command ...) из окон?
Я имею ввиду внутренние окна AutoCAD.
Жду с нетерпением ответа.

Re: Ожидание окончания выполнения LISP-команды.

> Serghei
Если речь идет о немодальных окнах, то acedPostCommand или sendStringToExecute - но это ассинхронно. Синхронно нельзя. Да из модальных тоже достаточно все проблематично.
P.S.: Это твои lisp-программы? Перепиши их на ObjectARX и не мучайся. VisualLisp-программы не расчитаны на вызов их из arx-приложений. Наоборот - пожалуйста.

Re: Ожидание окончания выполнения LISP-команды.

> Александр Ривилис
Благодарю, за оперативный ответ!

Это твои lisp-программы? Перепиши их на ObjectARX и не мучайся.

Увы не получится, на это есть 2 причины:
1. Честно говоря страшно переписывать, т.к. мой уровень владения C/C++ нулевой, пишу в основном на LISP, а C++, как хобби. Понятно, все приходит с опытом, но все равно стремно.
2. Это огромное количество LISP-кода, причем чужого.
В крайнем случае оставлю как есть внешнее приложение, с доработкой для новой версии. Хотя хотелось сделать красиво!
Спасибо еще раз!!!

Re: Ожидание окончания выполнения LISP-команды.

В продолжение нашей темы, может кому-то пригодиться.
Для простейшего варианта я нашел решение, может кривое (с точки зрения профи), но первые тесты ничего плохого не выдали.
Я изменил функцию ads_myf вот так:

static int ads_myf(void)
{
    //----- Remove the following line if you do not expect any argument for this ADS function
    // TODO: add your code here
    if (!m_cadbatDialog)
    {
        CAcModuleResourceOverride resOverride;
        m_cadbatDialog = new CNoModalDlg;
        m_cadbatDialog->Create(IDD_NOMODALDLG);
        m_cadbatDialog->ShowWindow(SW_SHOWNORMAL);
    }
    else
    {
        if (!m_cadbatDialog->IsWindowVisible() || m_cadbatDialog->IsIconic())
        {
            m_cadbatDialog->ShowWindow(SW_SHOWNORMAL);
        }
    }
    if (m_cadbatDialog)
    {
        CMDIFrameWnd* acadFrame = acedGetAcadFrame();
        acadFrame->SetActiveWindow();
        bool RetVal = false;
          struct resbuf *Result;
          struct resbuf *Temp;
          //struct resbuf *FuncCall = acutBuildList(RTSTR, _T("myfunc"), 0);
          struct resbuf *FuncCall = acutBuildList(RTSTR, _T("myfunc"), 0);
          // Check to make sure list was build properly
          if (FuncCall != NULL)
          {
            // Make the LISP call to get the value
            if (acedInvoke(FuncCall, &Result) == RTNORM)
            {
              if (Result != NULL)
              {
                // Free buffers when done
                acutRelRb(Result);
              }
            }
            else
            {
                MessageBox(NULL, _T("acedInvoke Error!"), _T("ARX Test"), MB_OK);
            }
            // Free buffers when done
            acutRelRb(FuncCall);
          }
    }
    // TODO: Replace the following line by your returned value if any
    acedRetVoid () ;
    return (RSRSLT) ;
}

То есть, открывается в этой функции немодальное окно и в ней же вызывается acedInvoke(...).
Потом, из окна, если надо
вызываю

 acDocManager->sendStringToExecute(acDocManager->curDocument(), _T("(myf)\n"));

В моем случае, для теста, я подцепил эту строку на кнопку.
Теперь буду пробовать подключить дополнительно таймер.
Ждите снова вопросов wink