为.net程序集实现Com接口
本帖最后由 作者 于 2009-12-12 22:33:10 编辑下面是一个简单的示例,
详细见
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=75796
7楼
一、
新建一个类库项目:TlsCad.Curve
在AssemblyInfo.cs文件中修改:
二、
添加引用:acdbmgd.dll,acmgd.dll
在Class1.cs中加入下列代码using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using System.Runtime.InteropServices;
using System;
using System.Collections.Generic;
namespace TlsCad
{
public class Curve
{
AcDb.ObjectId _id;
public void Set(object acadObj)
{
_id = AcDb.Entity.FromAcadObject(acadObj);
}
private AcDb.Curve acCurve
{
get
{
AcDb.Database db = _id.Database;
using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
{
return tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
}
}
}
public double StartParam
{
get
{
return acCurve.StartParam;
}
}
public double EndParam
{
get
{
return acCurve.EndParam;
}
}
public object GetClosestPointTo(object pnt, bool extend)
{
return acCurve.GetClosestPointTo(new Point3d((double[])pnt), extend).ToArray();
}
public double GetDistAtParam(double param)
{
return acCurve.GetDistanceAtParameter(param);
}
public double GetParamAtDist(double dist)
{
return acCurve.GetParameterAtDistance(dist);
}
public double GetParamAtPoint(object pnt)
{
return acCurve.GetParameterAtPoint(new Point3d((double[])pnt));
}
public double GetDistAtPoint(object pnt)
{
return acCurve.GetDistAtPoint(new Point3d((double[])pnt));
}
public object GetParamsByPoints(object pnts)
{
AcDb.Curve c = acCurve;
List<double> pars = new List<double>();
foreach (object pnt in (object[])pnts)
{
pars.Add(c.GetParameterAtPoint(new Point3d((double[])pnt)));
}
return pars.ToArray();
}
public object SplitByParams(object pars)
{
AcDb.Database db = _id.Database;
List<object> objs = new List<object>();
using (Application.DocumentManager.MdiActiveDocument.LockDocument())
{
using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
{
AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
AcDb.BlockTableRecord btr = tr.GetObject(c.OwnerId, AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
double[] parrs = (double[])pars;
Array.Sort(parrs);
foreach (AcDb.Curve cc in c.GetSplitCurves(new DoubleCollection(parrs)))
{
btr.AppendEntity(cc);
tr.AddNewlyCreatedDBObject(cc, true);
objs.Add(cc.AcadObject);
}
tr.Commit();
}
}
return objs.ToArray();
}
}
}生成解决方案,将TlsCad.Curve.dll复制到AutoCad目录下
三、
切换到AutoCad目录下,在命令行键入
regasm TlsCad.Curve.dll /regfile /codebase
运行生成的reg文件,为.Net类库注册Com
四、
在Cad中绘制一条曲线,然后打开VB编辑器,加入下列代码调用Sub tt()
Dim tCuve As Object
Dim obj As Object, pnts(0)
Set tCuve = Application.GetInterfaceObject("TlsCad.Curve")
ThisDrawing.Utility.GetEntity obj, pnts(0)
tCuve.Set obj
pnts(0) = tCuve.GetClosestPointTo(pnts(0), False)
tCuve.SplitByParams tCuve.GetParamsByPoints(pnts)
End Sub
<p>老大,我照你的方法做了一遍,但是注册的时候的消息不知道是不是注册成功了,在添加com引用的时候找不到TlsCad.Curve。</p><p>在执行VBA代码的时候,Set tCuve = Application.GetInterfaceObject("TlsCad.Curve") 这一句出错:运行时错误</p><p>'-2147221005(800401f3)' 加载应用程序时出现问题。</p><p></p> <p>添加com引用的时候确实找不到TlsCad.Curve</p><p>你运行生成的reg文件么?</p><p>把下面的rar解压到d:/tlscad/bin目录下试试</p><p>上面的VBA代码改动了一下</p> 老大,我按照你说的帖子的7楼的方法实现了com和ObjectAPI的调用,那8楼的方法和7楼却完全不一样,是不是7楼的方法有时候会碰到问题? 本人轻易不灌水,灌水只为顶狐哥!~ <p>奇怪的问题是:上面的方法在VB或C#却不能使用,只能VBA?</p><p>有时间按8楼的代码试下</p> 本帖最后由 作者 于 2009-12-14 0:06:50 编辑
代码更改了一下,这样可以了
结论是:
1、不要在NetApi中使用DBObject.FromAcadObject函数
2、注意当前文档加锁的方法
3、C#做Com反射真的好累!
C#代码:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using System.Runtime.InteropServices;
using System;
using System.Collections.Generic;
namespace TlsCad.Common
{
public class Curve
{
AcDb.ObjectId _id;
public void Set(int id)
{
_id = new Autodesk.AutoCAD.DatabaseServices.ObjectId(new IntPtr(id));
}
private AcDb.Curve acCurve
{
get
{
AcDb.Database db = _id.Database;
using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
{
return tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
}
}
}
public double StartParam
{
get
{
return acCurve.StartParam;
}
}
public double EndParam
{
get
{
return acCurve.EndParam;
}
}
public object GetClosestPointTo(object pnt, bool extend)
{
return acCurve.GetClosestPointTo(new Point3d((double[])pnt), extend).ToArray();
}
public double GetDistAtParam(double param)
{
return acCurve.GetDistanceAtParameter(param);
}
public double GetParamAtDist(double dist)
{
return acCurve.GetParameterAtDistance(dist);
}
public double GetParamAtPoint(object pnt)
{
return acCurve.GetParameterAtPoint(new Point3d((double[])pnt));
}
public double GetDistAtPoint(object pnt)
{
return acCurve.GetDistAtPoint(new Point3d((double[])pnt));
}
private object GetParamsByPoints(object pnts)
{
List<double> pars = new List<double>();
AcDb.Database db = _id.Database;
using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
{
AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
foreach (object pnt in (object[])pnts)
{
pars.Add(c.GetParameterAtPoint(new Point3d((double[])pnt)));
}
}
return pars.ToArray();
}
public void SplitByPoints(object pnts)
{
SplitByParams(GetParamsByPoints(pnts));
}
public object SplitByParams(object pars)
{
AcDb.Database db = _id.Database;
List<object> objs = new List<object>();
Document doc = Application.DocumentManager.GetDocument(AcDb.HostApplicationServices.WorkingDatabase);
using (doc.LockDocument())
{
using (AcDb.Transaction tr = db.TransactionManager.StartTransaction())
{
AcDb.Curve c = tr.GetObject(_id, AcDb.OpenMode.ForRead) as AcDb.Curve;
AcDb.BlockTableRecord btr = tr.GetObject(c.OwnerId, AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
double[] parrs = (double[])pars;
Array.Sort(parrs);
foreach (AcDb.Curve cc in c.GetSplitCurves(new DoubleCollection(parrs)))
{
btr.AppendEntity(cc);
tr.AddNewlyCreatedDBObject(cc, true);
objs.Add(cc.AcadObject);
}
tr.Commit();
}
}
return objs.ToArray();
}
}
}VBA调用的代码
Sub tt()
Dim tc As Object
Set tc = Application.GetInterfaceObject("TlsCad.Common.Curve")
Dim obj As Object, pnts(1)
ThisDrawing.Utility.GetEntity obj, pnts(0)
tc.Set obj.ObjectID
pnts(0) = tc.GetClosestPointTo(pnts(0), False)
pnts(1) = ThisDrawing.Utility.GetPoint()
pnts(1) = tc.GetClosestPointTo(pnts(1), False)
tc.SplitByPoints (pnts)
End SubVB调用的代码
Private Sub Command1_Click()
Dim app As Object
Set app = GetObject(, "AutoCad.Application")
Dim tcAs Object
Set tc = app.GetInterfaceObject("TlsCad.Common.Curve")
Dim obj As Object, pnts(1)
app.ActiveDocument.Utility.GetEntity obj, pnts(0)
tc.Set obj.ObjectID
pnts(0) = tc.GetClosestPointTo(pnts(0), False)
pnts(1) = app.ActiveDocument.Utility.GetPoint()
pnts(1) = tc.GetClosestPointTo(pnts(1), False)
tc.SplitByPoints (pnts)
End SubC#调用的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using System.Runtime.InteropServices;
using System.Reflection;
namespace ComTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
AcadApplication acApp = GetAcApp();
object tc = acApp.GetInterfaceObject("TlsCad.Common.Curve");
object acCurve;
object[] pnts = new object;
AcadDocument acDoc = acApp.ActiveDocument;
acDoc.Utility.GetEntity(out acCurve, out pnts, "");
InvokeMethod(tc, "Set", ((AcadEntity)acCurve).ObjectID);
pnts = InvokeMethod(tc, "GetClosestPointTo", pnts, false);
pnts = acDoc.Utility.GetPoint(pnts, "");
pnts = InvokeMethod(tc, "GetClosestPointTo", pnts, false);
InvokeMethod(tc, "SplitByPoints", new object{pnts});
}
public object InvokeMethod(object obj, string methodName, params object[] args)
{
Type t = obj.GetType();
object res =
t.InvokeMember(
methodName,
BindingFlags.Public | BindingFlags.InvokeMethod,
null,
obj,
args);
return res;
}
public AcadApplication GetAcApp()
{
const string progID = "AutoCAD.Application.18";
AcadApplication acApp = null;
try
{
acApp =
(AcadApplication)Marshal.GetActiveObject(progID);
}
catch
{
try
{
Type acType =
Type.GetTypeFromProgID(progID);
acApp =
(AcadApplication)Activator.CreateInstance(
acType,
true
);
}
catch
{
MessageBox.Show(
"Cannot create object of type \"" +
progID + "\""
);
}
}
return acApp;
}
}
}
<p>老大,问个简单的问题哈:</p><p>api.net编好dll之后,应该把这个dll放到cad安装目录下注册吧?</p><p>注册成功之后这个到cad安装目录下的dll能删除吗?</p><p>然后新建的应用程序在引用这个dll的时候是否复制本地呢?</p><p></p> <p>regasm TlsCad.Curve.dll /regfile /codebase</p><p>生成reg文件</p><p>如果不在安装目录注册,要更改reg文件中的目录信息</p><p>然后再运行注册</p><p>不需要引用dll的</p> <p>但是kean的帖子里面的7楼和8楼都引用了dll,都有这一句using LoadableComponent;</p><p>不知道引用和不引用到底有什么区别,很困惑啊</p><p>另外他8楼的方法很难看懂,主要是他写了 </p><p>不知道这是干什么用的</p>
页:
[1]
2