AutoCAD.NET 不使用P/Invoke方式调用acad.exe或accore.dll中的接口(如acedCommand、acedPostCommand等)
使用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等)的更多相关文章
- .netcore在linux下使用P/invoke方式调用linux动态库
http://www.mamicode.com/info-detail-2358309.html .netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件 1 ...
- Delphi调用DLL中的接口
问题描述: 具体问题就是在隐式使用接口变量后,在FreeLibrary执行后,就会出现一个非法访址的错误. 这个错误的原因就是在FreeLibrary后,DLL以的代码均为不可用状态,而在代码执行完整 ...
- Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)
文章目录: 1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...
- DLL模块例1:使用.def模块导出函数,规范修饰名称,显示连接调用dll中函数
以下内容,我看了多篇文章,整合在一起,写的一个例子,关于dll工程的创建,请参考博客里另一篇文章:http://www.cnblogs.com/pingge/articles/3153571.html ...
- 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)
反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法) 创建Delegate (1).Delegate.CreateDelegate(Type, ...
- Atitit 动态调用webservice与客户端代理方式调用
Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke 直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...
- YbSoftwareFactory 代码生成插件【二十五】:Razor视图中以全局方式调用后台方法输出页面代码的三种方法
上一篇介绍了 MVC中实现动态自定义路由 的实现,本篇将介绍Razor视图中以全局方式调用后台方法输出页面代码的三种方法. 框架最新的升级实现了一个页面部件功能,其实就是通过后台方法查询数据库内容,把 ...
- HttpClient Get/Post方式调用Http接口
本节摘要:本节主要分别介绍如何用get方式.post方式向http接口发送数据. preparation 1. 项目环境如下: myeclipse6.5 .tomcat5.0.system:xp.JD ...
- C#以post方式调用struts rest-plugin service的问题
struts2: 玩转 rest-plugin一文中,学习了用struts2开发restful service的方法,发现用c#以post方式调用时各种报错,但java.ajax,包括firefox ...
随机推荐
- bootstrapValidator对于隐藏域验证和程序赋值即时验证的问题
问题1: 如下代码: <input type="hidden" name="productId"/> $("#addForm") ...
- Windows系统下Memcached缓存系列一:Couchbase(服务器端)和CouchbaseClient(c#客户端)的安装教程
一:服务器端的安装 官网 http://www.couchbase.com/download 我的电脑是64位的win7,找到对应下载windows版本的服务器端缓存,大概90M的样子 运行期间可 ...
- &引用的问题
C++中&可以代表引用也代表取地址符. 引用这一方面略微有点头大. 注意: 1)引用的函数可以作为左值 一个简单的作为左值的例子 #include <iostream> using ...
- (六) 6.2 Neurons Networks Backpropagation Algorithm
今天得主题是BP算法.大规模的神经网络可以使用batch gradient descent算法求解,也可以使用 stochastic gradient descent 算法,求解的关键问题在于求得每层 ...
- Android 一步步教你从ActionBar迁移到ToolBar
谷歌的材料设计也发布了有一段时间了,包括官方的support库 相信大家也熟悉了不少,今天就把actionbar 迁移到toolbar的 经验发出来. 这个地方要注意 我用的图标都是studio里的一 ...
- SQLSERVER 检查字段值域并输出行数和值列表
select * from ( SELECT 'C_DILEI' as fen,'地类' as fcn, 'NVARCHAR'as ftype, '2'as flen, ( SELECT count( ...
- 浅谈MySQL Replication(复制)基本原理
1.MySQL Replication复制进程MySQL的复制(replication)是一个异步的复制,从一个MySQL instace(称之为Master)复制到另一个MySQL instance ...
- hdu 1166 敌兵布阵(线段树单点更新,区间查询)
题意:区间和 思路:线段树 #include<iostream> #include<stdio.h> using namespace std; #define MAXN 500 ...
- Oracle数据泵
要使用数据泵必须先创建数据库目录 数据库目录只允许sys创建 普通用户使用 必须授权 假设scott 用户是导出导入用户 SQL> ! mkdir dp_dir SQ ...
- jquery checkbox勾选取消勾选的诡异问题
jquery checkbox勾选/取消勾选的诡异问题jquery checkbox勾选/取消勾选的诡异问题 <form> 你爱好的运动是?<input type=&q ...