Search code examples
c#autocad

How to silently send a synchronous Lisp command to Autocad from c# code?


I am trying to silently send a synchronous Lisp command to autocad from c# code.

Here's how we send a Synchronous command to autocad.

string textToSend = $"(command-s \"_.-layout\" \"_t\" {filePath} {layoutName})";
object acadDoc = Application.DocumentManager.MdiActiveDocument.GetAcadDocument();
acadDoc.GetType().InvokeMember("SendCommand", BindingFlags.InvokeMethod, null, acadDoc, new[] { textToSend + "\n" });

The command works but the problem is that the command ends up in autocad's command line and clogs up the history of the drafters using our extensions.

We tried modifying system variables CMDECHO, CMDDIA, and NOMUTT without success

  • Directly in autocad's command line manually
  • With the c# method SetSystemVariable()
  • The same way we called our InvokeMember("SendCommand")
  • In the same Lisp command where we do our action

I looked at the InvokeMember parameters but didn't see anything that might affect the display of the command like there exists for the ActiveDocument.SendTextToExecute() asynchronous command.

How do we send synchronous Lisp commands to autocad from c# code silently?

Ps: The reason why I am not using WBlockCloneObjects() is because it makes our apps extremely unstable. I am not really interested in opening that whole can of worms in this issue, I'm only stating this to explain why I ended up with the solution from my question.


Solution

  • The title of my question was misleading. I didn't need to run lisp code silently, I needed to run commands in acad's command line silently. It just happened to be that acad's command line accepts lisp code so that's what I was using.

    Instead of running lisp code, I used the method ActiveDocument.Editor.Command() to send my command to autocad. This method is synchronous and is affected by the system variable cmdecho.

    I encountered a subsequent problem; because I was calling this method from a button in the banner with RelayCommand, Editor.Command was throwing the exception eInvalidInput because I was in the Application context instead of the Document context.

    The best way to handle this was to split my first method in two and call the second method with ActiveDocument.SendStringToExecute() which uses the command line so I end up in the Document context. But because SendstringToExecute() is async, I had to rework my method's logic a bit.

    Here is the final result (simplified)

    private Layout Layout;
    
    private RelayCommand _Command_Test;
    public RelayCommand Command_Test
    {
        get
        {
            if (_Command_Test == null)
            {
                _Command_Test = new RelayCommand(
                    (param) =>
                    {
                        FirstMethod();
                    },
                    (param) =>
                    {
                        return true;
                    }
                );
            }
            return _Command_Test;
        }
    }
    
    [CommandMethod("FirstMethod")]
    public void FirstMethod()
    {
        // Many actions and processing
        Layout = new Layout(/*With stuff*/);
        Application.DocumentManager.MdiActiveDocument.SendStringToExecute("SecondMethod ", true, false, false);
    }
    
    [CommandMethod("SecondMethod")]
    public void SecondMethod()
    {
        short cmdecho = (short)Application.GetSystemVariable("cmdecho");
        Application.SetSystemVariable("cmdecho", 0);
        
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
        ed.Command("_.-layout", "_t", Layout.FilePath, Layout.Name);
        
        Application.SetSystemVariable("cmdecho", cmdecho);
        
        // Actions that need to be ran after the command
    }
    
    • I had to split my first method differently to have two sets of synchronous actions.
    • Because CommandMethod can't receive parameters, I had to store information in the fields of the class.
    • I skipped it in the code shown here but I, of course, used try-catches and transactions to handle potential issues.