对AutoCAD的二次开发是采用插件的方式,即运行AutoCAD.net API编写dll文件,运行时在AutoCAD命令行中输入netload命令来加载你的自定义插件dll。一般AutoCAD开发过程中你可能需要在你自己的主界面程序里启动AutoCAD并执行你的自定义命令。这时可以通过下面的方式来做。如果你用AutoCAD 2010及以上版本可能会遇到Problem executing component: Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED))的问题,下文一并分析解决。以下方法同时适用于Map 3D和Civil 3D。 

实现外部程序启动AutoCAD

~~~~~~~~~~~~~~~~~~~~~~~~~

在Visual Studio里新建一个Class library的工程,这里命名为myplugin, 编译生成myplugin.dll的程序集。这个项目是你对AutoCAD扩展的主要工作项目,你可以添加AutoCAD相关程序集的引用,并创建自定义命令等等。这个不用多说。如果你需要在自己的主程序窗口中启动AutoCAD。可以在解决方案里创建一个WinForm的项目,比如叫做StartCAD,在Form里放一个button,标题为Start AutoCAD。然后调整你的myplugin的输出路径到StartCAD的bin目录下,方便StartCAD找到你的自定义应用程序集。 如图:

下面实现StartCAD项目中启动AutoCAD并自动加载myplugin.dll . 在StartCAD项目中需要添加如下COM引用:

AutoCAD 2012 Type Library

AutoCAD/ObjectDBX Common 18.0 Type Library

下面是Button1.Click的代码:

        private void button1_Click(object sender, EventArgs e){Autodesk.AutoCAD.Interop.AcadApplication cadApp = null;try{//Get the AutoCAD which is running,cadApp = (Autodesk.AutoCAD.Interop.AcadApplication)Marshal.GetActiveObject(programID);}catch{try{//If AutoCAD is not running, start itType sType = Type.GetTypeFromProgID(programID);cadApp = (Autodesk.AutoCAD.Interop.AcadApplication)Activator.CreateInstance(sType, true);cadApp.Visible = true;}catch (Exception ex){MessageBox.Show("Cannot open AutoCAD. \n Error message : " + ex.Message);}}//send command to AutoCAD to load our custom assemblyif (cadApp != null){cadApp.Visible = true; //[对应AutoCAD 2010 Update1 及以上] //Load my custom plugin assemblycadApp.ActiveDocument.SendCommand("filedia\r0\r"); // 关闭文件对话框模式//通过netload命令加载自定义程序集cadApp.ActiveDocument.SendCommand("netload\r" + Application.StartupPath + "\\myplugin.dll\r");//再打开文件对话框模式cadApp.ActiveDocument.SendCommand("filedia\r1\r");this.Close();}}

可能会遇到的问题及分析

~~~~~~~~~~~~~~~~~~~~~~~~~

如果你用AutoCAD 2010以前版本,上面代码应该没什么问题。但如果你用AutoCAD 2010 Update1及以后版本,你可能会遇到如下错误:

Problem executing component: Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED))

根据Kean的博客,这个“问题”是由于AutoCAD为了解决接受COM消息时可能出现崩溃的问题而引入的。由于微软决定在WPF中不支持嵌套消息循环,如果WPF正在进行布局处理操作时(这时会调用Dispatcher.DisableProcessing 停止处理消息)又接到COM调用,可能会造成AutoCAD崩溃。所以现在的改进是拒绝这个COM调用,以便让他过一会儿再重新调用。所以就有了上面的错误消息RPC_E_CALL_REJECTED。

解决的方法就是让我们的Form1类实现COM的IMessageFilter接口,这个接口是一个IUnknown接口,他的作用是使得COM服务器或者应用程序能够在等待同步调用响应时选择处理输入或者输入的COM消息。通过这个消息过滤机制,可以让COM 服务器来判定某个调用是否安全,不过造成死锁。COM会调用你的IMessageFilter的实现,从而使得你有机会来对消息做进一步的处理。

IMessageFilter 接口有下面3个方法:

HandleInComingCall 提供了一个输入调用的单一入口

Provides a single entry point for incoming calls.

他的返回值为:

SERVERCALL_ISHANDLED  应用程序也许能够处理这个调用The application might be able to process the call.SERVERCALL_REJECTED   应用程序由于一些不可预计的问题处理不了这个调用。The application cannot handle the call due to an unforeseen problem, such as network unavailability, or if it is in the process of terminating.SERVERCALL_RETRYLATER  应用程序现在处理不了The application cannot handle the call at this time. An application might return this value when it is in a user-controlled modal state.

MessagePending COM的等待远程调用响应的时候来了一个消息

Indicates that a message has arrived while COM is waiting to respond to a remote call.

他的返回值为:

PENDINGMSG_CANCELCALL  取消调用,只在极端情况下使用。Cancel the outgoing call. This should be returned only under extreme conditions. Canceling a call that has not replied or been rejected can create orphan transactions and lose resources. COM fails the original call and returns RPC_E_CALL_CANCELLED.PENDINGMSG_WAITNOPROCESS  不派发消息继续等待回应Continue waiting for the reply, and do not dispatch the message unless it is a task-switching or window-activation message. A subsequent message will trigger another call to MessagePending. Leaving messages or events in the queue enables them to be processed normally, if the outgoing call is completed. Note that returning PENDINGMSG_WAITNOPROCESS can cause the message queue to fill.PENDINGMSG_WAITDEFPROCESS 不再派发键盘和鼠标事件,但派发WM_PAINT消息,任务切换和计划消息正常处理Keyboard and mouse messages are no longer dispatched. However there are some cases where mouse and keyboard messages could cause the system to deadlock, and in these cases, mouse and keyboard messages are discarded. WM_PAINT messages are dispatched. Task-switching and activation messages are handled as before.

RetryRejectedCall 提供给应用程序一个显示一个以对话框来选择重试,取消还是切换任务的选择。

Provides applications with an opportunity to display a dialog box offering retry, cancel, or task-switching options.

他的返回值是:

-1          调用会取消The call should be canceled. COM then returns RPC_E_CALL_REJECTED from the original method call.0 ≤ value < 100   调用会立即重试The call is to be retried immediately.100 ≤ value     调用会在指定时间后重试,以毫秒计。COM will wait for this many milliseconds and then retry the call.

解决办法

~~~~~~~~~~~~~~~~~~~~~~~~~

上面提到AutoCAD在WPF进行布局处理时拒绝了COM调用的消息,我们可以实现一个IMessageFilter的接口,等待一段时间再重新调用,下面是改进后的代码:

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 System.Runtime.InteropServices;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;namespace StartAutoCAD
{// about IMessageFilter Interface http://msdn.microsoft.com/zh-cn/library/ms693740%28v=VS.85%29.aspx [ComImport,InterfaceType(ComInterfaceType.InterfaceIsIUnknown),Guid("00000016-0000-0000-C000-000000000046")]public interface IMessageFilter{[PreserveSig]int HandleInComingCall(int dwCallType,IntPtr hTaskCaller,int dwTickCount,IntPtr lpInterfaceInfo);[PreserveSig]int MessagePending(IntPtr hTaskCallee,int dwTickCount,int dwPendingType);[PreserveSig]int RetryRejectedCall(IntPtr hTaskCallee,int dwTickCount,int dwRejectType);}public partial class Form1 : Form, IMessageFilter{string programID = "AutoCAD.Application";[DllImport("ole32.dll")]static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter,out IMessageFilter lplpMessageFilter);public Form1(){InitializeComponent();IMessageFilter oldFilter;CoRegisterMessageFilter(this, out oldFilter);}private void button1_Click(object sender, EventArgs e){Autodesk.AutoCAD.Interop.AcadApplication cadApp = null;try{//Get the AutoCAD which is runningcadApp = (Autodesk.AutoCAD.Interop.AcadApplication)Marshal.GetActiveObject(programID);}catch{try{Type sType = Type.GetTypeFromProgID(programID);cadApp = (Autodesk.AutoCAD.Interop.AcadApplication)Activator.CreateInstance(sType, true);cadApp.Visible = true;}catch (Exception ex){MessageBox.Show("Cannot open AutoCAD. \n Error message : " + ex.Message);}}if (cadApp != null){cadApp.Visible = true;//Load my custom plugin assemblycadApp.ActiveDocument.SendCommand("filedia\r0\r");cadApp.ActiveDocument.SendCommand("netload\r" + Application.StartupPath + "\\myplugin.dll\r");cadApp.ActiveDocument.SendCommand("filedia\r1\r");this.Close();}}#region IMessageFilter Membersint IMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo){return 0; // SERVERCALL_ISHANDLED}int IMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType){return 1; // PENDINGMSG_WAITNOPROCESS}int IMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType){return 1000; // Retry in a second}#endregion}
}

作者:峻祁连
邮箱:junqilian@163.com 
出处:http://junqilian.cnblogs.com 
转载请保留此信息。
本文转自峻祁连. Moving to Cloud/Mobile博客园博客,原文链接:http://www.cnblogs.com/junqilian/archive/2011/08/21/2148630.html,如需转载请自行联系原作者

外部程序通过COM启动AutoCAD时RPC_E_CALL_REJECTED的问题解决办法相关推荐

  1. EPIC客户端 “在我们启动更新时请稍后”解决办法

    EPIC客户端 "在我们启动更新时请稍后"解决办法 已经尝试的方法:使用各种 加速器 标题解决问题的方法: 实例:

  2. cad2006安装未找到html文件,启动 AutoCAD 时显示“加载自定义文件失败。未找到文件”...

    解决方案: 执行以下一个或多个操作: 查找安装的 ARG 文件是否来自 AutoCAD 工具组合 ARG 文件无法从 AutoCAD 工具组合(如 AutoCAD Architecture.AutoC ...

  3. 启动AutoCAD时显示“无效的配置路径/文件名”

    出现原因 我原来的电脑账户是中文,因为别的地方使用时不能出现中文,所以就把账户改成了英文,结果导致以前安装的Autocad打不开了,出现的问题如题. 解决教程(有效) 链接 https://knowl ...

  4. AndroidStudio启动app时闪退问题解决过程

    问题描述: Android app在启动时闪退的问题有很多种,大部分可能集中在代码有问题上,譬如StartActivity的时候启动不了. 看提示里一般是有错误出现的,这个很好解决,只要找到对应的错误 ...

  5. python读写csv时中文乱码问题解决办法

    参考1 参考2 参考3 CSV是英文Comma Separate Values(逗号分隔值)的缩写,顾名思义,文档的内容是由 "," 分隔的一列列的数据构成的,可以使用excel和 ...

  6. python csv 中文乱码_python读写csv时中文乱码问题解决办法

    CSV是英文Comma Separate Values(逗号分隔值)的缩写,顾名思义,文档的内容是由 "," 分隔的一列列的数据构成的,可以使用excel和文本编辑器等打开.CSV ...

  7. Tomcat 8.5.29启动报TldScanner.scanJars错误问题解决办法

    Tomcat 8.5.29启动过程中的错误信息: 16-Mar-2018 09:28:45.505 信息 [RMI TCP Connection(3)-127.0.0.1] org.apache.ja ...

  8. IE8 下 select option 内容过长 , 展开时信息显示不全问题解决办法

    为什么80%的码农都做不了架构师?>>>    /*** IE8 下 select option 内容过长 , 展开时信息显示不全 , 简单折衷的方式就是给 option 加上 ti ...

  9. 易康(ESP2插件)运行时出现的问题解决办法

    满满干货,解决在易康软件中ESP2插件运行出现的几个问题: 一.提示内存不足(not enough memory) 解决办法:图像太大,将载入的文件进行裁剪等操作. 二.运行ESP2插件并没有txt文 ...

最新文章

  1. IEDA与activiti不兼容等等安装错误问题的解决方案
  2. 【推荐】LSI(latent semantic indexing) 完美教程
  3. Qt Creator指定环境设置
  4. Vue报错bash: vue: command not found或者vue ui没有反应:官方修改成新的命令了
  5. python读取sqlserver数据库方法_SQLServer数据库之Python读取配置文件,并连接数据库SQL Server...
  6. THINKPHP增删改查--(改)
  7. java miniui datagrid_miniui datagrid 的客户端分页解决方案
  8. Android 获取imageview的图,在另一个imageview里显示,还能得到图片
  9. java读取ifc文件_IFC - 西北逍遥 - 博客园
  10. [网络诈骗]奈几利亚(奈及利亚), E-Mail 骗术
  11. 设备间子系统的工程技术
  12. R语言计算回归模型R方(R-Squared)实战
  13. 【计算机毕业设计】137欢迪迈手机商城设计与实现
  14. 行情平淡期做市商如何刷量 说一个网格策略魔改高频刷单策略的思路
  15. python笔记-05(条件、循环及其他语句)
  16. EXCEL--如何做多选对话框
  17. 【Kafka笔记】4.Kafka API详细解析 Java版本(Producer API,Consumer API,拦截器等)
  18. 计算机大赛a类有哪些,A类 B类学科竞赛项目清单
  19. NFT带给我们普通人的机遇是什么?
  20. [附源码]java毕业设计毕业设计管理系统

热门文章

  1. 8x8LED点阵显示数字和汉字
  2. 简单5步,从0开始搭建你的第一款小程序
  3. Tiva单片机——简易示波器(UART串口屏)
  4. Bootstra 警告框
  5. vscode 编译so库,并且引用so库调试
  6. node.js fs模块_Node.js中的fs模块简介
  7. 构造函数,定义一个网络用户类,信息有用户 ID、用户密码、 email 地址
  8. 用随机函数实现一组双色球号码
  9. Windows Mobile 5.0 SDK R2 for Pocket PC 安装错误解决方案
  10. 计算机类公务员 真题解析,公务员考试C类计算机考试真题及答案2[文].pdf