Constructor being called twice(!!) when an AutoCAD.Net API is being called

Constructor being called twice(!!) when an AutoCAD.Net API is being called

soonhui
Advisor Advisor
724 Views
5 Replies
Message 1 of 6

Constructor being called twice(!!) when an AutoCAD.Net API is being called

soonhui
Advisor
Advisor

I'm pretty sure this is a bug in AutoCAD 2025. Not sure the same problem was there in AutoCAD 2024 and below though.

 

Here's my plugin csproject in SDK style:

 

 

 

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<TargetFramework>net8.0-windows</TargetFramework>
		<!-- <ImplicitUsings>enable</ImplicitUsings> -->
		<!-- <Nullable>enable</Nullable> -->
		<UseWPF>true</UseWPF>
		<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
		<TargetFramework>net8.0-windows</TargetFramework>
		<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
		<EnableDefaultItems>true</EnableDefaultItems>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="AutoCAD.NET"
		                  Version="25.0.1"/>
	</ItemGroup>
</Project>

 

 

 

And here's the content of the only cs file in the folder

 

 

 

using System.Windows;
using Autodesk.AutoCAD.Runtime;
using DummDLL;
[assembly: ExtensionApplication(typeof(HookEntry))]
[assembly: CommandClass(typeof(HookEntry))]
namespace DummDLL
{

    public class HookEntry : IExtensionApplication
    {
        public HookEntry()
        {
            MessageBox.Show($"Constructor entered,{this.GetHashCode()}");
        }

        public void Initialize()
        {
            MessageBox.Show($"Initialize method entered,{this.GetHashCode()}");
        }

        public void Terminate()
        {
           
        }


        [CommandMethod(nameof(RunCommand2))]
        public void RunCommand2()
        {
            MessageBox.Show($"{nameof(RunCommand2)},{this.GetHashCode()}");

        }

        [CommandMethod(nameof(RunCommand))]
        public void RunCommand()
        {
            MessageBox.Show($"{nameof(RunCommand)},{this.GetHashCode()}");

        }
    }
}

 

 

 

Now try to netload the DLL. You will notice that the calling sequence for the method is as thus:

 

  1. Constructor 
  2. Initialize

Which is correct.

 

But now, try to call a command, such as RunCommand, the calling sequence is

  1. Constructor ( again! ). Which indicates that a different instance of IExtensionApplication is being called. This is a bug, I don't expect you to initialize a new plugin
  2. RunCommand

And if you call another command, whether RunCommand and RunCommand2, then only now, only that command will be called.

 

That's the problem. AutoCAD calls 2 instances of HookEntry (IExtensionApplication ), this is already a bug. And on the second instance where it really matters, the Initialize method isn't called at all. Such a scrambling of all the calling sequences will only break our plugin, as we count on that our HookEntry is called only once, and the Initialize method is being called. 

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Accepted solutions (1)
725 Views
5 Replies
Replies (5)
Message 2 of 6

1742647821
Participant
Participant

In my opinion, this is as expected, in general.This is a very normal feature of c#. If a class is instantiated multiple times, the constructor will be executed multiple times.

 

CommandMethod is typically added to a static method of a static class, and if you must write instance, each document will instantiate a class object the first time the class is used by the document, just like a scope.

 

If you want the constructor to be executed only once, you should use static construction by removing public from the front of the constructor and adding static

 

0 Likes
Message 3 of 6

soonhui
Advisor
Advisor

@1742647821 , what you said is correct but you completely don't understand what is going on here. 

 

The real issue is that why should the class that inherits IExtensionApplication be instantiated multiple times at all?

 

And more importantly, why is it that in the second instantiation-- that's the instantiation that really matters because it will be used by subsequent CommandMethod, and not the first one-- doesn't call the Initialize method, which is what IExtensionApplication interface mandates?

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Message 4 of 6

norman.yuan
Mentor
Mentor

The result of command class's constructor being called multiple times is due to the command method being NON-STATC.

 

One must realize that in our code, the constructor of a CommandClass (if we do write one) is never explicitly used in our own code. AutoCAD .NET API runtime decide when/how to instantiate CommandClass (thus calling its constructor). Here is the quote from According to Acad .NET API documentation:

 

[quote]
For an instance command method, the method's enclosing type is instantiated separately for each open document. This means that each document gets a private copy of the command's instance data. Thus there is no danger of overwriting document-specific data when the user switches documents. If an instance method needs to share data globally, it can do so by declaring static or Shared member variables.
For a static command method, the managed wrapper runtime module does not need to instantiate the enclosing type. A single copy of the method's data is used, regardless of the document context. Static commands normally do not use per-document data and do not require special consideration for MDI mode.
[/quote]

 

While IExtensionApplication.Initilze() will only be call once per loaded DLL, since it is a "must-run" method call, AutoCAD must instantiate the class where Initilize() is located. Of course, the IExtenstionApplication does not have to be a CommandClass. So, you can verify it by placing your IExentionApplication is a separate class with its own constructor; you would see, the Initialize() and CommandMethod in the CommandClass will call their own constructors.

 

However, although I would not go so far to say having custom constructors in CommandClass is a "bad" practice, I do not use custom constructors in CommandClass/IExtensionApplication implemented class. I'd rather keep the CommandClasses clean so that they only do the work they meant to do: start a command as the beginning point of a CAD application.  All working data should be encapsulated in other classes that are used inside the CommandMethods. 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 5 of 6

soonhui
Advisor
Advisor
Accepted solution

@norman.yuan , I think I understand now.

  1. Command Class will be instantiated on per document basis. One document, one Command Class instantiation
  2. IExtensionApplication is instantiated on per plugin basis. It is instantiated only once for the entire plugin.
  3. In the case when the IExtensionApplication and Command class are of the same class, then it will be instantiated (N+1) times, where N is the number of opened document. 
##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Message 6 of 6

norman.yuan
Mentor
Mentor

About your point 3: the CommandMethod being static or non-static matters: only non-static method call would result in instantiating of the class (i.e. constructor being called) of the current document, if the class has not been instantiated with this document. Static CommandMethod only result in the class instantiating in Application level once. Also remember a class could have both static and non-static CommandMethods.

 

That is why I said in previous reply: better not to create a custom constructor with code doing some complicated things. It would lead to confusion, difficulties for code maintenance. 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes