Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Lemieux от 22-10-2019, 19:57:15

Название: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 19:57:15
Всех приветствую.

Имеется вот такие две части кода

Код - vb.net [Выбрать]
  1. Dim lxDesign As ResultBuffer = LispExtensions.GetLispSym("lxDesign")
  2. Dim lxDesignDate As ResultBuffer = LispExtensions.GetLispSym("lxDesignDate")
  3. Dim lxChecking As ResultBuffer = LispExtensions.GetLispSym("lxChecking")
  4. Dim lxCheckingDate As ResultBuffer = LispExtensions.GetLispSym("lxCheckingDate")

Код - vb.net [Выбрать]
  1. Dim lxArray As Array
  2. Dim lxString As String
  3.  
  4. lxArray = lxDesign.AsArray
  5. lxString = lxArray(0).value
  6. TB_11.Text = lxString
  7.  
  8. lxArray = lxDesignDate.AsArray
  9. lxString = lxArray(0).value
  10. TB_21.Text = lxString
  11.  
  12. lxArray = lxChecking.AsArray
  13. lxString = lxArray(0).value
  14. TB_12.Text = lxString
  15.  
  16. lxArray = lxCheckingDate.AsArray
  17. lxString = lxArray(0).value
  18. TB_22.Text = lxString
Это части кода, который создаёт окно. Логика работы такая - при инициализации берутся переменные лиспа, есть они или нет в чертеже. Потом заполняются или редактируются поля, считываются и отправляются обратно в переменные лиспа. Мне интересно, возможно ли записать данные примеры циклом, чтобы было меньше строк. В автолиспе я делал это через (eval (read variable)). В VB.NET не могу найти информацию и не хватает опыта.

Конструкция типа:
Код - vb.net [Выбрать]
  1. Dim lxStringCollection = New String() {"lxDesign", "lxDesignDate", "lxChecking", "lxCheckingDate"}
  2. Dim lxTBCollection = New String() {"TB_11", "TB_21", "TB_12", "TB_22"}
  3.  
  4. For lxItem = 0 To lxStringCollection.GetUpperBound(0)
  5.   lxResultBuffer.Add(LispExtensions.GetLispSym(lxItem))
  6. Next
  7.  
  8. Dim lxIndex = 0
  9. For Each lxBuffer As TypedValue In lxResultBuffer
  10.   Dim lxStringBuffer As String = lxTBCollection(lxIndex) & ".text = lxBuffer.Value"
  11.   Dim lxTable = New System.Data.DataTable()
  12.   Convert.ToDouble(lxTable.Compute(lxStringBuffer, Nothing))
  13.   lxIndex += 1
  14. Next
Вылетает с критической ошибкой AutoCAD.

И второй вопрос.
Первый вариант окна я делал с помощью класса, написанного Александром Ривилисом https://forums.autodesk.com/t5/net/acedgetsym-and-acedputsym-in-net-applications/td-p/1635754 и переработанного для VB.net https://www.theswamp.org/index.php?topic=35714.0. Но изучая хелп по API .NET я наткнулся на тот факт, что в API реализованы данные методы. Нашёл пример использования этих методов на C# https://adndevblog.typepad.com/autocad/2014/08/set-or-get-lisp-symbol-in-net.html. И метод Set* работал отлично, но метод Get* не хотел работать, при отладке выдавало исключение, если в переменной находилось значение String. Изначально я неправильно переписал код с C# на VB.NET. Когда я точно повторил пример на сайте, то уже выдавало не просто исключение, а указывало на то, что объект String не может быть сконвертирован в TypedValue.

Я решил проблему двумя способами:
Код - vb.net [Выбрать]
  1. Dim lxDesign As Object = lxDocument.GetLispSymbol("lxDesignPE4")
  2. If Not String.IsNullOrEmpty(lxDesign) Then
  3.   TB_11.Text = lxDesign.ToString
  4. End If
Код - vb.net [Выбрать]
  1. Dim lxDesign = New TypedValue(CInt(LispDataType.Text), lxDocument.GetLispSymbol("lxDesignPE4"))
  2. TB_11.Text = lxDesign.Value
И если кто может объяснить чем эти способы различаются и могут повлиять на AutoCAD. Либо они равнозначны и можно делать как удобно.

PS Прошу особо не пинать за, может быть, глупые и непонятные вопросы, изучаю AutoLISP с лета этого года, а VB.NET пару недель.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 21:09:33
Приветствую на форуме!
изучаю AutoLISP с лета этого года, а VB.NET пару недель.
Рекомендую бросить изучать VB.NET и начать изучать C#.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 21:17:35
Вылетает с критической ошибкой AutoCAD.
Что говорит пошаговая отладка? И что за критическая ошибка?
Я решил проблему двумя способами:
Как по мне первый вариант предпочтительней, но особой разницы (особенно на VB.NET) я не вижу.

P.S.: Однозначно одна из ошибок здесь:
Код - vb.net [Выбрать]
  1. For lxItem = 0 To lxStringCollection.GetUpperBound(0)
  2.   lxResultBuffer.Add(LispExtensions.GetLispSym(lxItem))
  3. Next
Должно быть как-то так (на VB.NET не пишу):
Код - vb.net [Выбрать]
  1. For lxItem = 0 To lxStringCollection.GetUpperBound(0)
  2.   lxResultBuffer.Add(LispExtensions.GetLispSym(lxStringCollection(lxItem)))
  3. Next
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 21:51:20
Нашёл пример использования этих методов на C# https://adndevblog.typepad.com/autocad/2014/08/set-or-get-lisp-symbol-in-net.html. И метод Set* работал отлично, но метод Get* не хотел работать, при отладке выдавало исключение, если в переменной находилось значение String.
Похоже, что в статье ошибка, о чем в комментарии к ней написано. Document.GetLispSymbol возвращает Object, а не TypedValue.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 22:01:46
Рекомендую бросить изучать VB.NET и начать изучать C#.
Александр, а можете вкратце объяснить почему C# предпочтительнее? Я читал закреплённые темы Андрея Бушмана про книги и тему про изучение C#, но пока что не понял преимущества C# над VB.NET.

AutoCAD вылетает при операции добавления в ResultBuffer.
Код - vb.net [Выбрать]
  1. For lxItem = 0 To lxStringCollection.GetUpperBound(0)
  2.   lxResultBuffer.Add(LispExtensions.GetLispSym(lxStringCollection(lxItem)))
  3. Next

Он объявляется глобально
Код - vb.net [Выбрать]
  1. Public lxResultBuffer As ResultBuffer

Похоже, что в статье ошибка, о чем в комментарии к ней написано. Document.GetLispSymbol возвращает Object, а не TypedValue.
Вы правы, я в хелпе сразу видел, что он возвращает Object, но так как не имею своего опыта, понадеялся на опыт человека, написавшего статью.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 22:09:33
Александр, а можете вкратце объяснить почему C# предпочтительнее?
Вкратце - на C# значительно больше примеров, он красивее, лаконичнее, роднее для .NET
VB.NET - это искусственное образование из учебного Basic, с грехом пополам адаптированное для работы с .NET
Лично мне крайне неприятно читать код, написанный на нём.
Он объявляется глобально
Код - vb.net [Выбрать]

    Public lxResultBuffer As ResultBuffer
А где оно инициализировано? Должно быть где-то
Код - vb.net [Выбрать]
  1. lxResultBuffer = new ResultBuffer()
до вызовов lxResultBuffer.Add(...).
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 22:35:11
А где оно инициализировано? Должно быть где-то
Я думал, что инициализация происходит во время объявления глобальной переменной. Я добавил инициализацию перед выполнением цикла, ничего не изменилось. Хочу заметить, что AutoCAD крашится независимо от того есть ли в чертеже переменная, либо она просто пустая, либо с данными String.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 22:39:17
Я думал, что инициализация происходит во время объявления глобальной переменной.
Нет.
Хочу заметить, что AutoCAD крашится независимо от того есть ли в чертеже переменная, либо она просто пустая, либо с данными String.
А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?
Какая версия и разрядность AutoCAD? Где код LispExtensions.GetLispSym?
Вообще-то после появления в AutoCAD .NET API методов Document.GetLispSymbol/Document.SetLispSymbol потребность в использовании P/Invoke для acedGetSym/acedSetSym отпала. Тем более, что использование их сопряжено с определенными сложностями (начиная с AutoCAD 2013 вместо "acad.exe" используется "accore.dll" и сигнатура функции претерпела изменения - вместо "acedGetSym" в AutoCAD 2020 x64 "?acedGetSym@@YAHPEB_WPEAPEAUresbuf@@@Z").
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 23:01:04
А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?
Это я уже завтра потестирую

Какая версия и разрядность AutoCAD?
Простой английский AutoCAD x64.

Где код LispExtensions.GetLispSym?
Код брал вот отсюда http://www.theswamp.org/index.php?topic=35714.msg460016#msg460016 , там же и упоминается о том, что произошли изменения после 2013 версии.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 23:01:51
Простой английский AutoCAD x64.
Версия какая???
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 23:07:06
Простой английский AutoCAD x64.
Версия какая???
Блин, я уже сплю  :) Версия 2018
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 22-10-2019, 23:08:41
Блин, я уже сплю  :) Версия 2018
Теоретически замена "acad.exe" на "accore.dll" должна была помочь. Завтра проверю.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 22-10-2019, 23:20:18
Блин, я уже сплю  :) Версия 2018
Теоретически замена "acad.exe" на "accore.dll" должна была помочь. Завтра проверю.

Так если я делаю без цикла, а просто

Код - vb.net [Выбрать]
  1. Dim lxDesign As ResultBuffer = LispExtensions.GetLispSym("lxDesign")

то всё работает.

Я ведь правильно понимаю, что метод Add аналогичен вот такому добавлению?

Код - vb.net [Выбрать]
  1. Dim input As New ResultBuffer(
  2. New TypedValue(CInt(LispDataType.ListBegin)),
  3. New TypedValue(CInt(LispDataType.Int16), 12),
  4. New TypedValue(CInt(LispDataType.Text), "toto"),
  5. New TypedValue(CInt(LispDataType.T_atom)),
  6. New TypedValue(CInt(LispDataType.ListEnd)))
Хотя, пример со списком не совсем корректен...

И ещё хочу уточнить, что мне нужно получить не список строк для лиспа, а мне нужен массив ResultBuffer. Но я пытался сделать вот так
Код - vb.net [Выбрать]
  1. Public lxDesign As ResultBuffer()
При добавлении в массив по индексу AutoCAD уже не крашился, а вылетало исключение при следующей итерации.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 09:09:20
Я ведь правильно понимаю, что метод Add аналогичен вот такому добавлению?
Вообще-то ResultBuffer.Add работает с TypedValue, а не с ResultBuffer. В этом может быть ошибка.
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 11:00:40
Имеется вот такие две части кода

Код - vb.net [Выбрать]
  1. Dim lxDesign As ResultBuffer = LispExtensions.GetLispSym("lxDesign")
  2. Dim lxDesignDate As ResultBuffer = LispExtensions.GetLispSym("lxDesignDate")
  3. Dim lxChecking As ResultBuffer = LispExtensions.GetLispSym("lxChecking")
  4. Dim lxCheckingDate As ResultBuffer = LispExtensions.GetLispSym("lxCheckingDate")

Код - vb.net [Выбрать]
  1. Dim lxArray As Array
  2. Dim lxString As String
  3.  
  4. lxArray = lxDesign.AsArray
  5. lxString = lxArray(0).value
  6. TB_11.Text = lxString
  7.  
  8. lxArray = lxDesignDate.AsArray
  9. lxString = lxArray(0).value
  10. TB_21.Text = lxString
  11.  
  12. lxArray = lxChecking.AsArray
  13. lxString = lxArray(0).value
  14. TB_12.Text = lxString
  15.  
  16. lxArray = lxCheckingDate.AsArray
  17. lxString = lxArray(0).value
  18. TB_22.Text = lxString
Это части кода, который создаёт окно. Логика работы такая - при инициализации берутся переменные лиспа, есть они или нет в чертеже. Потом заполняются или редактируются поля, считываются и отправляются обратно в переменные лиспа. Мне интересно, возможно ли записать данные примеры циклом, чтобы было меньше строк. В автолиспе я делал это через (eval (read variable)). В VB.NET не могу найти информацию и не хватает опыта.

Конструкция типа:
Код - vb.net [Выбрать]
  1. Dim lxStringCollection = New String() {"lxDesign", "lxDesignDate", "lxChecking", "lxCheckingDate"}
  2. Dim lxTBCollection = New String() {"TB_11", "TB_21", "TB_12", "TB_22"}
  3.  
  4. For lxItem = 0 To lxStringCollection.GetUpperBound(0)
  5.   lxResultBuffer.Add(LispExtensions.GetLispSym(lxItem))
  6. Next
  7.  
  8. Dim lxIndex = 0
  9. For Each lxBuffer As TypedValue In lxResultBuffer
  10.   Dim lxStringBuffer As String = lxTBCollection(lxIndex) & ".text = lxBuffer.Value"
  11.   Dim lxTable = New System.Data.DataTable()
  12.   Convert.ToDouble(lxTable.Compute(lxStringBuffer, Nothing))
  13.   lxIndex += 1
  14. Next
Вылетает с критической ошибкой AutoCAD.
Это потому, что, несмотря на использование .NET, Вы продолжаете думать на LISP. То есть, Вы совершенно игнорируете новые возможности и пытаетесь адаптировать .NET под логику LISP. Разумеется, что ничего хорошего из этого не выйдет.
Как вариант, что можно сделать.
1. Вместо двух несвязанных между собой коллекций из названий переменных и имён текстбоксов можно создать словарь Dictionary<string, TextBox> с ключом-строкой с именем переменной и соответствующим ему значением типа TextBox (в .NET можно создавать коллекции из объектов) вида: ["lxDesign" - TB_11], ["lxDesignDate" - TB_21], ["lxChecking", TB_12]
2. Пройтись foreach по этому словарю, беря по очереди ключ и значение и выполняя операцию по занесению значения переменной в текстбокс.
На VB.NET не пишу, поэтому, примера не будет.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 11:37:15
Вообще-то ResultBuffer.Add работает с TypedValue, а не с ResultBuffer. В этом может быть ошибка.
Александр, я пробовал добавлять с помощью Typedvalue, но всё равно AutoCAD крашится.

Это потому, что, несмотря на использование .NET, Вы продолжаете думать на LISP. То есть, Вы совершенно игнорируете новые возможности и пытаетесь адаптировать .NET под логику LISP. Разумеется, что ничего хорошего из этого не выйдет.
Дмитрий, я знаю про словари, но у меня стринговые переменные, например "lxDesign", не только читаются из чертежа, но и потом присваиваются обратно, о чём я писал в начале. Я может не понимаю Вашей мысли, Вы не могли написать пример на C#. Да и вряд ли краш AutoCAD связан с тем, что я пишу так как в начальном примере, а не с помощью словаря.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 11:44:51
Lemieux,
Цитата: Александр Ривилис от 22-10-2019, 22:39:17

    А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?

Это я уже завтра потестирую
И? Какой результат?
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 11:48:22
Александр, я пробовал добавлять с помощью Typedvalue, но всё равно AutoCAD крашится.
Каким образом? Я не вижу кода, которым вы это делаете и поэтому не могу проверить. Создайте специальный тестовый проект, в котором будете только читать и писать lisp-переменные. Я его протестирую.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 11:58:05
И? Какой результат?
Я пока что на работе, когда дома буду, то выложу все результаты.

Каким образом? Я не вижу кода, которым вы это делаете и поэтому не могу проверить. Создайте специальный тестовый проект, в котором будете только читать и писать lisp-переменные. Я его протестирую.
Делал примерно так
Код - vb.net [Выбрать]
  1. lxResultBuffer.Add(New TypedValue(CInt(LispDataType.Text), (LispExtensions.GetLispSym(lxStringCollection(lxItem))))
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 12:27:02
Делал примерно так
Код - vb.net [Выбрать]

    lxResultBuffer.Add(New TypedValue(CInt(LispDataType.Text), (LispExtensions.GetLispSym(lxStringCollection(lxItem))))
Очевидно, что это ерунда. TypedValue - это один из элементов в ResultBuffer
Соответственно, должно было быть что-то типа:
Код - vb.net [Выбрать]
  1. For Each tv As TypedValue In LispExtensions.GetLispSym(lxStringCollection(lxItem)))
  2.  lxResultBuffer.Add(tv)
  3. Next

P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 12:34:25
Я может не понимаю Вашей мысли, Вы не могли написать пример на C#.
Код - C# [Выбрать]
  1. Dictionary<string, TextBox> varAndBoxesDict
  2.     = new Dictionary<string, TextBox>
  3.     {
  4.         { "lxDesign", TB_11 },
  5.         { "lxDesignDate", TB_21 },
  6.         { "lxChecking", TB_12 },
  7.         { "lxCheckingDate", TB_22 },
  8.     };
  9.  
  10.  
  11. // Переносим значения из переменных в текстбоксы
  12. foreach (KeyValuePair<string, TextBox> pair in varAndBoxesDict)
  13. {                
  14.     string text =
  15.         // Вспомогательный метод, который вытаскивает строку, сохранённую в LISP-переменной
  16.         LispExtensions.GetTextFromLispVariable(pair.Key);
  17.     pair.Value.Text = text ?? string.Empty;
  18. }
  19.  
  20. // Переносим значения из текстбоксов в переменные
  21. foreach (KeyValuePair<string, TextBox> pair in varAndBoxesDict)
  22. {
  23.     string text = pair.Value.Text?.Trim() ?? string.Empty;
  24.     // Вспомогательный метод, который записывает строку в LISP-переменную
  25.     LispExtensions.SetLispSym(pair.Key, text);
  26. }
  27.  
Да и вряд ли краш AutoCAD связан с тем, что я пишу так как в начальном примере, а не с помощью словаря.
Возможно. Я неправильно выразился. Я имел в виду, что такие сложные действия в коде являются следствием попытки реализовать операции через одно место через логику LISPа :)
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 12:50:39
P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET
Я последую Вашему совету и следующую работу выполню на C#

Я имел в виду, что такие сложные действия в коде являются следствием попытки реализовать операции через одно место через логику LISPа
Согласен, что через логику лиспа, но мне интересны различные варианты реализации, для этого я и создал эту тему. Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги. У меня была задача написать скрипты для автоматической формирований связей между элементами схемы, автоматического формирования остальных документов из схемы Э4. Я сделал, времени читать книги не было, разбираюсь на ходу.
Спасибо за пример.
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 13:01:12
Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги. У меня была задача написать скрипты для автоматической формирований связей между элементами схемы, автоматического формирования остальных документов из схемы Э4. Я сделал, времени читать книги не было, разбираюсь на ходу.
Да это, в общем-то, вполне нормальный подход: практика + теория. Главное - не пренебрегать чем-то одним. Читать книги обязательно надо, применять полученные знания на практике тоже очень важно. То, что задаёте вопросы - вообще отлично! Многие почему-то стесняются. Ну и готовьтесь к тому, что всё что вы сейчас напишете через год-два либо выкинете, либо будете переписывать заново ;)
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 13:07:51
Ну и готовьтесь к тому, что всё что вы сейчас напишете через год-два либо выкинете, либо будете переписывать заново
Так я к этому давно привык, ещё во времена, когда писал на Python и Mel интерфейсы и конвертеры шейдеров в Maya. Даже сейчас, за эти месяцы изучения и практики я нахожу более практичные реализации задач и, просматривая старый код, думаю - "Неправильно я написал, надо было делать по другому." Вообще у меня был такой план. Я пишу дополнение на лисп для создания КД шкафов РЗА, потом изучаю .NET и пишу дополнение для создания КД шкафов НКУ. Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET. VB.NET я выбрал только из-за того, что у меня были видео уроки по созданию плагинов для AutoCAD на VB.NET.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 13:08:16
Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги.
Эти эксперименты могут отнять много времени, которое можно было потратить на что-то другое более полезное. Впрочем ваше дело...
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 13:09:40
VB.NET я выбрал только из-за того, что у меня были видео уроки по созданию плагинов для AutoCAD на VB.NET.
Там же были уроки по созданию плагинов на C# для AutoCAD. На каком-то из C-подобных языков вы уже что-то писали?
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 13:26:11
Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET.
Так-так-так... Теперь понятны попытки скрестить лисп с нетом. То есть, нужен диалог для изменения каких-то лисповых данных? А есть уверенность, что подход выбран правильный? Я про то, что данные можно передавать по другому - не через считывание-запись лисповых переменных, а с помощью передачи аргументов в самописную лисп-функцию, которая после завершения диалога будет возвращать полученные в нём значения.
Типа такого:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq
  2.         res (run-my-dialog lxDesign lxDesignDate lxChecking lxCheckingDate)
  3.         lxDesign (nth 0 res)
  4.         lxDesignDate (nth 1 res)
  5.         lxChecking (nth 2 res)
  6.         lxCheckingDate (nth 3 res)
  7. )
Функцию run-my-dialog написать на .NET. Она будет принимать строковые значения, запускать диалог по их изменению и возвращать список новых значений после закрытия диалога.
P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET
+1
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 13:28:52
Функцию run-my-dialog написать на .NET. Она будет принимать строковые значения, запускать диалог по их изменению и возвращать список новых значений после закрытия диалога.
Именно так. Или всё полностью пишется на .NET (C#/VB.NET) или на .NET пишется функции, к которым обращаются из lisp.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 13:45:48
На каком-то из C-подобных языков вы уже что-то писали?
Нет

Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET.
Так-так-так... Теперь понятны попытки скрестить лисп с нетом. То есть, нужен диалог для изменения каких-то лисповых данных? А есть уверенность, что подход выбран правильный? Я про то, что данные можно передавать по другому - не через считывание-запись лисповых переменных, а с помощью передачи аргументов в самописную лисп-функцию, которая после завершения диалога будет возвращать полученные в нём значения.
Типа такого:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq
  2.         res (run-my-dialog lxDesign lxDesignDate lxChecking lxCheckingDate)
  3.         lxDesign (nth 0 res)
  4.         lxDesignDate (nth 1 res)
  5.         lxChecking (nth 2 res)
  6.         lxCheckingDate (nth 3 res)
  7. )
Функцию run-my-dialog написать на .NET. Она будет принимать строковые значения, запускать диалог по их изменению и возвращать список новых значений после закрытия диалога.
P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET
+1
Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.
То есть я делал конструкцию типа:
Код - vb.net [Выбрать]
  1. <LispFunction("Window")>
  2. //тут инициализовал окно
и AutoCAD вылетал.

Работает всё это только из команды:
Код - vb.net [Выбрать]
  1. <CommandMethod("Window")>
  2. //тут инициализовал окно

Или всё полностью пишется на .NET (C#/VB.NET) или на .NET пишется функции, к которым обращаются из lisp.
Согласен, но пришлось прибегнуть к такому способу, так как чтобы переписать весь код на .net уйдёт слишком много времени.
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 13:54:59
Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.
То есть я делал конструкцию типа:
Код - vb.net [Выбрать]
  1. <LispFunction("Window")>
  2. //тут инициализовал окно
и AutoCAD вылетал.
Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 13:58:44
Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.
Может быть. Тогда попробую реализовать окно через функции лиспа, когда буду переписывать окно для создания клемного ряда.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 23-10-2019, 14:35:28
Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.
То есть я делал конструкцию типа:
Код - vb.net [Выбрать]
  1. <LispFunction("Window")>
  2. //тут инициализовал окно
и AutoCAD вылетал.
Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.
100% проблема в самой форме (создание, запуск, события кнопок...)
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 14:38:05
Небольшая демонстрация того, как это работает.

Лисп:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq
  2.   data "Привет, .NET!"
  3.   res (run-custom-dialog data))
  4. (if res (setq data res))
  5. (alert data)
.NET:
Код - C# [Выбрать]
  1. [LispFunction("run-custom-dialog")]
  2. public string RunDia(ResultBuffer rb)
  3. {
  4.     string data = rb?
  5.         .AsArray()
  6.         .FirstOrDefault()
  7.         .Value.ToString()
  8.         ?? "*error*";
  9.  
  10.     CustomDialog customDialog = new CustomDialog();
  11.     customDialog.Data = data;
  12.     var res = Application.ShowModalDialog(customDialog);
  13.     if (res != System.Windows.Forms.DialogResult.Cancel)
  14.     {
  15.         return customDialog.Data;
  16.     }
  17.     else
  18.     {
  19.         return null;
  20.     }
  21. }
  22.  
Весь проект для VS2019 - в приложенном архиве.
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 14:40:21
Дмитрий, спасибо
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 21:55:12
Небольшая демонстрация того, как это работает.

Лисп:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq
  2.   data "Привет, .NET!"
  3.   res (run-custom-dialog data))
  4. (if res (setq data res))
  5. (alert data)
.NET:
Код - C# [Выбрать]
  1. [LispFunction("run-custom-dialog")]
  2. public string RunDia(ResultBuffer rb)
  3. {
  4.     string data = rb?
  5.         .AsArray()
  6.         .FirstOrDefault()
  7.         .Value.ToString()
  8.         ?? "*error*";
  9.  
  10.     CustomDialog customDialog = new CustomDialog();
  11.     customDialog.Data = data;
  12.     var res = Application.ShowModalDialog(customDialog);
  13.     if (res != System.Windows.Forms.DialogResult.Cancel)
  14.     {
  15.         return customDialog.Data;
  16.     }
  17.     else
  18.     {
  19.         return null;
  20.     }
  21. }
  22.  
Весь проект для VS2019 - в приложенном архиве.

Дмитрий, изучил Ваш пример. Вы делаете на WinForm,а я делаю окна на WPF. Сейчас как не пытался, так и не вызывает окно. Исключения при отладке не возникает, AutoCAD не крашится, просто в логе AutoCAD выводится вот такое
Код - Auto/Visual Lisp [Выбрать]
  1. System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
  2.    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
  3.    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
  4.    at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object commandObject, Boolean bLispFunction)
  5.    at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorkerWithExceptionFilter(MethodInfo mi, Object commandObject, Boolean bLispFunction)
  6.    at Autodesk.AutoCAD.Runtime.PerDocumentCommandClass.Invoke(MethodInfo mi, Boolean bLispFunction)
  7.    at Autodesk.AutoCAD.Runtime.CommandClass.CommandThunk.InvokeLisp(); error: ADS request error

Сам код имеет вот такой вид

Код - vb.net [Выбрать]
  1. Imports Autodesk.AutoCAD.Runtime
  2. Imports Autodesk.AutoCAD.ApplicationServices
  3. Imports Autodesk.AutoCAD.DatabaseServices
  4.  
  5. Public Class Initialization
  6.     <LispFunction("lmxWindowTest")>
  7.     Public Sub lmxDisplayFullName()
  8.         Dim WinTest As tWindow = New tWindow()
  9.         Application.ShowModalWindow(WinTest)
  10.     End Sub
  11. End Class
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 23-10-2019, 22:20:49
Метод лисп-функции должен иметь входной параметр типа ResultBuffer, даже если лисп-функция не будет иметь аргументов. А у Вас пустые скобки, то есть, входных параметров нет.
https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-NET/files/GUID-3B2760FE-A0DC-4229-AEBE-5CC83290BA95-htm.html
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 23-10-2019, 22:54:34
Метод лисп-функции должен иметь входной параметр типа ResultBuffer, даже если лисп-функция не будет иметь аргументов. А у Вас пустые скобки, то есть, входных параметров нет.
https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-NET/files/GUID-3B2760FE-A0DC-4229-AEBE-5CC83290BA95-htm.html
ёмоё. Я изначально делал по примеру из хелпа по API и не работало, сюда я скопировал последний вариант пробы. Моя невнимательность.
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 24-10-2019, 09:03:16
Ну зато теперь на всю жизнь запомните  8)
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 30-10-2019, 19:38:24
А кто-то может подсказать как тип Object преобразовать в TypedValue?

Я делаю вот так
Код - C# [Выбрать]
  1. object lxCollectionTB = lxDocument.GetLispSymbol("lmxNameTerminals");
  2. TypedValue[] lxType = (TypedValue[])lxCollectionTB;

В лисп переменной у меня хранится список из строк. И при выполнении кода переменная "lxCollectionTB" хранит в себе "TypeValue[]".

Но что-то мне подсказывает, что можно и по другому.

Сразу напрашивается вопрос - зачем мне это?
По советам выше я пробовал сделать через "LispFunction", но пришёл к выводу, что мне удобнее хранить в переменной и вызывать окно через "CommandMethod".

PS Хочу поблагодарить за советы выше. Я попробовал все варианты и сократил код, с помощью словарей примерно в 2 раза.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 19:44:26
Lemieux,
Как я понимаю lxDocument.GetLispSymbol("lmxNameTerminals") возвращает ResultBuffer
Соответственно:
Код - C# [Выбрать]
  1.     object lxCollectionTB = lxDocument.GetLispSymbol("lmxNameTerminals");
  2.     TypedValue[] lxType = lxCollectionTB.AsArray();
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 30-10-2019, 19:47:14
Lemieux,
Как я понимаю lxDocument.GetLispSymbol("lmxNameTerminals") возвращает ResultBuffer
Соответственно:
Код - C# [Выбрать]
  1.     object lxCollectionTB = lxDocument.GetLispSymbol("lmxNameTerminals");
  2.     TypedValue[] lxType = lxCollectionTB.AsArray();
Александр, в том-то и дело, что по хелпу он возвращает Object. С ResultBuffer было бы просто.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 19:48:32
Lemieux,
Сечас перепроверю.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 20:21:40
Да именно так и следует делать:
Код - C# [Выбрать]
  1. TypedValue[] lxType = (TypedValue[])lxCollectionTB;
Только желательно сначала проверить не равен ли случайно lxCollectionTB null (если такой переменной нет или она nil)

(https://live.staticflickr.com/65535/48986914917_560bed905e_o.png)
Впрочем возможен вариант, что в этой переменной не список и тогда преобразовывать в TypedValue[] нельзя.
Правильнее вот так:

Код - C# [Выбрать]
  1. [CommandMethod("GetLispVar")]
  2. public void GetLispVar()
  3. {
  4.   Document doc = Application.DocumentManager.MdiActiveDocument;
  5.   if (doc == null) return;
  6.  
  7.   Editor ed = doc.Editor;
  8.   PromptResult rs =  ed.GetString("\nУкажите имя переменной: ");
  9.   if (rs.Status == PromptStatus.OK)
  10.   {
  11.     var o = doc.GetLispSymbol(rs.StringResult);
  12.     if (o != null && o is TypedValue[])
  13.     {
  14.       TypedValue[] tvs = o as TypedValue[];
  15.       foreach (TypedValue tv in tvs)
  16.       {
  17.         ed.WriteMessage($"\n{tv.TypeCode} - {tv.Value}");
  18.       }
  19.     } else
  20.     {
  21.       ed.WriteMessage($"\n{o}");
  22.     }
  23.   }
  24. }
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 30-10-2019, 20:37:55
Да именно так и следует делать:
Код - C# [Выбрать]
  1. TypedValue[] lxType = (TypedValue[])lxCollectionTB;
Только желательно сначала проверить не равен ли случайно lxCollectionTB null (если такой переменной нет или она nil)

(https://live.staticflickr.com/65535/48986914917_560bed905e_o.png)
Впрочем возможен вариант, что в этой переменной не список и тогда преобразовывать в TypedValue[] нельзя.
Правильнее вот так:

Код - C# [Выбрать]
  1. [CommandMethod("GetLispVar")]
  2. public void GetLispVar()
  3. {
  4.   Document doc = Application.DocumentManager.MdiActiveDocument;
  5.   if (doc == null) return;
  6.  
  7.   Editor ed = doc.Editor;
  8.   PromptResult rs =  ed.GetString("\nУкажите имя переменной: ");
  9.   if (rs.Status == PromptStatus.OK)
  10.   {
  11.     var o = doc.GetLispSymbol(rs.StringResult);
  12.     if (o != null && o is TypedValue[])
  13.     {
  14.       TypedValue[] tvs = o as TypedValue[];
  15.       foreach (TypedValue tv in tvs)
  16.       {
  17.         ed.WriteMessage($"\n{tv.TypeCode} - {tv.Value}");
  18.       }
  19.     } else
  20.     {
  21.       ed.WriteMessage($"\n{o}");
  22.     }
  23.   }
  24. }

Меню смутило то, что я так, можно сказать в наглую, преобразовываю типы. А проверку я делаю следующим этапом, перед циклом для организации string массива. И там всегда будет список, так как никто к этой переменной не имеет доступа, а формируется она функцией написанной мной.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 20:43:39
Lemieux,
Кстати, ты обратил внимание что в этом списке есть не только строки, но и Autodesk.AutoCAD.Runtime.LispDataType.ListBegin и Autodesk.AutoCAD.Runtime.LispDataType.ListEnd (это как скобки в lisp)? У них TypeCode 5016 и 5017
Название: Re: Однотипные строки в цикл
Отправлено: Lemieux от 30-10-2019, 20:51:52
Lemieux,
Кстати, ты обратил внимание что в этом списке есть не только строки, но и Autodesk.AutoCAD.Runtime.LispDataType.ListBegin и Autodesk.AutoCAD.Runtime.LispDataType.ListEnd (это как скобки в lisp)? У них TypeCode 5016 и 5017
Да, я знаю об этом, поэтому у меня перебор массива начинается не с "0" элемента, а с "1" и заканчивается на "*.length-1". А есть какое решение как более изящно избавиться от обозначения границ списка?
PS Я с .ListStart и .ListEnd сталкивался, когда изучал ResultBuffer. Да и при отладке видно, что при передаче списка, размером 3, пишет "TypedValue[5]". Кстати, благодаря тому, что в Visual Studio, при отладке, удобно сделано, что показывает значение переменной и можно посмотреть, что там внутри, я решил вот так преобразовать тип.
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 20:55:06
А есть какое решение как более изящно избавиться от обозначения границ списка?
Вполне изящное решение если ты уверен, что у тебя в переменной обычный линейный список строк.
Название: Re: Однотипные строки в цикл
Отправлено: Дмитрий Загорулькин от 30-10-2019, 21:03:02
Впрочем возможен вариант, что в этой переменной не список и тогда преобразовывать в TypedValue[] нельзя.
Правильнее вот так:

Код - C# [Выбрать]
  1. [CommandMethod("GetLispVar")]
  2. public void GetLispVar()
  3. {
  4.   Document doc = Application.DocumentManager.MdiActiveDocument;
  5.   if (doc == null) return;
  6.  
  7.   Editor ed = doc.Editor;
  8.   PromptResult rs =  ed.GetString("\nУкажите имя переменной: ");
  9.   if (rs.Status == PromptStatus.OK)
  10.   {
  11.     var o = doc.GetLispSymbol(rs.StringResult);
  12.     if (o != null && o is TypedValue[])
  13.     {
  14.       TypedValue[] tvs = o as TypedValue[];
  15.       foreach (TypedValue tv in tvs)
  16.       {
  17.         ed.WriteMessage($"\n{tv.TypeCode} - {tv.Value}");
  18.       }
  19.     } else
  20.     {
  21.       ed.WriteMessage($"\n{o}");
  22.     }
  23.   }
  24. }
В C# не-помню-какой-версии добавили удобную проверку типа с одновременным преобразованием.
Поэтому, вместо строк 12-14 можно написать:
Код - C# [Выбрать]
  1. if (o is TypedValue[] tvs)
  2. {
Название: Re: Однотипные строки в цикл
Отправлено: Александр Ривилис от 30-10-2019, 21:08:21
В C# не-помню-какой-версии
Добавили в C# 7.0. Но я консервативен и использую старый синтаксис :)