.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Custom Commands within Namespace

18 REPLIES 18
Reply
Message 1 of 19
MRiemenCAD
3659 Views, 18 Replies

Custom Commands within Namespace

Initiated a project with the AutoDesk .net templates for VB.net. I've kept the ExtensionApplication loader that's part of the template, however commands that reside within my other classes aren't recognized. The extension is running because it's responding proplerly to events that trigger, however I can't call my custom command names from the command line. Could this be a function of the namespace that the commands are in?

 

Thanks in advance for your help.

 

Namespace IWC

    ' This class is instantiated by AutoCAD once and kept alive for the 
    ' duration of the session. If you don't do any one time initialization 
    ' then you should remove this class.
    Public Class MyPlugin

        Implements IExtensionApplication


        Public Sub Initialize() Implements IExtensionApplication.Initialize

            Dim NewLayer = New IWCLayer
            NewLayer.IWCLayerSysStart()

        End Sub


        Public Sub Terminate() Implements IExtensionApplication.Terminate
            MsgBox("Layer System Terminating", MsgBoxStyle.Critical)
        End Sub
    End Class

End Namespace





Namespace IWC

    ' This class is instantiated by AutoCAD for each document when
    ' a command is called by the user the first time in the context
    ' of a given document. In other words, non static data in this class
    ' is implicitly per-document!

    Public Class IWCLayer

        <CommandMethod("I3")> _
        Public Sub I3()
            If ReturnStandardLayername(3) = False Then
                ChangeCurrentLayer(AddLayer(IWCGetStandardLayer(3)))
            Else
                ChangeCurrentLayer(ReturnStandardLayername(3))
            End If
        End Sub
        Public Sub RegEvent()
            '**IWC**
            'registeres event handlers for start and end commands

            Dim Doc As Document = Application.DocumentManager.MdiActiveDocument
            AddHandler Doc.CommandWillStart, AddressOf IWCLayerSysCheck
            AddHandler Doc.CommandEnded, AddressOf IWCLayerReturn
            AddHandler Doc.CommandCancelled, AddressOf IWCLayerReturn

        End Sub

    End Class


End Namespace

 

18 REPLIES 18
Message 2 of 19
norman.yuan
in reply to: MRiemenCAD

try add this line on top of the class:

 

<Assembly: CommandClass(GetType(IWC.IWCLayer))>

Message 3 of 19

I'm thinking maybe you already have another class with the CommandClass Attribute?

 

The commands should be found and loaded with or without the CommandClass attribute, unless there is already another class decorated as a CommandClass. 

 

You can only have one Class labled as a CommandClass, and if you have one, AutoCAD will look for command methods in that class and that class only.  It won't even look anywhere else.  If you remove the CommandClass attribute, AutoCAD will find any properly declared commands in any Public Class or Public Module.

Dave O.                                                                  Sig-Logos32.png
Message 4 of 19

Thanks for the responses. Makes sence. Can you tell me what a best practice might be for managing commands within a project? Should I be collecting all commands within a single command class or module? Seems a bit too messy to have them interspersed within individual classes.

 

I appreciate your help.

Message 5 of 19


@chiefbraincloud wrote:You can only have one Class labled as a CommandClass, and if you have one, AutoCAD will look for command methods in that class and that class only.  It won't even look anywhere else.  If you remove the CommandClass attribute, AutoCAD will find any properly declared commands in any Public Class or Public Module.


No, You can have any number of classes with the CommandClass attribute applied to them.

Message 6 of 19

Do you have "Imports Autodesk.AutoCAD.Runtime" at the start of your class? This is need for the <CommandMethod("I3")> unless you define it as <Autodesk.AutoCAD.Runtime.CommandMethod("I3")>

 

Otherwise you should check out this post by Kean Walmsley http://through-the-interface.typepad.com/through_the_interface/2006/09/optimizing_the_.html

 

He goes over ExtensionApplication and CommandClass attributes and their use with examples.



If a post provides a fix for your issue, click on "Accept as Solution" to help other users find solutions to problems they might have that are similar to yours.

Andrew Puller
Maitland, NSW, Australia
Windows 10 Enterprise 64bit
Intel core i7 11800 @ 2.30 GHz with 32GB Ram
Civil 3d 2021
Message 7 of 19

This is a Quote from the ObjectARX SDK, AutoCAD Managed Class Reference.

 

"This custom attribute class is used to mark a type as the application's command class. An application may designate one, and only one, type as its command class. AutoCAD looks for an application's command methods on the type that bears this attribute."

 

While I agree with those that think the help files are incomplete, I've not known them to lie to me before.

Dave O.                                                                  Sig-Logos32.png
Message 8 of 19
MRiemenCAD
in reply to: MRiemenCAD

Thanks for your post. I appreciate the link too. I've spent alot of time on Kean's blog but didn't think to look for this issue there. 

 

I've had success with other custom commands running in other applications, it's only when I begin a new project using the AutoDesk supplied template that I'm running into this issue. I've even tried starting anew project, not changing any code and just debugging to see if I can get the AutoDesk generic commands to run but no luck. Odd....

 

I'm working thorugh VB.Net Express so the AutoDesk template is nice as it comes pre-configured with the project files already altered for debugging within AutoCAD.

 

That said, I deffinetly don't know enough about the ExtensionApplication attribute nor the CommandClass so I'll review Kean's information closely. 

 

thanks again for taking the time to reply

Message 9 of 19

Based on Kean's blog, and the comments at the bottom, it appears the SDK DID lie to me.

 

Great, now I want to go back and add CommandClass Attributes to all my code, to optimize the loading.  I do still believe that it is true, that if you have (one or more) Classes decorated with the CommandClass Attribute, that AutoCAD will not look for commands in Classes that are not decorated.

 

I have a bunch of commands defined in Modules, so I may be stuck leaving it the way it is.

Dave O.                                                                  Sig-Logos32.png
Message 10 of 19

Your quote from SDK document is intersting, and I certainly did not notice that before. I though the [assembly: CommandClass(....)] is only for optimize the way how AutoCAD can quickly find custom command. But how to interprete "An appliction" that "can designate one, and only one, type as ..." might open for debate. Since I had never run into an issue of my custom commands not being recognised by AutoCAD due to my code error, I decide to do a quick test.

 

So, I create a project, with 3 classes. Both classes have a command method in it. I did not place the 2 class in separate code file (*.cs, in my case, beause I uses C# more than VB.NET), becase I do not think, separate code files or not in the same assembly does not matter here.

 

Then, I tried:

1. place one [assembly: CommandClass(....)] there, so that only one class is designated as CommandClass;

 

2. place as many [assembly: CommandClass(...)] there, as the classes, as long as there is "Commandmethod" is defined in that class;

 

3. no [assembly: CommandClass(...)] used at all.

 

The result of test:

 

1. Indeed, if you only use one [assembly: CommandClass(...)], then AutoCAD only recognise the command methods iin the specified single commandclass.

 

2. All command methods in the classes specifed in multiple [assembly: CommandClass(...)] can be recognised by AutoCAD.

 

3. All command methods can be recognised by AutoCAD.

 

The conclusion:

 

The quote from SDK only be correct if one uses only one [assembly: CommandClass(...)] line. But, it is more the consuquence of using one [assembly: CommandClass(...)], rather than the requirement that the quote sounds. So, I'd say the SDK quote is wrong.

 

Using [assembly: CommandClass(....)] is more like indexing the classes that have executable custom command, so that AutoCAD do not have to scan loaded assembly for commandmethod from begining to its end. It will only scann specified classes, and one can use multiple [assembly: CommandClass(...)] iin a assembly, should commandmethods are scattered in multiple classes. But If one only use one [asembly;CommandClass(...)], then AutoCAD only scan one classes.

 

If one do not use [assembly: CommandClass(...)], AutoCAD will scan all classes in loaded assemblies and all CommandMethods can be found. This may take AutoCAD longer time to identify a command if there are a lot of assemblies cotaining a lot of classes loaded.

 

In the case of the OP, it might be that he has one [assembly: CommandClass(...)] specified, but later added another class with commandmethod, thus the commandmethod is not recoginised. Add one more [assembly: CommadClass(...)], or remove it entirely would solve his issue.

 

here is the code I did the test:

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

[assembly: CommandClass(typeof(CommandClassTest.MyCommandClass1))]
[assembly: CommandClass(typeof(CommandClassTest.MyCommandClass2))]
[assembly: CommandClass(typeof(CommandClassTest.MyCommandClass3))]

namespace CommandClassTest
{
    public class MyCommandClass1
    {
        [CommandMethod("CmdInClass1")]
        public static void MyCmd()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.
                Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand in MyCommandClass1 executed\n");
        }
    }

    public class MyCommandClass2
    {
        [CommandMethod("CmdInClass2")]
        public static void MyCmd()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.
                Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand in MyCommandClass2 executed\n");
        }
    }

    public class MyCommandClass3
    {
        [CommandMethod("CmdInClass3")]
        public static void MyCmd()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.
                Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand in MyCommandClass3 executed\n");
        }
    }
}

 Try to comment out 1, 2 or al of the [assembly:CommandClass(...)] to see what command is available.

 

 

Message 11 of 19

Yes, The SDK is incorrect.  It is possible that it used to be correct, but based on Kean's post, it has been incorrect since at least ACAD 2010.  (And I was looking at the 2013 SDK, It says the same thing going all the way back to 2009 SDK, at least)

 

I was always aware that if you had (any) CommandClass Attribute in your assembly, then only commands in that (those) class(es) would be found. 

 

Until today, I thought there could be only one, that is the part the help files mislead me on.

 

I still have a question regarding Modules.  I have many commands in Modules.  Most of them in fact.  The only commands I have in classes are commands where an instance of the class needs to be created (like forms, or jigs), and even in some of those cases, I have a short CommandMethod in a Module that handles creating and destroying the instance of the Class.

 

I am relatively certain that I can not apply a CommandClass Attribute to a Module, so I guess that means I am either stuck leaving my code the way it is, or I have to change my Modules to classes, which I don't want to do.

Dave O.                                                                  Sig-Logos32.png
Message 12 of 19

Module in VB.NET is alsoa class, which is equivalent to C# static class. That is, all the methods in Module are static/Shared method.

 

Yes, you can place <Assembly: CommandClass(...)> in Module, just as you place on top of a class. And yes, it is the same as with multiple CommandClass, you also use multiple <Assembly: CommandClass(...)>. However, my test does reveil ONE THING: <Assembly: CommandClass(GetType(NamesapceName.ModuleName))> is required if the commandmethod is in a module, not a class, this is different from C#. So, although I said in VB.NET, Module is also a class, but AutoCAD does not search module for CommandMethod, unless the module is decorated with <Assembly: CommandClass(...)>.

 

Another point one may want to pay attention when place CommandMethod iin VB.NET Module: all methods in module is static/Shared method. While in Acad .NET API, there is different when commandmethod is declared as static/Shared, or not. If one want to take advantage of non-static/Shared commandmethod (i.e. get the CommandClass instantiated per document, instead of against all document, then one cannot use Module. So, in general, I would not recommed to use Module to declare commandmethod, unless you absolutely know that you do not need document-level of commandClass instance. But why impose such self-limitation?

 

Here is the code I tested in VB.NET Module:

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

<Assembly: CommandClass(GetType(CommadClassInVBModuleTest.CommandModule1))> 
<Assembly: CommandClass(GetType(CommadClassInVBModuleTest.CommandModule2))> 

Module CommandModule1

    <CommandMethod("MyCmd1")> _
    Public Sub DoCommand1()
        Dim dwg As Document = Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = dwg.Editor

        ed.WriteMessage(vbCrLf & "Command in CommandModule1" & vbCrLf)

    End Sub

End Module

Module CommandModule2

    <CommandMethod("MyCmd2")> _
    Public Sub DoCommand1()
        Dim dwg As Document = Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = dwg.Editor

        ed.WriteMessage(vbCrLf & "Command in CommandModule2" & vbCrLf)

    End Sub

End Module

 

Message 13 of 19

"but AutoCAD does not search module for CommandMethod, unless the module is decorated with <Assembly: CommandClass(...)>."

 

I'm not sure how you arrived at that conclusion, but I speak from (plenty of) experience, Commands in a Module will be found without the CommandClass Attribute.  I have at least one Module in every assembly I have, and there are no CommandClasss Attributes in any of those assemblies (because I thought you could only have one, or none).

 

My module commands get loaded just fine.  (As I commented earlier in the thread, the Module does have to be declared Public, which is not the default)

 

 

Dave O.                                                                  Sig-Logos32.png
Message 14 of 19

If you run the VB.NET code in my previous reply by commenting out the <Assembly: CommandClass...> on top of the module, AutoCAD will not find the 2 ommand(MyCmd1 and MyCmd2): the usual "Unknown command "xxxx" message is shown at command line.

 

I tested with AutoCAD Map2012, 64bit on Win7.

Message 15 of 19

Those modules are not Public.

 

Add the Public Modifier, comment out your CommandClass attributes and AutoCAD will find the commands.

Dave O.                                                                  Sig-Logos32.png
Message 16 of 19


@chiefbraincloud wrote:

This is a Quote from the ObjectARX SDK, AutoCAD Managed Class Reference.

 

"This custom attribute class is used to mark a type as the application's command class. An application may designate one, and only one, type as its command class. AutoCAD looks for an application's command methods on the type that bears this attribute."

 

While I agree with those that think the help files are incomplete, I've not known them to lie to me before.


 

The help files are wrong, and please don't make the mistake of giving them the same legitimacy as one might give holy books. I've lost count of how many errata I've found (and been bitten by) in the managed API docs, not to mention the sample applications, labs, and so forth.

 

It also might help if you knew that if that was the intention (allow only one CommandClassAttribute per assembly), then the designer would have specified the AllowMultiple=false property in the [AttributeUsage] attribute applied to the CommandClassAttribute's definition (from Reflector):

 

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true, Inherited=false)]
public sealed class CommandClassAttribute : Attribute
{
   // Fields
   private Type type_;

   // Methods
   public CommandClassAttribute(Type name);

   // Properties
   public Type Type { get; }
}

 

 

 

 

Message 17 of 19
thoman999
in reply to: chiefbraincloud

I know this is an old thread but I'll post anyway just for searchers.

 

In working with Map3D 2013 the <CommandMethod ...> directive is not covered by the acmgd.dll and acdbmgd.dll references. I also had to load accoremgd.dll

 

Just an observation

 

tom

Message 18 of 19
chiefbraincloud
in reply to: thoman999

Yes, that is new to the 2013 API.

Dave O.                                                                  Sig-Logos32.png
Message 19 of 19
jeff
in reply to: chiefbraincloud

If you look at code in link from reflector you see how Autocad loads your assembly and explains results.

--Checks is assembly contains CommandClassAttribute if it does it will check only the classes defined in each attribute and if not will examine each type in the assembly

 

http://www.theswamp.org/index.php?topic=44237.msg494891#msg494891

You can also find your answers @ TheSwamp

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost