Creating a Sample AutoCAD Plugin with .NET 8.0 and C++/CLI for AutoCAD 2025

By Madhukar Moogala

In this article, will walk through the development of a simple AutoCAD plugin using C++/CLI. The plugin will add a feature to draw circles dynamically, where users can specify the radius and the plugin will generate a random color for each circle.

We will break the plugin down into three major parts:

  1. AutoCAD Database Helper Class
  2. UI Form Implementation
  3. ObjectARX Entry Point

Part 1: AutoCAD Database Helper Class

In AutoCAD, entities such as circles, lines, and other objects are stored in the AutoCAD database. The AcDbHelper class in our plugin facilitates the creation and manipulation of AutoCAD entities.

Smart Pointer for AutoCAD Database Objects

We start by creating a unique_db_ptr template class to manage AutoCAD objects with a smart pointer. This ensures that AutoCAD objects are correctly cleaned up after use.


template  struct unique_db_ptr : public std::unique_ptr
{
unique_db_ptr(T* t) : std::unique_ptr(t, closeOrDeleteDbObj) { }
static unique_db_ptr create()
{
T* newObj = new T();
return unique_db_ptr(newObj);
}
// Helper function for smart pointer cleanup
static void closeOrDeleteDbObj(AcDbObject* pObj)
{
if (pObj->objectId().isNull())
delete pObj;
else
pObj->close();
}
};

Adding Entities to the Database

We also define a method to add entities like circles to AutoCAD’s model space, ensuring they are correctly appended
to the database.


static bool addToDb(AcDbEntity* pEnt, AcDbDatabase* pDb = nullptr)
{
if (!pDb)
pDb = acdbHostApplicationServices()->workingDatabase();
unique_db_ptr ent(pEnt);
AcDbBlockTable* pBt;
if (Acad::eOk != pDb->getBlockTable(pBt, AcDb::kForRead))
return false;
unique_db_ptr bt(pBt);
AcDbBlockTableRecord* pMs;
if (Acad::eOk != pBt->getAt(ACDB_MODEL_SPACE, pMs, AcDb::kForWrite))
return false;
return Acad::eOk == unique_db_ptr(pMs)->appendAcDbEntity(ent.get());
}

Creating and Adding Circles

The createCircle method creates a circle with a specified radius and color index, then adds it to the
database:


static bool createCircle(const AcGePoint3d& center, double radius, int colorIndex = 1)
{
auto circlePtr = unique_db_ptr::create();
if (!circlePtr)
return false;
AcDbCircle* circle = circlePtr.get();
circle->setDatabaseDefaults();
circle->setRadius(radius);
circle->setColorIndex(colorIndex);
circle->setCenter(center);
return addToDb(circle);
}

Part 2: UI Form Implementation

Now, let’s move on to creating the user interface (UI) that interacts with the AutoCAD database. We’ll
use Windows Forms in C++/CLI for this purpose.

MainForm Class

The MainForm class represents the UI, containing a button to draw a circle and a numeric input for the
circle radius. It uses a task-based asynchronous method to perform the drawing operation on the main AutoCAD thread.


public ref class MainForm : public Form
{
private:
Button^ drawButton;
NumericUpDown^ radiusInput;
Label^ radiusLabel;
void InitializeComponent()
{
//adding controls to the form and initialising properties
}
Task^ DrawCircleAsync(System::Object^ data)
{
//draw the circle
}
void DrawButton_Click(System::Object^ sender, System::EventArgs^ e)
{
// Handle click event
auto dm = Autodesk::AutoCAD::ApplicationServices::Core::Application::DocumentManager;
// Create the delegate with the correct syntax
auto callback = gcnew Func(this, &MainForm::DrawCircleAsync);
// Execute the callback in the command context
auto task = dm->ExecuteInCommandContextAsync(callback, nullptr);
task->GetResult();
// Enable the button
drawButton->Enabled = true;
// Set focus to the drawing area and zoom extents
AcadUtils::Utils::SetFocusToDwgView();
AcadUtils::Utils::CancelAndRunCmds("_.zoomn_extentsn");
}
public:
MainForm()
{
InitializeComponent();
}
};

ExecuteInCommandContextAsync Method

In this code, the ExecuteInCommandContextAsync method is used to execute a callback (in this case, the
DrawCircleAsync method) within AutoCAD’s command context.
The primary reason for using this API is to
ensure that any interactions with AutoCAD, especially those that modify the drawing or perform operations on the
AutoCAD database, are executed on the correct thread, which is the AutoCAD main thread.

Why Use ExecuteInCommandContextAsync?

AutoCAD, being a single-threaded application, has strict rules about how commands and modifications to the AutoCAD
database should be performed. Interacting with AutoCAD from another thread, such as a UI thread, can cause problems
because it bypasses AutoCAD’s synchronization mechanisms, leading to potential crashes, invalid operations, or
unexpected behavior.

SynchronizationContext Issue

When you display a WinForm dialog (like MainForm in your code), it restores the ‘previous’
SynchronizationContext, which in this case is the default context. This default context attempts to
execute continuations using the thread pool, not the main AutoCAD thread. Since AutoCAD requires that commands (such
as modifying the database or interacting with the drawing) be run on its main thread, executing on a background
thread (via the thread pool) can cause synchronization issues.

AutoCAD doesn’t like this because it expects all UI operations and database modifications to occur on the main
AutoCAD thread. If you try to execute these operations on a different thread (e.g., using the thread pool),
AutoCAD’s internal threading model will not handle it correctly.

How ExecuteInCommandContextAsync Solves This

By using ExecuteInCommandContextAsync, the callback (i.e., the DrawCircleAsync method) is
explicitly executed within AutoCAD’s command context. This method ensures that the operation is correctly scheduled
on the AutoCAD thread, which means:

  1. Correct Threading: It guarantees that the AutoCAD API calls are made on the main AutoCAD
    thread, which is crucial for thread safety.
  2. Synchronization Context: It sets up the correct synchronization context for the operation, so
    any continuation (like UI updates or database operations) that happens after this method call will respect
    AutoCAD’s threading model and ensure that UI updates (like enabling buttons) are done on the UI thread without
    causing conflicts.
  3. Asynchronous Execution: It allows the asynchronous execution of AutoCAD commands without
    blocking the UI thread or causing AutoCAD to freeze while waiting for the operation to complete. The
    GetResult() method ensures that the UI thread waits for the task to finish before proceeding.

Part 3: ObjectARX Entry Point

The CArxNetCoreApp class represents the entry point of our AutoCAD plugin. It registers the
application and launches the UI dialog.


class CArxNetCoreApp : public AcRxArxApp
{
public:
virtual AcRx::AppRetCode On_kInitAppMsg(void* pkt) {
return AcRxArxApp::On_kInitAppMsg(pkt); }
virtual AcRx::AppRetCode On_kUnloadAppMsg(void* pkt) {
return AcRxArxApp::On_kUnloadAppMsg(pkt); }
virtual void RegisterServerComponents() {}
static void MADGUIToolLaunch()
{
try
{
auto form = gcnew UIForms::MainForm();
Autodesk::AutoCAD::ApplicationServices::Application::ShowModelessDialog(form);
}
catch (System::Exception^ ex)
{
acutPrintf(L"nException occurred: %s", ex->Message);
}
}
};

Conclusion

This plugin demonstrates how to integrate AutoCAD with C++/CLI, offering a simple yet powerful tool to interact
with AutoCAD’s database, create entities, and provide a user-friendly interface for drawing circles. The use of
smart pointers, task-based asynchronous methods, and Windows Forms for UI design highlights the flexibility and
power of combining C++/CLI with AutoCAD’s ObjectARX SDK.

By following the steps outlined in this tutorial, you can build and expand upon this basic plugin to add more
features and functionality to AutoCAD.


GitHub Logo
View on GitHub


Comments

3 responses to “Creating a Sample AutoCAD Plugin with .NET 8.0 and C++/CLI for AutoCAD 2025”

  1. I am typically the one to blog, and we truly value your posts. This article has piqued my curiosity about the topic. Please allow me to bookmark your blog and continue to check the selection details.

  2. Slope brings a sense of conquest, making players always want to try again to get a higher score.

  3. Kerry Brown Avatar
    Kerry Brown

    @Madhukar Moogala
    Thank you for these types of posts.
    Regards,

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading