Author Topic: Creating Dictionary<AcRtm.RXClass, Type>  (Read 7821 times)

0 Members and 1 Guest are viewing this topic.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Creating Dictionary<AcRtm.RXClass, Type>
« on: August 17, 2012, 02:38:57 AM »
Hi all.

Data:
AutoCAD 2009 SP3 Enu x86,
Windows XP SP3 x86
.Net Framework 3.5 SP1

I want to create Dictionary<AcRtm.RXClass, Type> for more quickly to define managed types for RXClasses. I wrote it code:
Code: [Select]
Dictionary<AcRtm.RXClass, Type> mngTypeDict = new Dictionary<AcRtm.RXClass, Type>();

//Names of RXClasses, which do not have manage wrapper.
StringBuilder sb = new StringBuilder();

foreach (DictionaryEntry item in AcRtm.SystemObjects.ClassDictionary) {
AcRtm.RXClass rx;
Type type;
AcRtm.RXObject obj;

try {
rx = (AcRtm.RXClass)item.Value;
obj = rx.Create();

if (obj != null) {
type = obj.GetType();
mngTypeDict.Add(rx, type);
}
else
sb.AppendLine(rx.Name);
}
catch (Exception ex) {
//oops..
}
}

But I get Fatall Error (try/catch doesn't help even):
Quote
INTERNAL ERROR:  !dbAnnotationScaleCollectioni.cpp@37: eNullObjectPointer

Regards

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #1 on: August 17, 2012, 07:29:21 AM »

What line of the code is execution crashing?
Revit 2019, AMEP 2019 64bit Win 10

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #2 on: August 17, 2012, 07:43:28 AM »
obj = rx.Create();

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #3 on: August 17, 2012, 10:37:22 AM »
I apologize if AcRtm is an AutoCAD class but I cannot find anything documenting it. Is this a custom class?

Edit:
Nevermind I see from another thread that you're using it as an alias for Autodesk.AutoCAD.Runtime.

I'd try
Code: [Select]
var rx = item.value as AcRtm.RXClass
if (rx != null)
  obj = rx.Create();

« Last Edit: August 17, 2012, 10:45:47 AM by MexicanCustard »
Revit 2019, AMEP 2019 64bit Win 10

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #4 on: August 17, 2012, 10:46:15 AM »
I apologize if AcRtm is an AutoCAD class but I cannot find anything documenting it. Is this a custom class?
No, it is namespace: using AcRtm = Autodesk.AutoCAD.Runtime;

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #5 on: August 20, 2012, 07:56:45 AM »
Autodesk.AutoCAD.Runtime is the namespace

AcRtm is an alias you're using to represent that namespace.
Revit 2019, AMEP 2019 64bit Win 10

fixo

  • Guest
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #6 on: August 20, 2012, 08:37:31 AM »
Perhaps
Code: [Select]
obj = rx.Create(IntPtr.Zero);Or I'm missing something above, so, sorry

~'J'~

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #7 on: August 20, 2012, 12:30:34 PM »
I didn't see it in the documentation but with Object Browser

Autodesk.AutoCAD.Runtime.DisposableWrapper.Create(System.Type, System.IntPtr, bool)
Autodesk.AutoCAD.Runtime.RXObject.Create(System.IntPtr, bool)
« Last Edit: August 20, 2012, 12:34:19 PM by MexicanCustard »
Revit 2019, AMEP 2019 64bit Win 10

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #8 on: August 20, 2012, 08:29:00 PM »
I am just guessing but you might need to filiter for objects because you will probably get a bunch of Imp****** objects.
 
Not sure what you are doing but you looks like you would still need iterate through dictionary and use a property of RxClasss to be able compare.
 
Some untested code?
Code - C#: [Select]
  1.  
  2.          [CommandMethod("RxclassTypes")]
  3.         public void RxclassTypes()
  4.         {
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;
  8.             Dictionary<RXClass, Type> dic = new Dictionary<RXClass, Type>();
  9.                 RXClass rxEntity = RXClass.GetClass(typeof(Entity));
  10.                 foreach (DictionaryEntry e in SystemObjects.ClassDictionary)
  11.                 {
  12.                     RXClass rxclass = e.Value as RXClass;
  13.                     if (rxclass.IsDerivedFrom(rxEntity))
  14.                     {                                      
  15.                         Type type = rxclass.GetRuntimeType();                    
  16.                         dic.Add(rxclass, type);
  17.                     }
  18.                 }
  19.        
  20.         }
  21.  

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #9 on: August 22, 2012, 03:48:12 AM »
Autodesk.AutoCAD.Runtime is the namespace

AcRtm is an alias you're using to represent that namespace.
Yes, I wrote it in my last message.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #10 on: August 22, 2012, 04:27:38 AM »
I didn't see it in the documentation but with Object Browser

Code - C#: [Select]
  1. Autodesk.AutoCAD.Runtime.DisposableWrapper.Create(System.Type, System.IntPtr, bool)
  2. Autodesk.AutoCAD.Runtime.RXObject.Create(System.IntPtr, bool)
It is very interesting. But AutoCAD 2009 .Net API has
Code - C#: [Select]
  1. Autodesk.AutoCAD.Runtime.DisposableWrapper.Create(System.Type, System.IntPtr, bool)
only. :(

I tried to get wrapper:
Code - C#: [Select]
  1. Dictionary<RXClass, Type> mngTypeDict = new Dictionary<RXClass, Type>();
  2.  
  3. foreach (DictionaryEntry item in SystemObjects.ClassDictionary) {
  4.         RXClass rx;
  5.         Type type;
  6.         try {
  7.                 rx = (RXClass)item.Value;
  8.                 IntPtr ptr = rx.UnmanagedObject;               
  9.                 DisposableWrapper wrap = Autodesk.AutoCAD.Runtime.DisposableWrapper.Create(typeof(Object), ptr, false);
  10.                 type = wrap.GetType();                                 
  11.         }
  12.         catch (Exception ex) {
  13.                 //oops..
  14.         }
  15. }
  16.  
but I got error:
Quote
Constructor on type 'System.Object' not found.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #11 on: August 22, 2012, 04:35:03 AM »
Some untested code?
Code - C#: [Select]
  1.  
  2. ...                                
  3. Type type = rxclass.GetRuntimeType();                    
  4. ...
  5.  
Sorry, but AutoCAD 2009 .Net API has not GetRuntimeType method for RXClass class. :(

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #12 on: August 22, 2012, 04:56:00 AM »
Am I inventing a bicycle, maybe? I need to get wrapper type for each RXClass in Database. Is exists a simple and fast (for speed) solution to do it?
« Last Edit: August 22, 2012, 05:03:50 AM by Andrey »

TheMaster

  • Guest
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #13 on: August 22, 2012, 07:30:37 AM »
Am I inventing a bicycle, maybe? I need to get wrapper type for each RXClass in Database. Is exists a simple and fast (for speed) solution to do it?

Before AutoCAD 2013, the only way was to create an instance of the wrapper class, and even that wasn't foolproof if the native ARX that provides it is not available (then an ImpDBObject wrapper is created).

In AutoCAD 2013, RXClass has a new method that returns the managed wrapper type.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #14 on: August 22, 2012, 12:03:24 PM »
Before AutoCAD 2013, the only way was to create an instance of the wrapper class, and even that wasn't foolproof if the native ARX that provides it is not available (then an ImpDBObject wrapper is created).

In AutoCAD 2013, RXClass has a new method that returns the managed wrapper type.
Thank you for answer.

kaefer

  • Guest
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #15 on: August 22, 2012, 12:07:41 PM »
In AutoCAD 2013, RXClass has a new method that returns the managed wrapper type.

Even in 2013 there's one RXClass which doesn't allow calling GetRuntimeType on it: AcRxObject. It seems to bomb in a nested call to native_GetFactoryBase(AcRxClass* ).

@Andrey: If you still insist on doing something seemingly dangerous, what would happen when you skip the known troublemakers, that would be AcDbAnnotationScaleCollection and AcDbAnnotationScaleCollectionIterator?

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #16 on: August 22, 2012, 12:33:06 PM »
@Andrey: If you still insist on doing something seemingly dangerous, what would happen when you skip the known troublemakers, that would be AcDbAnnotationScaleCollection and AcDbAnnotationScaleCollectionIterator?
I do not know. I wanted to avoid exception processing ("try/catch" code block). I Hoped, that it's problem has a solution. I still not use it code in the my applications. I write Extended AutoCAD .Net API Libraries, which I will to use in my applications, and it code must was be there.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #17 on: August 22, 2012, 01:01:47 PM »
In AutoCAD 2013, RXClass has a new method that returns the managed wrapper type.

Even in 2013 there's one RXClass which doesn't allow calling GetRuntimeType on it: AcRxObject. It seems to bomb in a nested call to native_GetFactoryBase(AcRxClass* ).

@Andrey: If you still insist on doing something seemingly dangerous, what would happen when you skip the known troublemakers, that would be AcDbAnnotationScaleCollection and AcDbAnnotationScaleCollectionIterator?

As kaefer mentioned skipping the troublemakers
 
Using RXClass.Create()
Two methods that created attached .txt files and only differ by filter and file name
Code - C#: [Select]
  1.        [CommandMethod("RxclassTypesDbo")]
  2.         public void RxclassTypesDbo()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.             Dictionary<RXClass, Type> dic = new Dictionary<RXClass, Type>();
  8.                 RXClass rxEntity = RXClass.GetClass(typeof(DBObject));
  9.                 foreach (DictionaryEntry e in SystemObjects.ClassDictionary)
  10.                 {
  11.                     RXClass rxclass = e.Value as RXClass;
  12.                     if (rxclass.IsDerivedFrom(rxEntity))
  13.                     {
  14.                         RXObject rxo = rxclass.Create();
  15.                         if (rxo != null)
  16.                         {
  17.                             dic.Add(rxclass, rxo.GetType());
  18.                         }
  19.  
  20.                     }
  21.                 }
  22.                 using (StreamWriter tw = new StreamWriter(@"C:\Testing\rxDbotypes.txt"))
  23.                 {
  24.                     foreach (var de in dic)
  25.                     {
  26.                         tw.WriteLine("{0,-45:D} -------- {1,-45:D}", de.Key.Name, de.Value.Name);
  27.                     }
  28.                 }
  29.        
  30.         }
  31.  
  32.         [CommandMethod("RxclassTypesEnt")]
  33.         public void RxclassTypesEnt()
  34.         {
  35.             Document doc = Application.DocumentManager.MdiActiveDocument;
  36.             Database db = doc.Database;
  37.             Editor ed = doc.Editor;
  38.             Dictionary<RXClass, Type> dic = new Dictionary<RXClass, Type>();
  39.             RXClass rxEntity = RXClass.GetClass(typeof(Entity));
  40.             foreach (DictionaryEntry e in SystemObjects.ClassDictionary)
  41.             {
  42.                 RXClass rxclass = e.Value as RXClass;
  43.                 if (rxclass.IsDerivedFrom(rxEntity))
  44.                 {
  45.                     RXObject rxo = rxclass.Create();
  46.                     if (rxo != null)
  47.                     {
  48.                         dic.Add(rxclass, rxo.GetType());
  49.                     }
  50.                    
  51.                    
  52.                 }
  53.             }
  54.             using (StreamWriter tw = new StreamWriter(@"C:\Testing\rxEnttypes.txt"))
  55.             {
  56.                 foreach (var de in dic)
  57.                 {
  58.                     tw.WriteLine("{0,-45:D} -------- {1,-45:D}", de.Key.Name, de.Value.Name);
  59.                 }
  60.             }
  61.         }
  62.  

Results are very Impish
Quote

 AbsToolsDbFabrication                         -------- ImpCurve                                     
AbsToolsDbHanger                              -------- ImpCurve                                     
AcAecCamera                                   -------- ImpEntity                                   
AcDb2dPolyline                                -------- Polyline2d                                   
AcDb2dVertex                                  -------- Vertex2d                                     
AcDb2LineAngularDimension                     -------- LineAngularDimension2                       
AcDb3dPolyline                                -------- Polyline3d                                   
AcDb3dPolylineVertex                          -------- PolylineVertex3d                             
AcDb3dSolid                                   -------- Solid3d                                     
AcDb3PointAngularDimension                    -------- Point3AngularDimension               
...........       

rxDbotypes.txt created from DBObject filter
rxEnttypes.txt created from Entity filter
 
 

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #18 on: August 23, 2012, 09:31:08 AM »
I rewrote my code and supplied this with detailed comments. In the same place, in comments, I specified the questions. Respond me on them, please.
Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Collections;
  6. using acad = Autodesk.AutoCAD.ApplicationServices.Application;
  7. using AcApp = Autodesk.AutoCAD.ApplicationServices;
  8. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  9. using AcEd = Autodesk.AutoCAD.EditorInput;
  10. using AcRtm = Autodesk.AutoCAD.Runtime;
  11.  
  12. [assembly: AcRtm.CommandClass(typeof(Testing.Class1))]
  13.  
  14. namespace Testing {
  15.  
  16.         public class Class1 {
  17.  
  18.                 //In this method code I try to create dictionary, which for every RXClass contains according it wrapper type.
  19.                 //
  20.                 //The error occurs after a while after cmd was finished:
  21.                 //FATAL ERROR:  Unhandled Access Violation Reading 0x0008 Exception at 63972160h
  22.                 //
  23.                 //QUESTION: Why I get it error?
  24.                 [AcRtm.CommandMethod("cmd")]
  25.                 public void Cmd() {
  26.                         AcApp.Document doc = acad.DocumentManager.MdiActiveDocument;
  27.                         AcDb.Database db = doc.Database;
  28.                         AcEd.Editor ed = doc.Editor;
  29.  
  30.                         //target dictionary
  31.                         Dictionary<AcRtm.RXClass, Type> mngTypeDict = new Dictionary<AcRtm.RXClass, Type>();
  32.  
  33.                         //errors log
  34.                         StringBuilder sb = new StringBuilder();
  35.  
  36.                         //It is necessary to exclude some types from processing, differently we will receive the errors:
  37.                         //Error message:
  38.                         //INTERNAL ERROR:  !dbAnnotationScaleCollectioni.cpp@546: eNullEntityPointer
  39.                         //or
  40.                         //INTERNAL ERROR:  !dbAnnotationScaleCollectioni.cpp@37: eNullObjectPointer
  41.                         //
  42.                         //QUESTION: Why I get it errors?
  43.                         String[] types = new String[] { "AcDbAnnotationScaleCollection", "AcDbAnnotationScaleCollectionIterator" };
  44.  
  45.                         foreach (DictionaryEntry item in AcRtm.SystemObjects.ClassDictionary) {
  46.                                 AcRtm.RXClass rxClass = null;
  47.                                 Type type = null;
  48.                                 try {
  49.                                         if (item.Value != null) {
  50.                                                 rxClass = (AcRtm.RXClass)item.Value;
  51.                                                 if (!types.Contains(rxClass.Name)) {
  52.                                                         //I use such code:
  53.                                                         AcRtm.RXObject rxObj = rxClass.Create();
  54.                                                         type = rxObj.GetType();
  55.  
  56.                                                         //But I can't use such code, because AutoCAD right there will finish the operation without the error message:
  57.                                                         //using (AcRtm.RXObject rxObj = rxClass.Create()) {
  58.                                                         //    type = rxObj.GetType();
  59.                                                         //}
  60.                                                         //
  61.                                                         //QUESTION: Why I get it error?
  62.                                                 }
  63.                                         }
  64.                                         else {
  65.                                                 sb.AppendLine(String.Format("{0} key value is null.", item.Key));
  66.                                         }
  67.                                 }
  68.                                 catch (Exception ex) {
  69.                                         if (rxClass != null)
  70.                                                 sb.AppendLine(String.Format("Can't to create instance of {0}. Error: {1}", rxClass.Name, ex.Message));
  71.                                 }
  72.                         }
  73.                 }
  74.  
  75.                 //I try to find instances of "AcDbAnnotationScaleCollection" or "AcDbAnnotationScaleCollectionIterator"
  76.                 //
  77.                 //QUESTION: Why I can't find it?
  78.                 [AcRtm.CommandMethod("cmd2")]
  79.                 public void Cmd2() {
  80.                         AcApp.Document doc = acad.DocumentManager.MdiActiveDocument;
  81.                         AcDb.Database db = doc.Database;
  82.                         AcEd.Editor ed = doc.Editor;
  83.                         //I use such array, like in Cmd method:
  84.                         String[] types = new String[] { "AcDbAnnotationScaleCollection", "AcDbAnnotationScaleCollectionIterator" };
  85.  
  86.                         using (AcDb.Transaction tr = db.TransactionManager.StartTransaction()) {
  87.                                 //I execute iteration on all database objects:
  88.                                 for (long i = db.BlockTableId.Handle.Value; i < db.Handseed.Value; i++) {
  89.                                         AcDb.ObjectId id = AcDb.ObjectId.Null;
  90.                                         AcDb.DBObject dbObj = null;
  91.                                         Type type = null;
  92.                                         AcDb.Handle h = new AcDb.Handle(i);
  93.                                         bool result = db.TryGetObjectId(h, out id);
  94.  
  95.                                         //But I can't find instances of "AcDbAnnotationScaleCollection" or "AcDbAnnotationScaleCollectionIterator":
  96.                                         //the condition is never executed.
  97.                                         if (result && id.IsValid && !id.IsNull && types.Contains(id.ObjectClass.Name)) {
  98.                                                 dbObj = tr.GetObject(id, AcDb.OpenMode.ForRead);
  99.                                                 type = dbObj.GetType();
  100.                                         }
  101.                                 }
  102.                                 tr.Abort();
  103.                         }
  104.                 }
  105.         }
  106. }
  107.  
« Last Edit: August 23, 2012, 09:53:14 AM by Andrey »

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Creating Dictionary<AcRtm.RXClass, Type>
« Reply #19 on: August 23, 2012, 09:47:43 AM »
rxDbotypes.txt created from DBObject filter
rxEnttypes.txt created from Entity filter
Yes, this is an interesting decision, thanks. But if there is a filter, then it means, what are eliminated some types and consequently we receive not complete result.
« Last Edit: August 23, 2012, 09:51:47 AM by Andrey »