明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 2318|回复: 16

Lisp与.NET互相调用。CAD2008 .net程序运行出现异常,请各位老师找出出错原因,非...

[复制链接]
发表于 2015-10-12 13:43 | 显示全部楼层 |阅读模式
本帖最后由 革天明 于 2015-10-12 14:04 编辑

李冠亿老师《深入浅出AutoCAD.NET二次开发》中6.8.3章节经出了一个Lisp与.NET程序互相调用的例子,如下:
/////////////////////////////////////////////////////////////////////////////////////////////////
//http://www.bimcad.org 数字建筑
//深入浅出AutoCAD二次开发(李冠亿)
/////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System.Runtime.InteropServices;

[assembly: CommandClass(typeof(Sample.CH6_8_3))]
namespace Sample
{
    class CH6_8_3
    {
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")]
        private static extern int acedInvoke(IntPtr args, out IntPtr result);

        public static ResultBuffer InvokeLisp(ResultBuffer args, ref int stat)
        {
            IntPtr rb = IntPtr.Zero;
            stat = acedInvoke(args.UnmanagedObject, out rb);
            if (stat == (int)PromptStatus.OK && rb != IntPtr.Zero)
                return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true);
            return null;
        }

        [CommandMethod("CallLispFunction")]
        public void CallLispFunction()
        {
            ResultBuffer args = new ResultBuffer();
            int stat = 0;
            args.Add(new TypedValue((int)LispDataType.Text, "c:CallByNet"));
            ResultBuffer res = InvokeLisp(args, ref stat);
        }

        [LispFunction("CallByLispFunction")]
        public static void CallByLispFunction(ResultBuffer rbArgs)
        {
            foreach (TypedValue rb in rbArgs)
                if (rb.TypeCode == (int)Autodesk.AutoCAD.Runtime.LispDataType.Text)
                    Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(rb.Value.ToString());
        }
    }
}

并给出了对应的lisp文件的代码:
(defun c:CallByNet()
(setq p1 (getpoint"输入第一点:"))
(setq p2 (getpoint"输入第二点:"))
(command "line" p1 p2 "")
)

(defun c:CallNet()
(setq t1 "BimCad.org")
(setq t2 "数字建筑")
(CallByLispFunction t1 t2)
)


我在测试过程中发现.NET调用lisp的函数Calllispfunction可正常运行,但使用lisp调用.NET的CallNET命令出现异常,错误如下:

命令: callnet
System.ArgumentException: 绑定到目标方法时出错。
   在 System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo
method, Boolean throwOnBindFailure)
   在 AcMgCommandClass.InvokeWorker(AcMgCommandClass* , MethodInfo mi, Object
commandObject, Boolean bLispFunction)
   在 AcMgCommandClass.InvokeWorkerWithExceptionFilter(AcMgCommandClass* ,
MethodInfo mi, Object commandObject, Boolean bLispFunction)
   在 AcMgCommandClass.Invoke(AcMgCommandClass* ,
gcroot<System::Reflection::MethodInfo ^>* mi, Boolean bLispFunction)
   在 AcMgCommandClass.CommandThunk.InvokeLisp(CommandThunk* ); 错误: ADS 请求错误


原以为是CAD2008安装过程中出现的msxml6.dll不能更新的错误,但重装系统及下载微软msxml6_x86(1.3M)修复后也是同样的错误,经网友确认CAD2011、2014下可正确运行,也说明李老师给的代码是可行的,但现在我的电脑上出现上面的错误,导致程序不能正常运行,请各位指点一下如何才能用Lisp调用.NET的函数。

本人运行环境如下:GHOST XP(32位)SP3,CAD2008(32位),
发表于 2015-10-12 18:19 来自手机 | 显示全部楼层
为什么这样用!
 楼主| 发表于 2015-10-13 08:56 | 显示全部楼层
ivde 发表于 2015-10-12 18:19
为什么这样用!

请教如何用才对?
发表于 2015-10-13 10:13 | 显示全部楼层
革天明 发表于 2015-10-13 08:56
请教如何用才对?

class CH6_8_3 用 public class CH6_8_3

using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System.Runtime.InteropServices;

[assembly: ExtensionApplication(typeof(Sample.MyPlugin))]
[assembly: CommandClass(typeof(Sample.CH6_8_3))]

namespace Sample
{
    public class MyPlugin : IExtensionApplication
    {

        void IExtensionApplication.Initialize()
        {
           
        }

        void IExtensionApplication.Terminate()
        {
            
        }

    }
    public class CH6_8_3
    {
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")]
        private static extern int acedInvoke(IntPtr args, out IntPtr result);

        public static ResultBuffer InvokeLisp(ResultBuffer args, ref int stat)
        {
            IntPtr rb = IntPtr.Zero;
            stat = acedInvoke(args.UnmanagedObject, out rb);
            if (stat == (int)PromptStatus.OK && rb != IntPtr.Zero)
                return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true);
            return null;
        }

        [CommandMethod("CallLispFunction")]
        public void CallLispFunction()
        {
            ResultBuffer args = new ResultBuffer();
            int stat = 0;
            args.Add(new TypedValue((int)LispDataType.Text, "c:CallByNet"));
            ResultBuffer res = InvokeLisp(args, ref stat);
        }

        [LispFunction("CallByLispFunction")]
        public static void CallByLispFunction(ResultBuffer rbArgs)
        {
            foreach (TypedValue rb in rbArgs)
                if (rb.TypeCode == (int)Autodesk.AutoCAD.Runtime.LispDataType.Text)
                    Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(rb.Value.ToString());
        }
    }
}
发表于 2015-10-13 15:43 | 显示全部楼层
在XP 、CAD2007能运行。
 楼主| 发表于 2015-10-13 15:52 | 显示全部楼层
ivde 发表于 2015-10-13 10:13
class CH6_8_3 用 public class CH6_8_3

using System;

using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System.Runtime.InteropServices;

[assembly: ExtensionApplication(typeof(Lisp2NET.MyPlugin))]
[assembly: CommandClass(typeof(Lisp2NET.CH6_8_3))]

namespace Lisp2NET
{
    public class MyPlugin : IExtensionApplication
    {

        void IExtensionApplication.Initialize()
        {
           
        }

        void IExtensionApplication.Terminate()
        {
            
        }

    }
    class CH6_8_3
    {
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")]
        private static extern int acedInvoke(IntPtr args, out IntPtr result);

        public static ResultBuffer InvokeLisp(ResultBuffer args, ref int stat)
        {
            IntPtr rb = IntPtr.Zero;
            stat = acedInvoke(args.UnmanagedObject, out rb);
            if (stat == (int)PromptStatus.OK && rb != IntPtr.Zero)
                return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true);
            return null;
        }

        [CommandMethod("CallLispFunction")]
        public void CallLispFunction()
        {
            ResultBuffer args = new ResultBuffer();
            int stat = 0;
            args.Add(new TypedValue((int)LispDataType.Text, "c:CallByNet"));
            ResultBuffer res = InvokeLisp(args, ref stat);
        }

        [LispFunction("CallByLispFunction")]
        public static string  CallByLispFunction(ResultBuffer rbArgs)
        {
            foreach (TypedValue rb in rbArgs)
                if (rb.TypeCode == (int)Autodesk.AutoCAD.Runtime.LispDataType.Text)
                    Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(rb.Value.ToString());
            return "";
        }
    }
}

以上修改源于EDATA,指明CAD2008时函数返回值不能空(lisp函数至少会返回一个nil)
XP SP3 CAD2008 sp1 VS2010 .net 2.0下测试通过,谢谢EDATA!
 楼主| 发表于 2015-10-13 15:54 | 显示全部楼层
yshf 发表于 2015-10-13 15:43
在XP 、CAD2007能运行。

目前已知2007、2010、2011、2014下没有问题,2008的有点特殊,6楼为2008的正确代码
发表于 2015-10-13 16:07 | 显示全部楼层
革天明 发表于 2015-10-13 15:54
目前已知2007、2010、2011、2014下没有问题,2008的有点特殊,6楼为2008的正确代码

void 是没有返回值的,alisp 好像都需要一个返回值
 楼主| 发表于 2015-10-13 16:28 | 显示全部楼层
ivde 发表于 2015-10-13 16:07
void 是没有返回值的,alisp 好像都需要一个返回值

好像是这个原因,请问如何定义一个.NET函数,参数为int a和int b,结果为a*b,这样的函数如何写?最终还是想让lisp调用的
发表于 2015-10-13 16:55 | 显示全部楼层
本帖最后由 ivde 于 2015-10-13 17:37 编辑
革天明 发表于 2015-10-13 16:28
好像是这个原因,请问如何定义一个.NET函数,参数为int a和int b,结果为a*b,这样的函数如何写?最终还是 ...

  1. [LispFunction("MyAdd")]
  2.         public static object MyAdd(ResultBuffer rbArgs)
  3.         {
  4.             var arg = rbArgs.AsArray();
  5.             if (arg.Length==2 && arg[0].TypeCode==(int)LispDataType.Double && arg[1].TypeCode==(int)LispDataType.Double)
  6.             {
  7.                 var num1 = (double)arg[0].Value;
  8.                 var num2 = (double)arg[1].Value;
  9.                 Double result = num1 + num2;
  10.                 return result;
  11.             }
  12.             else {
  13.                 return null;
  14.             }
  15.         }
C# 是区分类型的,Acad 用到的有 5001 5003 5010 ,简单的结果转为 double,否则就要 区分

  1. if (arg.Length==2 && (arg[0].TypeCode==5001 ||  arg[0].TypeCode==5003 || arg[0].TypeCode==5010)
  2.                 && (arg[1].TypeCode == 5001 || arg[1].TypeCode == 5003 || arg[1].TypeCode == 5010))
  3.             {
  4.                 var num1 = arg[0].Value;
  5.                 var num2 = arg[1].Value;
  6.                 var result = (double)num1 + (double)num2;
  7.                 return result;
  8.             }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-27 10:57 , Processed in 0.532612 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表