Продолжение работы запущенной команды

Автор Тема: Продолжение работы запущенной команды  (Прочитано 9655 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Если в двух словах, то есть команда (прозрачная), которая меняет системную переменную
Присутствует хук и AcEditorReactor.
AcEditorReactor контролирует, моя ли команда поменяла конкретную переменную. и если да, работать начинает хук.
в хуке вызывается диалоговое окно. Ну и на этом всё. после закрытия диалогового окна команда должна продолжить работу.
Это в теории :)

По факту, после закрытия диалогового окна в командной строке висит название команды. И, только если клацнуть на командную строку и на клавиатуре нажать "Backspace", команда продолжается.
В остальных случаях не отображаются результаты действий в командной строке. Например, можно начать рисовать отрезок. Нарисуется без проблем, но командная строка не пополнится отчетом об этом. Ну и тому подобное... Короче говоря, что-то тут не так. И в связи с этим хотелось бы узнать, чего я собственно упустил, что мои действия приводят к разваливанию командной строки?
Ну и естественно, тестовый проект

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Код я еще не смотрел, но похоже у тебя не хватает вызова acedPostCommandPrompt
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Код я еще не смотрел, но похоже у тебя не хватает вызова acedPostCommandPrompt
в ЭТОМ коде действительно нет acedPostCommandPrompt, в оригинале есть в конце функции, вызываемой хуком. вот только ничего он не дает. результат и с ним и без него одинаковый.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Я поразбираюсь с твоим кодом немного позднее. Пока уточни версию AutoCAD, в которой тестируешь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Конкретно этот проект настроен на 2017.
Свой рабочий проект тестировал в 2014х64 и 2017х64. Подозреваю во всех остальных автокадах ситуация такая же, просто не было времени протестировать.
Использоваться будет в 2010+

:) ну и спасибо за помощь

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Похоже в общем случае это не лечится, но в случае если командная строка не "развернута", то работает такой код:
Код - C++ [Выбрать]
  1. void neededFunction()
  2. {
  3.   {
  4.     CAcModuleResourceOverride res;
  5.     CSampleDlg dlg(CWnd::FromHandle(adsw_acadMainWnd()));
  6.     if (dlg.DoModal() == IDOK)
  7.     {
  8.       acedAlert(_T("OK pressed"));
  9.     }
  10.   }
  11.   CWnd *wnd = acedGetAcadDockCmdLine();
  12.   wnd->PostMessageW(WM_KEYDOWN, VK_BACK, 0);
  13.   wnd->PostMessageW(WM_KEYUP, VK_BACK, 0);  // Не обязательно
  14.   acedPostCommandPrompt();  // Не обязательно
  15.   acedPrompt(L"");  // Не обязательно
  16. }



Вообще же вызывать диалоговое окно из фильтра событий - это извращение.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Николай Горлов 17-07-2017, 10:03:38

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Кажется я всё-таки нашел универсальный workaround, не зависящий от состояния командной строки:

Код - C++ [Выбрать]
  1. BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
  2. {
  3.   ::PostMessage(hwnd,WM_KEYDOWN, VK_BACK, 0);
  4.   ::PostMessage(hwnd, WM_KEYUP, VK_BACK, 0);
  5.   return TRUE;
  6. }
  7.  
  8. void neededFunction()
  9. {
  10.   {
  11.     CAcModuleResourceOverride res;
  12.     CSampleDlg dlg(CWnd::FromHandle(adsw_acadMainWnd()));
  13.     if (dlg.DoModal() == IDOK)
  14.     {
  15.       acedAlert(_T("OK pressed"));
  16.     }
  17.   }
  18.   CWnd *wnd = acedGetAcadDockCmdLine();
  19.   wnd->PostMessage(WM_KEYDOWN, VK_BACK, 0);
  20.   wnd->PostMessage(WM_KEYUP, VK_BACK, 0);
  21.   EnumChildWindows(wnd->GetSafeHwnd(), EnumChildProc, 0);
  22.   acedPostCommandPrompt();
  23.   acedPrompt(L"");
  24. }
  25.  

Проверял только в AutoCAD 2017:

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
По факту, после закрытия диалогового окна в командной строке висит название команды. И, только если клацнуть на командную строку и на клавиатуре нажать "Backspace", команда продолжается.
Как раз нет. Программа продолжала работу до клацания в командной строке (во всяком случае если речь шла о тестовой программе), просто в командной строке это не отображалось. Не сложно было проверить с отладчиком.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
то что нужно, спасибо огрооооомное :)
Цитировать
Вообще же вызывать диалоговое окно из фильтра событий - это извращение.
ну, это первое, что пришло на ум.

сейчас пытаюсь разработать новый механизм защиты. Ну и если в двух словах - есть серверная ARX, которая занимается обработкой файла лицензии, загрузкой-выгрукой защищаемых arx-ин. Есть "подзащитные" arx-ины. Серверная их грузит и ждет, когда начнут запускаться команды. Также, "подзащитные" в момент своей загрузки проверяют наличие загруженной серверной. Ну и чтоб нельзя было просто подменить серверную - обмениваются с ней сообщениями (типа вопрос-ответ).
В момент запуска команд из поздащитных arx-ин, серверная проверяет возможность запуска.  Чтоб не городить огород с этим самым обменом сообщениями (хуки, общая оперативная память, системные таблицы виндузов, заргузочный сектор :) и т.п.), решил устроить обмен через пользовательские переменные автокада.
ну и собственно говоря, когда серверная arx-ина выясняет, что, например, закончился временный период (а это как раз и происходит в функции sysVarChanged), то появляется окно, в котором пользователь может ввести код разблокировки, для продолжения работы программы.

PS: повторюсь, на мой взгляд это самый простой вариант организации обмена информацией (ну как информацией, там то всего 16 символов передаются) между двумя различными arx-инами.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
PS: повторюсь, на мой взгляд это самый простой вариант организации обмена информацией (ну как информацией, там то всего 16 символов передаются) между двумя различными arx-инами.
Я бы так делать не стал. Использование системных переменных запросто может войти в противоречие с какими-нибудь простейшими lisp-программами.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Я бы так делать не стал. Использование системных переменных запросто может войти в противоречие с какими-нибудь простейшими lisp-программами.

хм... а на пальцах объяснить можете, какие могут быть противоречия?
вот полный код функций, которые собственно и запускают механизм защиты
Код - C++ [Выбрать]
  1. void CSysVarReactor::sysVarChanged(const ACHAR *varName, Adesk::Boolean success)
  2. {
  3.         if (canUseSysVar) // см. функцию commandWillStart
  4.         {
  5.                 if (_tcsstr(varName, CONTROLVAR)) // поменялась именно переменная, которую отслеживает сервер
  6.                 {
  7.                         resbuf buf;
  8.                         acedGetVar(CONTROLVAR, &buf);
  9.                         if (_tcscmp(answerValue, buf.resval.rstring) != 0) // это пришел запрос
  10.                         {
  11.                                 answerValue = buf.resval.rstring; //answerValue - строковая переменная
  12.                                 if (!answerValue.IsEmpty())
  13.                                 {
  14.                                         CString mapa = MAPB; // карта шифрования
  15.                                         for (int i = 0; i < answerValue.GetLength(); i++)
  16.                                         {
  17.                                                 CString newCharSymb = answerValue[i];
  18.                                                 int pos = mapa.FindOneOf(newCharSymb);
  19.                                                 answerValue.SetAt(i, MAPC[pos]); // формируем строку ответа по другой карте шифрования
  20.                                         }
  21.                                         resbuf *rb = acutBuildList(RTSTR, answerValue.GetString(), RTNONE);
  22.                                         acedSetVar(CONTROLVAR, rb); // выплюнули ответ (тут уже клиентская arx получает ответ и если всё плохо выгружается из автокада)
  23.                                         acutRelRb(rb);
  24.  
  25.                                         vzhyhk = !pSecurity->isSecured(moduleType); // проверка работоспособности конкретного модуля
  26.                                         if (vzhyhk) // вжуууух. тут начитается магия ))). вернее, магия начинается после того, как закончит работать эта функция (по крайней мере, сообщение acedAlert появляется первым)
  27.                                         {// пользователь должен знать, почему наступила Ж*ПА :)
  28.                                                 acedAlert(pSecurity->getPossibleError().GetString());
  29.                                         }
  30.                                 }
  31.                         }
  32.                 }
  33.         }
  34.  
  35.         AcEditorReactor::sysVarChanged(varName, success);
  36. }
  37.  
  38. void CSysVarReactor::commandWillStart(const ACHAR *cmdStr)
  39. {
  40.         moduleType = EMPTY; // переменная, отвечающая за тип модуля
  41.         CString lowerCaseStr = cmdStr;
  42.         lowerCaseStr.MakeLower();
  43.         //-> проверяем, с каких символов начинается команда. нас интересуют только НАШИ команды
  44.         if ( (lowerCaseStr.Find(_T("sm_")) == 0) || (lowerCaseStr.Find(_T("fm_")) == 0) )
  45.         {
  46.                 moduleType = SAMARA_FATAMORGANA;
  47.         }
  48.         else if ( (lowerCaseStr.Find(_T("plpr_")) == 0) || (lowerCaseStr.Find(_T("pl_")) == 0) )
  49.         {
  50.                 moduleType = SURFACE_PLANNING;
  51.         }
  52.         else if (lowerCaseStr.Find(_T("vx_")) == 0)
  53.         {
  54.                 moduleType = BLOCK_MODEL;
  55.         }
  56.         else if (lowerCaseStr.Find(_T("bvr_")) == 0)
  57.         {
  58.                 moduleType = DRIL_N_BLAST;
  59.         }
  60.         //<-
  61.  
  62.         if (moduleType != EMPTY)
  63.                 canUseSysVar = true; // это наш клиент. иначе sysVarChanged работает в холостую
  64.  
  65.         AcEditorReactor::commandWillStart(cmdStr);
  66. }
  67.  
  68. void CSysVarReactor::commandEnded(const ACHAR* cmdStr)
  69. {
  70.         canUseSysVar = false;
  71.         AcEditorReactor::commandEnded(cmdStr);
  72. }
  73.  
  74. void CSysVarReactor::commandCancelled(const ACHAR* cmdStr)
  75. {
  76.         canUseSysVar = false;
  77.         AcEditorReactor::commandCancelled(cmdStr);
  78. }
  79.  
  80. void CSysVarReactor::commandFailed(const ACHAR* cmdStr)
  81. {
  82.         canUseSysVar = false;
  83.         AcEditorReactor::commandFailed(cmdStr);
  84. }
  85.  

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

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
единственный вариант противоречий возможен, только если чужая команда, которая начинается с наших зарегистрированных символов ))) также выплевывает какой-то текст любой длины в переменную, которую я мониторю. но, на работоспособность той лисп функции это никак не скажется (если она потом не читает данные из той же переменной ))). увы, то, что приходит туда - видоизменяется внутри sysVarChanged)
Я как раз об этом и писал. Использование системных переменных USERSN часто возможно в интерфейсе lisp<->vba для передачи значений.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Я как раз об этом и писал. Использование системных переменных USERSN часто возможно в интерфейсе lisp<->vba для передачи значений.

т.е. с вероятностью 0.000000001% сторонняя лисп-функция будет не корректно работать.
и чтоб свести эту вероятность к твердому нулю, заботясь о других разработчиках, мне нужно сделать полноценное клиент-серверное приложение, где клиентскую часть нужно создавать каждый раз, как запускается команда ))). не, увольте :):):) я готов пойти на такие жертвы.
к тому же, если что, создателя лиспа можно совершенно справедливо послать в автодесковский документ по разграничению имен команд.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Николай Горлов
Твоё дело - уговаривать не буду. Но я бы пошел другим путём. Например, экспорт функций, который позволил бы вызывать их из других arx-файлов. 
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение