I've got a form that has the ability to open a drawing, but have run into a complication in the event there is an active command so I've attempted to cancel any potentially active command before opening the documentCode - C#: [Select]I get an error COMExeption Invalid execution context and the drawing does not open.
if (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.Count > 0) { try { //acedCommand(new object[3] {(int)5005, String.Format("{0}{0}", (char)27), 0}); //AcDb.ResultBuffer args = new AcDb.ResultBuffer(); //args.Add(new AcDb.TypedValue(5005, String.Format("{0}{0}", (char)27))); //Command(args); //acedPostCommand("CANCELCMD"); //acedPostCommand(String.Format("{0}{0}", (char)27)); //System.Threading.Thread.Sleep(0); //Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.SendStringToExecute(String.Format("{0}{0}", (char)27), true, false, true); //((AcadDocument)((Document)Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument).GetAcadDocument()).SendCommand(String.Format("{0}{0}", (char)27)); //System.Threading.Thread.Sleep(500); } catch (System.Exception ex) { MessageBox.Show(String.Format("{0}", ex)); } } try { ((DocumentCollection)Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager).Open(((FileInfo)item.Tag).FullName, false); } catch (System.Exception ex) { MessageBox.Show(String.Format("{0}\n{1}", ((FileInfo)item.Tag).FullName, ex)); }
First I tried to find a method of testing for an active command without any luck, would have liked to just tell the user to finish what the hell they were doing before opening another doc.
Then I tried using the SendCommand method through the COM interface. I still get the same error, however after getting the error I can see at the command line that the escape command has been sent. I tried to remedy this with a Thread.Sleep call, but I still get the error. The drawing does however load, but then the focus switches back to the original document, which is pretty user unfriendly :realmad:
Then I tried using acedPostCommand as was suggested in this (http://through-the-interface.typepad.com/through_the_interface/2006/08/cancelling_an_a.html) post by Kean but I still get the same results.
Then I tried using acedCmd as was suggested here (http://forums.autodesk.com/t5/NET/acedcommand-function-in-Net-managed-classes/m-p/1332900) by Tony, as below:Code - C#: [Select]But I'm getting the COM error still and the following error posted to the command line of the active document: Invalid type in acutBuildList() arg #1
[System.Runtime.InteropServices.DllImport("accore.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "acedCmd")] extern static int acedCmd(IntPtr pResbuf); unsafe static int Command(Autodesk.AutoCAD.DatabaseServices.ResultBuffer args) { if (!Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.IsApplicationContext) return acedCmd((IntPtr)args.UnmanagedObject.ToPointer()); else return 0; } //Then in my routine: Command(args);
Although, there were a couple times where for some unknown reason when I manually cancelled the command the document opened
Then I tried using acedCommand as follows with no sign of any command being sent to execute, same COM error:Code - C#: [Select]
[System.Runtime.InteropServices.DllImport("accore.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "acedCommand")] extern static int acedCommand(object[] args); //Then in my routine: //Also tried passing just 0 as mentioned in the docs to just cancel a command
Can anyone comment on why it is that this is throwing a COM exception when I'm running purely through .NET by calling the .Open method?
Thanks
Why cast the (Namespace qualified) DocumentManager to DocumentCollection in the call to Open()?
Can anyone comment on why it is that this is throwing a COM exception when I'm running purely through .NET by calling the .Open method?
You're passing the ResultBuffer's UnmanagedObject.ToPointer() to acedCmd() which is wrong. You pass it only the UnmanagedObject property, which is an IntPtr, and that's it.Thanks, I updated my code to reflect with no success. There was no error however.
Also, you really don't have to screw around with P/Invoke to use the CommandLine. You can call the
Editor's RunCommand method which in addition to doing the messy stuff, also converts managed types to native types, including SelectionSets.
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:
Why cast the (Namespace qualified) DocumentManager to DocumentCollection in the call to Open()?Tony nailed that one. Since this is a WPF form that I'm working inside I have used the fewest possible using declarations. This is the only segment that has any references to autocad. I was able to cut out the other reference thanks to a post regarding getting the preview (http://www.theswamp.org/index.php?topic=44093.msg493904#msg493904) from the .dwg file.
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:Update: I tried using Command("^C^C") as is done in scripts... no such luck
Can anyone comment on why it is that this is throwing a COM exception when I'm running purely through .NET by calling the .Open method?
The DocumentCollection (or DocumentCollectionExtension in 2013) Open() method delegates to the AcadDocument COM wrapper's Open() method under the hood.
Take a look at it with Reflector.
Can anyone comment on why it is that this is throwing a COM exception when I'm running purely through .NET by calling the .Open method?
The DocumentCollection (or DocumentCollectionExtension in 2013) Open() method delegates to the AcadDocument COM wrapper's Open() method under the hood.
Take a look at it with Reflector.
Sorry for the perhaps silly question; I'm relegate to Express. As I understand it that precludes my using extensions like Reflector, etc.
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:Update: I tried using Command("^C^C") as is done in scripts... no such luck
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:Update: I tried using Command("^C^C") as is done in scripts... no such luck
If DocumentCollection.IsApplicationContext == true, You can't use the command line or the Command() wrapper for the RunCommand method.
The way to deal with the problem is to not do anything in your UI handler (e.g., button click, etc.) other than to set a flag, and you should add a handler to the Application's Idle event, and in the handler for that event, check and clear the flag, and if it is set, then try using SendStringToExecute() to cancel the current command as per Kean's blog post.
You can't do much from the WPF UI thread, and that seems to be the problem.
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:Update: I tried using Command("^C^C") as is done in scripts... no such luck
If DocumentCollection.IsApplicationContext == true, You can't use the command line or the Command() wrapper for the RunCommand method.
The way to deal with the problem is to not do anything in your UI handler (e.g., button click, etc.) other than to set a flag, and you should add a handler to the Application's Idle event, and in the handler for that event, check and clear the flag, and if it is set, then try using SendStringToExecute() to cancel the current command as per Kean's blog post.
You can't do much from the WPF UI thread, and that seems to be the problem.
You can use this reflection-free wrapper to invoke RunCommand(), which is a little faster than calling it via Reflection:Code - C#: [Select]
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; using System.Reflection; using Autodesk.AutoCAD.ApplicationServices; namespace Autodesk.AutoCAD.EditorInput { public static class EditorInputExtensionMethods { public static PromptStatus Command( this Editor editor, params object[] args ) { if( editor == null ) return runCommand( editor, args ); } static Func<Editor, object[], PromptStatus> runCommand = GenerateRunCommand(); static Func<Editor, object[], PromptStatus> GenerateRunCommand() { BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public ); return Expression.Lambda<Func<Editor, object[], PromptStatus>>( Expression.Call( instance, method, args ), instance, args ) .Compile(); } } }