明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 6594|回复: 11

[运行时] 为.net程序集实现Com接口

  [复制链接]
发表于 2009-12-12 20:55:00 | 显示全部楼层 |阅读模式
本帖最后由 作者 于 2009-12-12 22:33:10 编辑

下面是一个简单的示例,
详细见
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=75796
7楼
一、
新建一个类库项目:TlsCad.Curve
在AssemblyInfo.cs文件中修改:
[assembly: ComVisible(true)]
二、
添加引用:acdbmgd.dll,acmgd.dll
在Class1.cs中加入下列代码
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.Geometry;
  6. using System.Runtime.InteropServices;
  7. using System;
  8. using System.Collections.Generic;
  9. namespace TlsCad
  10. {
  11.     [ProgId("TlsCad.Curve")]
  12.     public class Curve
  13.     {
  14.         AcDb.ObjectId _id;
  15.         public void Set(object acadObj)
  16.         {
  17.             _id = AcDb.Entity.FromAcadObject(acadObj);
  18.         }
  19.         private AcDb.Curve acCurve
  20.         {
  21.             get
  22.             {
  23.                 AcDb.Database db = _id.Database;
  24.                 using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
  25.                 {
  26.                     return tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
  27.                 }
  28.             }
  29.         }
  30.         public double StartParam
  31.         {
  32.             get
  33.             {
  34.                 return acCurve.StartParam;
  35.             }
  36.         }
  37.         public double EndParam
  38.         {
  39.             get
  40.             {
  41.                 return acCurve.EndParam;
  42.             }
  43.         }
  44.         public object GetClosestPointTo(object pnt, bool extend)
  45.         {
  46.             return acCurve.GetClosestPointTo(new Point3d((double[])pnt), extend).ToArray();
  47.         }
  48.         public double GetDistAtParam(double param)
  49.         {
  50.             return acCurve.GetDistanceAtParameter(param);
  51.         }
  52.         public double GetParamAtDist(double dist)
  53.         {
  54.             return acCurve.GetParameterAtDistance(dist);
  55.         }
  56.         public double GetParamAtPoint(object pnt)
  57.         {
  58.             return acCurve.GetParameterAtPoint(new Point3d((double[])pnt));
  59.         }
  60.         public double GetDistAtPoint(object pnt)
  61.         {
  62.             return acCurve.GetDistAtPoint(new Point3d((double[])pnt));
  63.         }
  64.         public object GetParamsByPoints(object pnts)
  65.         {
  66.             AcDb.Curve c = acCurve;
  67.             List<double> pars = new List<double>();
  68.             foreach (object pnt in (object[])pnts)
  69.             {
  70.                 pars.Add(c.GetParameterAtPoint(new Point3d((double[])pnt)));
  71.             }
  72.             return pars.ToArray();
  73.         }
  74.         public object SplitByParams(object pars)
  75.         {
  76.             AcDb.Database db = _id.Database;
  77.             List<object> objs = new List<object>();
  78.             using (Application.DocumentManager.MdiActiveDocument.LockDocument())
  79.             {
  80.                 using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
  81.                 {
  82.                     AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
  83.                     AcDb.BlockTableRecord btr = tr.GetObject(c.OwnerId, AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
  84.                     double[] parrs = (double[])pars;
  85.                     Array.Sort(parrs);
  86.                     foreach (AcDb.Curve cc in c.GetSplitCurves(new DoubleCollection(parrs)))
  87.                     {
  88.                         btr.AppendEntity(cc);
  89.                         tr.AddNewlyCreatedDBObject(cc, true);
  90.                         objs.Add(cc.AcadObject);
  91.                     }
  92.                     tr.Commit();
  93.                 }
  94.             }
  95.             return objs.ToArray();
  96.         }
  97.     }
  98. }
生成解决方案,将TlsCad.Curve.dll复制到AutoCad目录下
三、

切换到AutoCad目录下,在命令行键入
regasm TlsCad.Curve.dll /regfile /codebase
运行生成的reg文件,为.Net类库注册Com
四、
在Cad中绘制一条曲线,然后打开VB编辑器,加入下列代码调用
  1. Sub tt()
  2.     Dim tCuve As Object
  3.     Dim obj As Object, pnts(0)
  4.     Set tCuve = Application.GetInterfaceObject("TlsCad.Curve")
  5.     ThisDrawing.Utility.GetEntity obj, pnts(0)
  6.     tCuve.Set obj
  7.     pnts(0) = tCuve.GetClosestPointTo(pnts(0), False)
  8.     tCuve.SplitByParams tCuve.GetParamsByPoints(pnts)
  9. End Sub

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
发表于 2009-12-12 22:02:00 | 显示全部楼层

老大,我照你的方法做了一遍,但是注册的时候的消息不知道是不是注册成功了,在添加com引用的时候找不到TlsCad.Curve。

在执行VBA代码的时候,Set tCuve = Application.GetInterfaceObject("TlsCad.Curve") 这一句出错:运行时错误

'-2147221005(800401f3)' 加载应用程序时出现问题。

 楼主| 发表于 2009-12-12 22:28:00 | 显示全部楼层

添加com引用的时候确实找不到TlsCad.Curve

你运行生成的reg文件么?

把下面的rar解压到d:/tlscad/bin目录下试试

上面的VBA代码改动了一下

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
发表于 2009-12-13 15:20:00 | 显示全部楼层
老大,我按照你说的帖子的7楼的方法实现了com和ObjectAPI的调用,那8楼的方法和7楼却完全不一样,是不是7楼的方法有时候会碰到问题?
发表于 2009-12-13 19:31:00 | 显示全部楼层
本人轻易不灌水,灌水只为顶狐哥!~
 楼主| 发表于 2009-12-13 21:31:00 | 显示全部楼层

奇怪的问题是:上面的方法在VB或C#却不能使用,只能VBA?

有时间按8楼的代码试下

 楼主| 发表于 2009-12-13 23:39:00 | 显示全部楼层
本帖最后由 作者 于 2009-12-14 0:06:50 编辑

代码更改了一下,这样可以了
结论是:
1、不要在NetApi中使用DBObject.FromAcadObject函数
2、注意当前文档加锁的方法
3、C#做Com反射真的好累!
C#代码:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.Geometry;
  6. using System.Runtime.InteropServices;
  7. using System;
  8. using System.Collections.Generic;
  9. namespace TlsCad.Common
  10. {
  11.     [ProgId("TlsCad.Common.Curve")]
  12.     public class Curve
  13.     {
  14.         AcDb.ObjectId _id;
  15.         public void Set(int id)
  16.         {
  17.             _id = new Autodesk.AutoCAD.DatabaseServices.ObjectId(new IntPtr(id));
  18.         }
  19.         private AcDb.Curve acCurve
  20.         {
  21.             get
  22.             {
  23.                 AcDb.Database db = _id.Database;
  24.                 using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
  25.                 {
  26.                     return tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
  27.                 }
  28.             }
  29.         }
  30.         public double StartParam
  31.         {
  32.             get
  33.             {
  34.                 return acCurve.StartParam;
  35.             }
  36.         }
  37.         public double EndParam
  38.         {
  39.             get
  40.             {
  41.                 return acCurve.EndParam;
  42.             }
  43.         }
  44.         public object GetClosestPointTo(object pnt, bool extend)
  45.         {
  46.             return acCurve.GetClosestPointTo(new Point3d((double[])pnt), extend).ToArray();
  47.         }
  48.         public double GetDistAtParam(double param)
  49.         {
  50.             return acCurve.GetDistanceAtParameter(param);
  51.         }
  52.         public double GetParamAtDist(double dist)
  53.         {
  54.             return acCurve.GetParameterAtDistance(dist);
  55.         }
  56.         public double GetParamAtPoint(object pnt)
  57.         {
  58.             return acCurve.GetParameterAtPoint(new Point3d((double[])pnt));
  59.         }
  60.         public double GetDistAtPoint(object pnt)
  61.         {
  62.             return acCurve.GetDistAtPoint(new Point3d((double[])pnt));
  63.         }
  64.         private object GetParamsByPoints(object pnts)
  65.         {
  66.             List<double> pars = new List<double>();
  67.             AcDb.Database db = _id.Database;
  68.             using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
  69.             {
  70.                 AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
  71.                 foreach (object pnt in (object[])pnts)
  72.                 {
  73.                     pars.Add(c.GetParameterAtPoint(new Point3d((double[])pnt)));
  74.                 }
  75.             }
  76.             return pars.ToArray();
  77.         }
  78.         public void SplitByPoints(object pnts)
  79.         {
  80.             SplitByParams(GetParamsByPoints(pnts));
  81.         }
  82.         public object SplitByParams(object pars)
  83.         {
  84.             AcDb.Database db = _id.Database;
  85.             List<object> objs = new List<object>();
  86.             Document doc = Application.DocumentManager.GetDocument(AcDb.HostApplicationServices.WorkingDatabase);
  87.             using (doc.LockDocument())
  88.             {
  89.                 using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
  90.                 {
  91.                     AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
  92.                     AcDb.BlockTableRecord btr = tr.GetObject(c.OwnerId, AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
  93.                     double[] parrs = (double[])pars;
  94.                     Array.Sort(parrs);
  95.                     foreach (AcDb.Curve cc in c.GetSplitCurves(new DoubleCollection(parrs)))
  96.                     {
  97.                         btr.AppendEntity(cc);
  98.                         tr.AddNewlyCreatedDBObject(cc, true);
  99.                         objs.Add(cc.AcadObject);
  100.                     }
  101.                     tr.Commit();
  102.                 }
  103.             }
  104.             return objs.ToArray();
  105.         }
  106.     }
  107. }
VBA调用的代码
  1. Sub tt()
  2.     Dim tc As Object
  3.     Set tc = Application.GetInterfaceObject("TlsCad.Common.Curve")
  4.    
  5.     Dim obj As Object, pnts(1)
  6.     ThisDrawing.Utility.GetEntity obj, pnts(0)
  7.     tc.Set obj.ObjectID
  8.    
  9.     pnts(0) = tc.GetClosestPointTo(pnts(0), False)
  10.     pnts(1) = ThisDrawing.Utility.GetPoint()
  11.     pnts(1) = tc.GetClosestPointTo(pnts(1), False)
  12.    
  13.     tc.SplitByPoints (pnts)
  14.    
  15. End Sub
VB调用的代码
  1. Private Sub Command1_Click()
  2. Dim app As Object
  3. Set app = GetObject(, "AutoCad.Application")
  4. Dim tc  As Object
  5. Set tc = app.GetInterfaceObject("TlsCad.Common.Curve")
  6.     Dim obj As Object, pnts(1)
  7.     app.ActiveDocument.Utility.GetEntity obj, pnts(0)
  8.     tc.Set obj.ObjectID
  9.    
  10.     pnts(0) = tc.GetClosestPointTo(pnts(0), False)
  11.     pnts(1) = app.ActiveDocument.Utility.GetPoint()
  12.     pnts(1) = tc.GetClosestPointTo(pnts(1), False)
  13.    
  14.     tc.SplitByPoints (pnts)
  15. End Sub
C#调用的代码
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using Autodesk.AutoCAD.Interop;
  10. using Autodesk.AutoCAD.Interop.Common;
  11. using System.Runtime.InteropServices;
  12. using System.Reflection;
  13. namespace ComTest
  14. {
  15.     public partial class Form1 : Form
  16.     {
  17.         public Form1()
  18.         {
  19.             InitializeComponent();
  20.         }
  21.         private void button1_Click(object sender, EventArgs e)
  22.         {
  23.             AcadApplication acApp = GetAcApp();
  24.             object tc = acApp.GetInterfaceObject("TlsCad.Common.Curve");
  25.             object acCurve;
  26.             object[] pnts = new object[2];
  27.             AcadDocument acDoc = acApp.ActiveDocument;
  28.             acDoc.Utility.GetEntity(out acCurve, out pnts[0], "");
  29.             InvokeMethod(tc, "Set", ((AcadEntity)acCurve).ObjectID);
  30.             pnts[0] = InvokeMethod(tc, "GetClosestPointTo", pnts[0], false);
  31.             pnts[1] = acDoc.Utility.GetPoint(pnts[0], "");
  32.             pnts[1] = InvokeMethod(tc, "GetClosestPointTo", pnts[1], false);
  33.             InvokeMethod(tc, "SplitByPoints", new object[1]{pnts});
  34.         }
  35.         public object InvokeMethod(object obj, string methodName, params object[] args)
  36.         {
  37.             Type t = obj.GetType();
  38.             object res =
  39.                 t.InvokeMember(
  40.                     methodName,
  41.                     BindingFlags.Public | BindingFlags.InvokeMethod,
  42.                     null,
  43.                     obj,
  44.                     args);
  45.             return res;
  46.         }
  47.         public AcadApplication GetAcApp()
  48.         {
  49.             const string progID = "AutoCAD.Application.18";
  50.             AcadApplication acApp = null;
  51.             try
  52.             {
  53.                 acApp =
  54.                   (AcadApplication)Marshal.GetActiveObject(progID);
  55.             }
  56.             catch
  57.             {
  58.                 try
  59.                 {
  60.                     Type acType =
  61.                       Type.GetTypeFromProgID(progID);
  62.                     acApp =
  63.                       (AcadApplication)Activator.CreateInstance(
  64.                         acType,
  65.                         true
  66.                       );
  67.                 }
  68.                 catch
  69.                 {
  70.                     MessageBox.Show(
  71.                       "Cannot create object of type "" +
  72.                       progID + """
  73.                     );
  74.                 }
  75.             }
  76.             return acApp;
  77.         }
  78.     }
  79. }
发表于 2009-12-15 21:56:00 | 显示全部楼层

老大,问个简单的问题哈:

api.net编好dll之后,应该把这个dll放到cad安装目录下注册吧?

注册成功之后这个到cad安装目录下的dll能删除吗?

然后新建的应用程序在引用这个dll的时候是否复制本地呢?

 楼主| 发表于 2009-12-16 07:45:00 | 显示全部楼层

regasm TlsCad.Curve.dll /regfile /codebase

生成reg文件

如果不在安装目录注册,要更改reg文件中的目录信息

然后再运行注册

不需要引用dll的

发表于 2009-12-17 19:53:00 | 显示全部楼层

但是kean的帖子里面的7楼和8楼都引用了dll,都有这一句using LoadableComponent;

不知道引用和不引用到底有什么区别,很困惑啊

另外他8楼的方法很难看懂,主要是他写了[Guid("5B5B731C-B37A-4aa2-8E50-42192BD51B17")]

不知道这是干什么用的

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-25 20:17 , Processed in 0.193998 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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