使用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. bootstrapValidator对于隐藏域验证和程序赋值即时验证的问题

    问题1: 如下代码: <input type="hidden" name="productId"/> $("#addForm") ...

  2. Windows系统下Memcached缓存系列一:Couchbase(服务器端)和CouchbaseClient(c#客户端)的安装教程

    一:服务器端的安装  官网 http://www.couchbase.com/download  我的电脑是64位的win7,找到对应下载windows版本的服务器端缓存,大概90M的样子 运行期间可 ...

  3. &引用的问题

    C++中&可以代表引用也代表取地址符. 引用这一方面略微有点头大. 注意: 1)引用的函数可以作为左值 一个简单的作为左值的例子 #include <iostream> using ...

  4. (六) 6.2 Neurons Networks Backpropagation Algorithm

    今天得主题是BP算法.大规模的神经网络可以使用batch gradient descent算法求解,也可以使用 stochastic gradient descent 算法,求解的关键问题在于求得每层 ...

  5. Android 一步步教你从ActionBar迁移到ToolBar

    谷歌的材料设计也发布了有一段时间了,包括官方的support库 相信大家也熟悉了不少,今天就把actionbar 迁移到toolbar的 经验发出来. 这个地方要注意 我用的图标都是studio里的一 ...

  6. SQLSERVER 检查字段值域并输出行数和值列表

    select * from ( SELECT 'C_DILEI' as fen,'地类' as fcn, 'NVARCHAR'as ftype, '2'as flen, ( SELECT count( ...

  7. 浅谈MySQL Replication(复制)基本原理

    1.MySQL Replication复制进程MySQL的复制(replication)是一个异步的复制,从一个MySQL instace(称之为Master)复制到另一个MySQL instance ...

  8. hdu 1166 敌兵布阵(线段树单点更新,区间查询)

    题意:区间和 思路:线段树 #include<iostream> #include<stdio.h> using namespace std; #define MAXN 500 ...

  9. Oracle数据泵

    要使用数据泵必须先创建数据库目录        数据库目录只允许sys创建        普通用户使用 必须授权 假设scott 用户是导出导入用户 SQL> ! mkdir dp_dir SQ ...

  10. jquery checkbox勾选取消勾选的诡异问题

    jquery checkbox勾选/取消勾选的诡异问题jquery checkbox勾选/取消勾选的诡异问题 <form>        你爱好的运动是?<input type=&q ...