TheSwamp
Code Red => .NET => Topic started by: jtoverka 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.
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?
-
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
-
Thank you John for the advice,
After more inspection it appears that it has to do with redirecting the console Standard IO
/// <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:
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.
-
Read text from a file instead? I am assuming the `RedirectStandardInput` is keyboard entry.
-
I found it. It was this one line:
writer.Close();
Apparently when I remove that one line, it settles the issue.
-
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.
would you mind sharing more about this? I would be highly interested in your solution