使用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获取设备系统信息

    UIDevice *device_=[[UIDevice alloc] init]; NSLog(@"设备所有者的名称--%@",device_.name); NSLog(@&qu ...

  2. HDU 1023 Train Problem II (卡特兰数,经典)

    题意: 给出一个数字n,假设火车从1~n的顺序分别进站,求有多少种出站序列. 思路: 卡特兰数的经典例子.n<101,用递推式解决.需要使用到大数.n=100时大概有200位以下. #inclu ...

  3. 09day1

    词编码 模拟 [问题描述] 一个发送机可以通过一条隧道发送一些以二进制代码组成的单词.在其尽头的接受机可以使用特殊技术恢复到最初的单词.每个单词最初都由0和1组成.所有的单词最初长度都为n(4< ...

  4. .Net dll多个同名的程序集版本冲突共存与通过基本代码或探测定位程序集方案

    .Net dll多个同名的程序集版本冲突共存与通过基本代码或探测定位程序集方案 在使用调用程序集的引用中的信息和配置文件中的信息确定了正确的程序集版本之后,并且在公共语言运行时在全局程序集缓存中进行检 ...

  5. 极大似然估计&最大后验概率估计

    https://guangchun.wordpress.com/2011/10/13/ml-bayes-map/ http://www.mi.fu-berlin.de/wiki/pub/ABI/Gen ...

  6. phonegap 检查是否有网络

    在主active onCreate函数中实现 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(sa ...

  7. 二:ZooKeeper术语概念

    一:Zookeeper的设计目标   -->Zookeeper致力于提供一个高性能,高可用,且具有严格的顺序访问控制能力(主要是写操作的严格顺行性)的分布式协调服务. -->高性能使得Zo ...

  8. 【转】Xcode6 模拟器路径

    原文网址:http://www.cocoachina.com/bbs/read.php?tid-231024.html Xcode6发布后,出现了很多的变动,功能性的变动,在这里不进行过多的赘述,在W ...

  9. 别人的的MYSQL学习心得(十五) 日志

    我的MYSQL学习心得(十五) 日志 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  10. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:4.安装Oracle RAC FAQ-4.1.系统界面报错Gnome

    1.错误信息:登录系统后,屏幕弹出几个错误对话框,无菜单.无按钮 GConf error: Failed to contact configuration server; some possible ...