Solution to RPC_E_CALL_REJECTED when an external program starts AutoCAD through COM

Source: Internet
Author: User

The second development of AutoCAD adopts the plug-in method, that is, run the AutoCAD.net API to compile the dll file, and enter the netload command in the AutoCAD command line to load your custom plug-in dll. Generally, you may need to start AutoCAD in your own main interface program and execute your custom commands during AutoCAD Development. In this case, we can do it in the following way. If you use AutoCAD 2010 or later, you may encounter Problem executing component: Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED. The following methods apply to both Map 3D and Civil 3D.

 

 

Enable external programs to start AutoCAD

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

Create a Class library project in Visual Studio, named myplugin here, compile and generate the assembly of myplugin. dll. This project is your main work project for AutoCAD extension. You can add references to AutoCAD-related Assembly and create custom commands. Needless to say. If you need to start AutoCAD in your main program window. You can create a WinForm project in the solution, such as StartCAD. Put a button in the Form and the title is Start AutoCAD. Then adjust the output path of your myplugin to the bin directory of StartCAD to help StartCAD find your custom application assembly.

 

The following code starts AutoCAD in the StartCAD project and automatically loads myplugin. dll. Add the following COM references to the StartCAD project:

Autoscaling 2012 Type Library

AutoCAD/ObjectDBX Common 18.0 Type Library

 

The code for Button1.Click is as follows:

 

Private void button#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 it Type sType = Type. getTypeFromProgID (programID); cadApp = (Autodesk. autoCAD. interop. acadApplication) Activa Tor. 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 assembly if (cadApp! = Null) {cadApp. Visible = true; // [corresponding to AutoCAD 2010 Update1 and later]Problem executing component: Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED ))// Load my custom plugin assembly cadApp. activeDocument. sendCommand ("filedia \ r0 \ r"); // close the file dialog box mode // load the custom Assembly cadApp using the netload command. activeDocument. sendCommand ("netload \ r" + Application. startupPath + "\ myplugin. dll \ r "); // then open the file dialog box mode cadApp. activeDocument. sendCommand ("filedia \ r1 \ r"); this. close ();}}

 

 

 

Possible problems and Analysis

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

If you use a version earlier than AutoCAD 2010, the above Code should be fine. However, if you use AutoCAD 2010 Update1 or a later version, you may encounter the following error:

 

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

 

According to Kean's blog, this "problem" is introduced by AutoCAD to solve the problem that may crash when receiving COM messages. Since Microsoft decided not to support nested message loops in WPF, if WPF is performing layout processing operations (Dispatcher will be called at this time. disableProcessing stops processing messages, and then receives a COM call, which may cause AutoCAD to crash. So the improvement now is to reject this COM call so that he can call it again later. Therefore, the preceding error message RPC_E_CALL_REJECTED is available.

 

The solution is to let our Form1 class implement the IMessageFilter interface of COM, which is an IUnknown interface, its function is to enable the COM server or application to process the input or input COM messages while waiting for the synchronous call response. This message filtering mechanism allows the COM server to determine whether a call is safe, but it causes a deadlock. COM will call the implementation of your IMessageFilter, so that you have the opportunity to further process the message.

 

IMessageFilterThe interface has the following three methods:

HandleInComingCallProvides a single entry for input calls

Provides a single entry point for incoming CILS.

The returned value is:

The SERVERCALL_ISHANDLED application may be able to handle this call the application might be able to process The call.
The SERVERCALL_REJECTED application cannot handle this call due to unpredictable issues. The application cannot handle the call due to an unforeseen problem, such as network unavailability, or if it is in the process of terminating.
The SERVERCALL_RETRYLATER application cannot handle the application cannot handle The call at this time. An application might return this value when it is in a user-controlled modal state.

MessagePendingA message is sent when COM is waiting for a remote call response.

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

The returned value is:

PENDINGMSG_CANCELCALL cancels the call and is only used in extreme cases.
Cancel the outgoing call. this shoshould 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 does not send messages and continues waiting for response
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 no longer distributes keyboard and mouse events, but distributes WM_PAINT messages. The task switching and scheduled messages are processed properly.
Keyboard and mouse messages are no longer dispatched. however there are some cases where mouse and keyboard messages cocould 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.

RetryRejectedCallA dialog box is displayed for the application to choose "retry", "cancel", or "switch task.

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

The returned value is:

-1 call will cancel The call shocould be canceled. COM then returns RPC_E_CALL_REJECTED from the original method call.
0 ≤ Value<100 call will immediately retry The call is to be retried immediately.
100 ≤ ValueThe call will be retried after the specified time, in milliseconds. COM will wait for this example milliseconds and then retry the call.

 

 

Solution

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

As mentioned above, AutoCAD rejects the COM call message when processing the layout of WPF. We can implement an IMessageFilter interface and call it again after a while. The following is the improved code:

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 running                cadApp = (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 assembly                cadApp.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 Members        int 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    }}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.