Author Topic: Running AutoCAD Core Console  (Read 180 times)

0 Members and 1 Guest are viewing this topic.

jtoverka

  • Newt
  • Posts: 108
Running AutoCAD Core Console
« on: April 21, 2021, 08:03:39 AM »
Gentlemen,

I have found a way to run the AutoCAD Core Console with the window invisible, set secureload to 0, then Netload a dll, run a .NET Lisp application with an argument, a GUID string. This string is the pipe name for inter process communication. This allows external applications to process dwgs elegantly.

The AutoCAD Core Console itself uses very little RAM in comparison to AutoCAD. When it is idling it uses 0% CPU power. The problem I am running into is that my application is hogging a lot of CPU power. I have 10 cores, 20 threads in my intel I9 CPU. It is using one thread at 100%, or 5% of an entire CPU. I want to reduce this to ~0.1% when the program is idling.

The following is my code that runs in the AutoCAD Core Console.

Code: [Select]
using AcConsole;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Clifton.Core.Pipes;
using NetDBX;
using System.Collections.Generic;
using System.IO;

namespace AcConsoleIn
{
    /// <summary>
    /// Provides static methods to run within AutoCAD Core Console
    /// </summary>
    public static class Run
    {
        // IPC Pipe
        private static ClientPipe Client { get; set; }

        /// <summary>
        /// Provides the Lisp Function to connect this process to an external application.
        /// </summary>
        /// <param name="buffer"></param>
        [LispFunction("PROCESS")]
        public static void Process(ResultBuffer buffer)
        {
            try
            {
                using (buffer)
                {
                    // Process input
                    List<TypedValue> args = AutoLisp.HandleLispArguments(buffer, 1, 1);

                    // Create and connect IPC pipe
                    string pipeName = AutoLisp.LispToString(args[0]);
                    Client = new ClientPipe(".", pipeName, p => p.StartStringReaderAsync());
                    Client.DataReceived += Client_DataReceived;
                    Client.Connect();
                }
            }
            catch { }
        }

        /// <summary>
        /// Event Handler for processing data from server.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void Client_DataReceived(object sender, PipeEventArgs e)
        {
            // Exit if communication pipe is broken
            if (Client == null)
                return;

            try
            {
                // Check for a close application message
                if (e.String == "Close Application")
                {
                    // Disconnect Pipe
                    Client.DataReceived -= Client_DataReceived;
                    Client.Close();
                    Client = null;

                    // Close AutoCAD
                    Autodesk.AutoCAD.ApplicationServices.Core.Application.Quit();
                    return;
                }

                // Tell server that this is busy
                Client.WriteString("1");

                // Get database object
                AcConsole.DatabaseServices.Database database;
                database = IO.XmlDeserializeFromString<AcConsole.DatabaseServices.Database>(e.String);

                // Throw error if it received an invalid database object
                if (database == null)
                    throw new InvalidDataException("Invalid Database Object");

                // Create new drawing
                using Database drawing = new Database(true, true);

                using (Transaction transaction = drawing.TransactionManager.StartTransaction())
                {
                    // Convert AcConsole.DatabaseServices.Database to Autodesk.AutoCAD.DatabaseServices.Database
                    database.ToDatabase(drawing, transaction);
                    transaction.Commit();
                }

                // Delete file if it exists
                string filename = database.Filename;
                if (File.Exists(filename))
                    File.Delete(filename);

                // Save drawing
                drawing.SaveAs(filename, DwgVersion.Current);

                // Tell Server it is not busy.
                Client.WriteString("0");
            }
            catch (System.Exception ex)
            {
                // Tell server that an error occured.
                Client.WriteString(ex.Message);
            }
        }
    }
}


I thought if I use an event handler, I would not use any CPU power when it is idling. Could anyone help me out?

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9596
Re: Running AutoCAD Core Console
« Reply #1 on: April 21, 2021, 11:01:42 AM »
Warning: I am not good with C#. This response is more along the theory side.

What about using TASKS?
https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?redirectedfrom=MSDN&view=net-5.0
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

jtoverka

  • Newt
  • Posts: 108
Re: Running AutoCAD Core Console
« Reply #2 on: April 21, 2021, 01:33:05 PM »
Thank you John for the advice,
After more inspection it appears that it has to do with redirecting the console Standard IO

Code: [Select]

        /// <summary>
        /// Initializes a new instance of this class
        /// </summary>
        public Console()
        {
            try
            {
                string installpath = null;

                // Search the directory for the AutoCAD Console Application
                foreach (string file in Directory.GetFiles(@"C:\Program Files\Autodesk\", "accoreconsole.exe", SearchOption.AllDirectories))
                {
                    if (Path.GetFileName(file).Equals("accoreconsole.exe", StringComparison.OrdinalIgnoreCase))
                    {
                        installpath = file;
                        break;
                    }
                }

                // Set up process
                coreprocess.StartInfo.Arguments = "/isolate";
                coreprocess.StartInfo.UseShellExecute = false;
                coreprocess.StartInfo.CreateNoWindow = true;
                coreprocess.StartInfo.RedirectStandardOutput = false;
                coreprocess.StartInfo.RedirectStandardInput = true;
                coreprocess.StartInfo.FileName = installpath;
               
                // Start Process
                this.ConsoleStarted = coreprocess.Start();

                // Load program to AutoCAD Core Console
                if (this.ConsoleStarted)
                {
                    // Get program running inside accoreconsole
                    string loadDLL = Directory.GetCurrentDirectory() + "\\AcConsoleIn.dll";

                    using StreamWriter writer = coreprocess.StandardInput;

                    // Set up the IPC pipe connection
                    string guid = Guid.NewGuid().ToString().ToUpper();
                    server = new(guid, p => p.StartStringReaderAsync());
                    server.Connected += Server_Connected;
                    server.DataReceived += Server_DataReceived;

                    // Write to AutoCAD Core Console
                    writer.WriteLine("SECURELOAD 0");
                    writer.WriteLine("NETLOAD " + loadDLL);
                    writer.WriteLine("(PROCESS \"" + guid + "\") ");
                    writer.Close();
                }
            }
            catch { }
        }

If I comment out the writer section of the code, it still runs at 5% despite not running anything. However, if I change the following:
Code: [Select]
coreprocess.StartInfo.RedirectStandardInput = false;
It runs at 0%.
So the Redirecting of Standard Input does this. How do I fix this?
I need to write to the console, and would like to not run 100% of a thread.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9596
Re: Running AutoCAD Core Console
« Reply #3 on: April 21, 2021, 01:55:42 PM »
Read text from a file instead? I am assuming the `RedirectStandardInput` is keyboard entry.
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

jtoverka

  • Newt
  • Posts: 108
Re: Running AutoCAD Core Console
« Reply #4 on: April 21, 2021, 04:15:30 PM »
I found it. It was this one line:

Code: [Select]
writer.Close();
Apparently when I remove that one line, it settles the issue.