使用C#进行AutoCAD二次开发,有时候由于C#接口不够完善,或者低版本AutoCAD中的接口缺少,有些工作不能直接通过C#接口来实现,所以需要通过P/Invoke的方式调用AutoCAD的其他DLL中的接口来实现。

最常见的是向AutoCAD发送同步命令,在高版本的AutoCAD.NET接口中好像是可以发送同步命令了(据说是从2014或2015开始是可以了,不过我没有进行验证),但在低版本AutoCAD.NET中是没有发送同步命令接口的,SendStringToExecute和COM接口中的SendCommand都是异步操作,只有通过acedCmd、acedCommand、acedPostCommand才可能发送同步命令,这三个接口在AutoCAD2013之前是在acad.exe中的,而从AutoCAD2013开始放到了accore.dll中,并且acedPostCommand这个接口是官方没有公布但实际是可以使用的。

正常通过P/Invoke方式调用需要进行以下声明:

AutoCAD2013以前的版本

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("acad.exe", EntryPoint = "acedCmd", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedCmd(IntPtr vlist);
[DllImport("acad.exe", EntryPoint = "acedCommand")]
private static extern int acedCommand(IntPtr vlist);
//CAD2008和2008以前版本中的EntryPoint名称和2009以及2009之后的版本不一样
[DllImport("acad.exe", CharSet = CharSet.Auto, EntryPoint = "?acedPostCommand@@YAHPB_W@Z", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedPostCommand(string strExpr);
//CAD2008之后的版本中
[DllImport("acad.exe", CharSet = CharSet.Auto, EntryPoint = "?acedPostCommand@@YAHPEB_W@Z", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedPostCommand(string strExpr);

AutoCAD2013及更新版本

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("accore.dll", EntryPoint = "acedCmd", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedCmd(IntPtr vlist); [DllImport("accore.dll", EntryPoint = "acedCommand")]
private static extern int acedCommand(IntPtr vlist); //CAD2008和2008以前版本中的EntryPoint名称和2009以及2009之后的版本不一样
[DllImport("accore.dll", CharSet = CharSet.Auto, EntryPoint = "?acedPostCommand@@YAHPB_W@Z", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedPostCommand(string strExpr);
//CAD2008之后的版本中
[DllImport("accore.dll", CharSet = CharSet.Auto, EntryPoint = "?acedPostCommand@@YAHPEB_W@Z", CallingConvention = CallingConvention.Cdecl)]
private static extern int acedPostCommand(string strExpr);

使用时直接进行调用即可:

ResultBuffer rb = new ResultBuffer();
rb.Add(new TypedValue((int)LispDataType.Text, "_.mycmd"));
int i = acedCmd(rb.UnmanagedObject);

要注意的是这些接口不能使用Loadlibrary的方式进行调用,因为Loadlibrary会把指定的DLL或EXE进行加载,加载后应该和当前程序所寄存的AutoCAD主进程不是一回事了,调用会有问题或调用结果达不到预期效果。

今天要介绍的是另外一种不使用P/Invoke方式就可以在自己的插件中调用acad.exe或accore.dll中接口的方法,主要思路如下:

1、获取当前进程Process,因为插件是被加载到AutoCAD中运行的,所以获取到的是AutoCAD进程。

2、获取当前进程加载的所有模块ProcessModuleCollection。

3、遍历ProcessModuleCollection找到自己要调用的接口所在的模块ProcessModule。

4、声明一个和要调用的接口格式相同的委托。

5、获取ProcessModule的EntryPointAddress,然后使用Marshal.GetDelegateForFunctionPointer方法根据函数句柄得到一个委托实例。

6、调用委托实例进行执行即可。

以acedPostCommand为例完整代码如下:

//此处声明的委托和acedPostCommand(string strExpr)不相同是因为经过测试,如果参数声明为string类型,调用的时候传送到CAD的命令是乱码
public delegate int DelegateAcedPostCommand(byte[] cmd);
static DelegateAcedPostCommand pc; public void ShowMsg()
{
//不同版本接口所在的程序模块不同
string mdName = Application.Version.Major >= ? "accore.dll" : "acad.exe";
//CAD2007和2008中接口入口点名称不一样,2007以前的没有看,想看的可以用depends工具查看
string apiName = (Application.Version.Major >= && Application.Version.Minor <= ) ? "?acedPostCommand@@YAHPB_W@Z" : "?acedPostCommand@@YAHPEB_W@Z";
//获取当前CAD进程
Process pro = Process.GetCurrentProcess();
//获取CAD加载的所有程序模块(引用了什么DLL、EXE)
ProcessModuleCollection pmc = pro.Modules;
IntPtr iptr = IntPtr.Zero;
for (int i = ; i < pmc.Count; i++)
{
ProcessModule pm = pmc[i];
if (pm.ModuleName == mdName)
{
iptr = pm.EntryPointAddress;
break;
}
}
if (iptr != IntPtr.Zero)
{
pc = (DelegateAcedPostCommand)Marshal.GetDelegateForFunctionPointer(iptr, typeof(DelegateAcedPostCommand));
if (pc != null)
{
string str = "_.remmenu\n";
//此处要把字符串使用Unicode编码转换为byte[],然后再传入委托接口,不然到CAD之后会乱码
byte[] bytes = Encoding.Unicode.GetBytes(str);
int i = pc.Invoke(bytes);
}
}
}

AutoCAD.NET 不使用P/Invoke方式调用acad.exe或accore.dll中的接口(如acedCommand、acedPostCommand等)的更多相关文章

  1. .netcore在linux下使用P/invoke方式调用linux动态库

    http://www.mamicode.com/info-detail-2358309.html   .netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件 1 ...

  2. Delphi调用DLL中的接口

    问题描述: 具体问题就是在隐式使用接口变量后,在FreeLibrary执行后,就会出现一个非法访址的错误. 这个错误的原因就是在FreeLibrary后,DLL以的代码均为不可用状态,而在代码执行完整 ...

  3. Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)

    文章目录:                   1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...

  4. DLL模块例1:使用.def模块导出函数,规范修饰名称,显示连接调用dll中函数

    以下内容,我看了多篇文章,整合在一起,写的一个例子,关于dll工程的创建,请参考博客里另一篇文章:http://www.cnblogs.com/pingge/articles/3153571.html ...

  5. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

  6. Atitit 动态调用webservice与客户端代理方式调用

    Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke  直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...

  7. YbSoftwareFactory 代码生成插件【二十五】:Razor视图中以全局方式调用后台方法输出页面代码的三种方法

    上一篇介绍了 MVC中实现动态自定义路由 的实现,本篇将介绍Razor视图中以全局方式调用后台方法输出页面代码的三种方法. 框架最新的升级实现了一个页面部件功能,其实就是通过后台方法查询数据库内容,把 ...

  8. HttpClient Get/Post方式调用Http接口

    本节摘要:本节主要分别介绍如何用get方式.post方式向http接口发送数据. preparation 1. 项目环境如下: myeclipse6.5 .tomcat5.0.system:xp.JD ...

  9. C#以post方式调用struts rest-plugin service的问题

    struts2: 玩转 rest-plugin一文中,学习了用struts2开发restful service的方法,发现用c#以post方式调用时各种报错,但java.ajax,包括firefox ...

随机推荐

  1. iOS富文本(二)初识Text Kit

    概述 Text Kit 是建立在Core Text上的文本布局系统,虽然没有Core Text那么强大的文本处理功能,但是对于大多数常见的文本布局用Text Kit能够很简单的实现,而不是用Core ...

  2. Kafka Topic动态迁移 (源代码解析)

    总结下自己在尝试Kafka分区迁移过程中对这部分知识的理解,请路过高手指正. 关于Kafka数据迁移的具体步骤指导,请参考如下链接:http://www.cnblogs.com/dycg/p/3922 ...

  3. 漫游Kafka设计篇之数据持久化

    Kafka大量依赖文件系统去存储和缓存消息.对于硬盘有个传统的观念是硬盘总是很慢,这使很多人怀疑基于文件系统的架构能否提供优异的性能.实际上硬盘的快慢完全取决于使用它的方式.设计良好的硬盘架构可以和内 ...

  4. UVa 247 Calling Circles【传递闭包】

    题意:给出n个人的m次电话,问最后构成多少个环,找出所有的环 自己想的是:用map来储存人名,每个人名映射成一个数字编号,再用并查集,求出有多少块连通块,输出 可是map不熟,写不出来,而且用并查集输 ...

  5. mongodb数据备份与还原

    1)简单数据的导出与导入导出:./mongoexport -d test -c users -o /tmp/users.out 导入:./mongoimport -d test -c users /t ...

  6. 整理一些js中常见的问题

    原文链接 1.js获取select标签选中的值 原生js var obj = document.getElementByIdx_x(”testSelect”); //定位id var index =  ...

  7. php 计算本月第一天 本月最后一天 下个月第一天

    本文转载自   http://jin541223.blog.163.com/blog/static/1637398052011111233018533/ //本周第一天(星期日为一周开始) echo ...

  8. PHP include()和require()方法的区别

    本文总结了PHP的include()和require()两种包含外部文件的方法的不同之处.基本上就是,加载失败的处理方法,性能,以及使用弹性方面的不同. PHP的include()和require() ...

  9. 利用命令控制台cmd进入某个硬盘的某个文件夹的命令是什么?

    在命令行窗口中输入F:后回车就可以切换到F盘,如果想查看F盘的内容,可以再输入dir后回车 (输入“F”后要再输入一个“ :”再回车才行哦)

  10. 关于Servlet的PrintWriter 中文乱码问题

    ps:servlet的PrintWriter和ServletOutputStream是不能同时使用的,同时使用会抛异常; PrintWriter是字符流.ServletOutputStream是字节流 ...