Объявление lisp под NET (nanoCAD 24+) и *error*
Да, в NC24.0 (ну и, соответственно, дальше) появилась возможность объявления lisp-функций через NET. А оно вообще работает? Попробую разобраться. И не пожалею на это отдельной лицензии )
Репозитория на github/gitflic/.. не будет, смысла примерно ноль. Задачка проста и незатейлива - на NET написать функцию округления переданного числа до указанной точности. Выглядеть это должно в лиспе примерно так:
1 | (net-round 12.3456789 2) ; 12.35 |
NET-овский код тоже не блещет сложностью:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System; using Teigha.DatabaseServices; using Teigha.Runtime; namespace NCadLispCheck.LipsDefinitions { public static class RoundLisp { [LispFunction("net-round")] public static double RoundNetLisp(ResultBuffer rb) { TypedValue[] args = rb.AsArray(); if (args.Length != 2) { throw new ArgumentOutOfRangeException( "Аргументов должно быть 2 - первый число, второй - количество знаков после запятой"); } double value = Convert.ToDouble(args[0].Value.ToString()); int precision = Convert.ToInt32(args[1].Value.ToString()); return (double)Math.Round((decimal)value, precision, MidpointRounding.AwayFromZero); } } } |
Ну что ж, создаю проект NET6, подключаю даже не nuget, а напрямую сборки из SDK, запуск...
1 2 3 4 | Команда: (net-round 12.3456987 2) nil Команда: (setq res (net-round 12.345 2)) nil |
Че?! Сначала я подумал, что надо в .csproj прописать не только net6, но и платформу. Поменял. Результат тот же.
Причем, что самое странное - объявление функции-то подхватывается! Но входа в точку останова так и не происходит. Что-то тут не то. При этом создать проект NetFramework со ссылками на host*mgd.dll мне не удалось: при попытке сборки выводятся ошибки типа
1 2 3 | Ссылка на тип "MarshalByRefObject" требует его определения в "System.Runtime", но его не удалось найти. Сборка "hostdbmgd" с удостоверением "hostdbmgd, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" использует "System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" с более высокой версией, чем у сборки "System.Runtime" с удостоверением "System.Runtime, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", на которую делается ссылка. |
Что в принципе логично. Но все равно я не понимаю, что я делаю не так, раз объявленная возможность не работает.
Последняя идея - это подключить dll не из SDK, а от NC24.1 ситуацию не спасло и не изменило. Что ж не так-то?
А если убрать статику хотя бы из объявления класса? Сработало! Хотя, по мне, это дичь полная.
почему ты решил, что должно быть static?
https://github.com/ADN-DevTech/AutoCAD-Net-Wizards/blob/master/AutoCAD-Plugin-Template/ExamplePlugin/myCommands.cs
https://github.com/ADN-DevTech/AutoCAD-Net-Wizards/blob/ForAutoCAD2024/AutoCADNetWizardsInstaller/Output/AutoCAD%20CSharp%20plug-in/myCommands.cs
===================
учитывая, что МАЭСТРО не поправил и по видимому все собралось и заработало в АК, этот жеж код работает у меня в нано
https://adn-cis.org/forum/index.php?topic=10382.msg48321#msg48321
кстати в SDK АК2016
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
...
[LispFunction("c:helloworld")]
public void hw(ResultBuffer args)
{
Editor ed =
Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage('\n' + "Hello World!" + '\n');
}
потом появился static
статический метод то же работает
public class TEST
{
[CommandMethod("t-HelloWorld")]
public void HelloWorld()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("Hello World");
}
#region LISP FUNCTION
[LispFunction("dr-ttt")]
public static bool LispTest3(ResultBuffer arguments)
{
bool res = false;
Array args = arguments.AsArray();
if (args.Length == 1)
{
string sText = ((TypedValue)(args.GetValue(0))).Value.ToString();
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("\nAnswer " + sText);
res = true;
}
return res;
}
[LispFunction("_tt")]
public static bool LispTest2(ResultBuffer arguments)
{
bool res = false;
Array args = arguments.AsArray();
if (args.Length == 1)
{
string sText = ((TypedValue)(args.GetValue(0))).Value.ToString();
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("Answer " + sText);
res = true;
}
return res;
}
[LispFunction("_dr_test")]
public static bool LispTest(ResultBuffer arguments)
{
bool res = false;
Array args = arguments.AsArray();
if (args.Length == 1)
{
string sText = ((TypedValue)(args.GetValue(0))).Value.ToString();
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("Answer " + sText);
res = true;
}
return res;
}
[LispFunction("kpblc-test-resbuf")]
public static ResultBuffer KpblcTestResBufList(ResultBuffer arg)
{
ResultBuffer res = new ResultBuffer();
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.Text, "key"));
res.Add(new TypedValue((int)LispDataType.DottedPair));
res.Add(new TypedValue((int)LispDataType.Text, "value"));
res.Add(new TypedValue((int)LispDataType.ListEnd));
res.Add(new TypedValue((int)LispDataType.ListEnd));
return res;
}
[LispFunction("kpblc-test-resbuf2")]
public static ResultBuffer KpblcTestResBufList2(ResultBuffer arg)
{
ResultBuffer res = new ResultBuffer();
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.Text, "key"));
res.Add(new TypedValue((int)LispDataType.Text, "value"));
res.Add(new TypedValue((int)LispDataType.ListEnd));
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.Text, "key2"));
res.Add(new TypedValue((int)LispDataType.Int32, 123));
res.Add(new TypedValue((int)LispDataType.ListEnd));
res.Add(new TypedValue((int)LispDataType.ListEnd));
return res;
}
[LispFunction("kpblc-test-resbuf1")]
public static ResultBuffer KpblcTestResBufList1(ResultBuffer arg)
{
ResultBuffer res = new ResultBuffer();
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.Text, "key"));
res.Add(new TypedValue((int)LispDataType.DottedPair));
res.Add(new TypedValue((int)LispDataType.Text, "value"));
res.Add(new TypedValue((int)LispDataType.ListEnd));
res.Add(new TypedValue((int)LispDataType.ListBegin));
res.Add(new TypedValue((int)LispDataType.Text, "key2"));
res.Add(new TypedValue((int)LispDataType.DottedPair));
res.Add(new TypedValue((int)LispDataType.Int32, 123));
res.Add(new TypedValue((int)LispDataType.ListEnd));
res.Add(new TypedValue((int)LispDataType.ListEnd));
return res;
}
#endregion
}
в том году на старом форуме в начале февраля разбирались
Ну, во-первых, на многих исхониках (которые я видел в свое время) команды и лисп-функции прописывались в статических классах. И, во-вторых, если объявить команду не статической, она может быть вызывана в NC с ком.строки и без документа, насколько я помню. И плевать на регистрацию команды в меню )
нет, static не влияет
по умолчанию команда всегда выполняется в контексте документа
очевидно, что эти команды без документа работать не будут
using Win = System.Windows;
/////
[Rtm.CommandMethod("drz_Test1")]
public static void CmdPTest1()
{
Win.MessageBox.Show("static Test1");
}
[Rtm.CommandMethod("drz_Test2")]
public void CmdPTest2()
{
Win.MessageBox.Show("Test2");
}
флаг CommandFlags.Sessionуказывает, что контекст выполнения команды документ
так без документа команды будут работать
[Rtm.CommandMethod("drz_Test3",Rtm.CommandFlags.Session)]
public static void CmdPTest3()
{
Win.MessageBox.Show("static Session Test3");
}
[Rtm.CommandMethod("drz_Test4",Rtm.CommandFlags.Session)]
public void CmdPTest4()
{
Win.MessageBox.Show("Session Test2");
}
мы с тобой уже обсуждали этот момент год назад)))
на убиенном форуме, я то же забыл пришлось вспоминать
более того
для команды
[Rtm.CommandMethod("drz_Test5")]
public void CmdPTest5()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null)
{
return;
}
Editor ed = doc.Editor;
ed.WriteMessage("Проверка документа на null не нужна, команда и так не будет выполнена без документа");
}
проверка наличия активного документа не требуется
======
а вот здесь обязательна проверка, команда выполняется в контексте приложения (мы жэж не только с документом можем работать)))
[Rtm.CommandMethod("drz_Test6", Rtm.CommandFlags.Session)]
public void CmdPTest6()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null)
{
return;
}
Editor ed = doc.Editor;
ed.WriteMessage("Проверка документа на null обязательна, иначе без дакумента выхватим эксепшен");
}
как видишь static совсем не при делах),
по крайней мере в нане
флаг CommandFlags.Sessionуказывает, что контекст выполнения команды документ
заболтался, конечно жэ контент выполнения приложение)))
М-да, как-то про CommandFlags я упустил из виду. Спасибо )