Okay, so you've run into the Interop/In-Process automation issue. Traditionally, AutoCAD doesn't want to let out of process modules talk to in-process modules, at least in the context of sending parameters back and forth. The formal approach which involves registering the in-process COM interface is challenging to get behaving correctly, especially in the context of x64 bit. I've still yet to see it behave consistently across multiple computers, therefore I tend to default to the following approach.
You are correct in that methods flagged with the [CommandMethod] flag cannot take arguments, so they'll obviously need to be voids. The trick to sending it parameter context at runtime is to include parameter prompts in the defined method itself. Think of it as you're developing the command to be invoked by the user inside AutoCAD, and they are prompted for each piece of data before the command can proceed. Much like other native AutoCAD commands, the parameter data can be sent alongside the call to the command in a single string.
Example:
(Command "._CIRCLE" "0,0" "5") <-- Draws a circle at 0,0 with a radius of 5.
So your command call could end up looking something like this:
(Command "DRAWDBCIRCLE" "2.3,56.12", "7" "Gauge" "Label" "Title")
In-Process Code
[CommandMethod("DRAWDBCIRCLE")]
public void DrawDbCircle()
{
var acDb = HostApplicationServices.WorkingDatabase;
var acEd = Application.DocumentManager.MdiActiveDocument.Editor;
using (var acTrans = acDb.TransactionManager.StartOpenCloseTransaction())
{
var bt = (BlockTable)acTrans.GetObject(acDb.BlockTableId, OpenMode.ForWrite);
var btr = (BlockTableRecord)acTrans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
Point3d centerPoint;
double radius;
string gauge, label, title;
// Prompt for the centerpoint
var pointResult = acEd.GetPoint("ENTER CIRCLE ORIGIN: \n");
centerPoint = pointResult.Value;
// Prompt for the radius
var doubleResult = acEd.GetDouble("ENTER CIRCLE RADIUS: \n");
radius = doubleResult.Value;
// Prompt for the strings
var stringResult = acEd.GetString("ENTER CIRCLE GAUGE: \n");
gauge = stringResult.StringResult;
stringResult = acEd.GetString("ENTER CIRCLE LABEL: \n");
label = stringResult.StringResult;
stringResult = acEd.GetString("ENTER CIRCLE TITLE: \n");
title = stringResult.StringResult;
// Create the circle
var circ = new Circle(centerPoint, Vector3d.ZAxis, radius);
// <-- Add code for dealing with strings -->
btr.AppendEntity(circ);
acTrans.AddNewlyCreatedDBObject(circ, true);
acTrans.Commit();
}
}
Interop Code
private AcadApplication acApp;
private AcadDocument acDoc;
private void btnRun_Click(object sender, EventArgs e)
{
if (acApp == null) return;
acDoc = acApp.ActiveDocument;
foreach (DataRow row in circleTable.Rows)
DrawDatabaseCircle(row);
}
private void DrawDatabaseCircle(DataRow circRow)
{
var cmdFormat = string.Format("\"{0},{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\"", circRow.ItemArray);
acDoc.SendCommand(string.Format("(Command \"DRAWDBCIRCLE\" {0})\n", cmdFormat));
}
Obviously this is more or less pseudo-code. I assume a number of things here, like the AcadApplication and AcadDocument fields being set correctly, that the dll containing the defined command method has been properly netloaded, and that the database circles are coming out of a DataTable. Error-handling would be needed in the commandmethod for checking the parameters, and it would make sense to enclose the SendCommand method in a try/catch.
This technique really only works when you have data types that can be represented by strings, so it won't cover every situation. It's definitely worth trying to get the COM registered interface working long-term for more robust communication between in/out processes.