Author Topic: Layer and Block SymbolTable Iteration  (Read 8921 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Layer and Block SymbolTable Iteration
« on: November 22, 2005, 04:55:12 AM »
Any comments ? ?

The using statements are from my standard template, whatever is not actually used isn't included in the build, so it's only visually an issue when the region is 'open'.

Code: [Select]
// Iterator test for Layer and Block SymbolTables
// AC2006 from MSVC#2005
// by kwb 2005Nov22

#region using declarations
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;

using System.Text;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;
using System.Text.RegularExpressions;

//// COM Interop References
//// AutoCAD 2006 Type Library
using Autodesk.AutoCAD.Interop;

//// AXDBLib AutoCAD/ObjectDBX Common 16.0 Type Library
using Autodesk.AutoCAD.Interop.Common;

//// Assembly acdbmgd .. ObjectDBX.NET Managed Wrapper
//// Assembly acmgd .. Autocad.NET Managed Wrapper
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Colors;

// Shortcuts to the managed classes .. using the ObjectARX class prefixes
using AcAp = Autodesk.AutoCAD.ApplicationServices;
using AcCm = Autodesk.AutoCAD.Colors;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using AcEd = Autodesk.AutoCAD.EditorInput;
using AcGe = Autodesk.AutoCAD.Geometry;
using AcGi = Autodesk.AutoCAD.GraphicsInterface;

using AcLy = Autodesk.AutoCAD.LayerManager;
using AcPl = Autodesk.AutoCAD.PlottingServices;
using AcRx = Autodesk.AutoCAD.Runtime;
using AcUi = Autodesk.AutoCAD.Windows;
//
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
#endregion




public class Class1120
{
    [AcRx.CommandMethod("Test1120")]
    public void TestCommand1120()
    {
        Database db = HostApplicationServices.WorkingDatabase;
        Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
        using (AcDb.TransactionManager tm = db.TransactionManager)
        using (Transaction tr = tm.StartTransaction())
        {
            LayerTable ltbl = (LayerTable)tm.GetObject(db.LayerTableId, OpenMode.ForRead, false);
            IEnumerator ltblItem = ltbl.GetEnumerator();
            while (ltblItem.MoveNext())
            {
                ObjectId id = (ObjectId)ltblItem.Current;
                using (LayerTableRecord rec = (LayerTableRecord)tm.GetObject(id, OpenMode.ForRead))
                {
                    ed.WriteMessage(string.Format("\nLayer Name : {0}", rec.Name));                   
                }
            }

            BlockTable btbl = (BlockTable)tm.GetObject(db.BlockTableId, OpenMode.ForRead, false);
            IEnumerator btblItem = btbl.GetEnumerator();
            while (btblItem.MoveNext())
            {
                ObjectId id = (ObjectId)btblItem.Current;
                using (BlockTableRecord rec = (BlockTableRecord)tm.GetObject(id, OpenMode.ForRead))
                {
                    // string blokName = rec.Name;
                    // if ((blokName.Contains("*D") || blokName.Contains("*U") ) == false)

                    if ((rec.Name.StartsWith("*")) == false)
                    {
                        ed.WriteMessage(string.Format("\nBlock Name : {0}", rec.Name));
                    }
                }
            }
            tr.Commit();
        }
    }
}
« Last Edit: November 22, 2005, 05:48:51 AM by Kerry Brown »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Layer and Block TSymbol Table Iteration
« Reply #1 on: November 22, 2005, 05:15:22 AM »
Only an observation which I've been meaning to explore myself, what effect would there be if you put the 'rec' objects outside of the while loop utilising the one object (pointer) and not creating/destroying an object on each iteration?
Do you think  there could be any side effects ? ie. bad memory??
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block TSymbol Table Iteration
« Reply #2 on: November 22, 2005, 05:35:15 AM »
Hi Mick,

Could suck it and see I s'pose.

I originally thought a rec.close() would be required, and I'm still trying to determine that ...
It builds and runs either way,  ? ?
ie :
 
Code: [Select]
          while (ltblItem.MoveNext())
            {
                ObjectId id = (ObjectId)ltblItem.Current;
                using (LayerTableRecord rec = (LayerTableRecord)tm.GetObject(id, OpenMode.ForRead))
                {
                    ed.WriteMessage(string.Format("\nLayer Name : {0}", rec.Name));
                    rec.Close();
                }
            }

            BlockTable btbl = (BlockTable)tm.GetObject(db.BlockTableId, OpenMode.ForRead, false);
            IEnumerator btblItem = btbl.GetEnumerator();
            while (btblItem.MoveNext())
            {
                ObjectId id = (ObjectId)btblItem.Current;
                using (BlockTableRecord rec = (BlockTableRecord)tm.GetObject(id, OpenMode.ForRead))
                {
                    // string blokName = rec.Name;
                    // if ((blokName.Contains("*D") || blokName.Contains("*U") ) == false)

                    if ((rec.Name.StartsWith("*")) == false)
                    {
                        ed.WriteMessage(string.Format("\nBlock Name : {0}", rec.Name));                       
                    }
                    rec.Close();
                }
            }
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block SymbolTable Iteration
« Reply #3 on: November 22, 2005, 06:02:38 AM »
Here's something interesting

When I ran the .DLL through a reflector, this was the disassembly ..

notice the continue statements added ..

and the nesting of the using statements ..

and the change to
if (!record2.Name.StartsWith("*"))
in place of
if ((rec.Name.StartsWith("*")) == false)
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Layer and Block SymbolTable Iteration
« Reply #4 on: November 22, 2005, 06:07:02 AM »
Commenting away... :-D

1. Any particular reason you are EXPLICITLY getting an IEnumerator interface pointer and NOT using a foreach loop, which get's you a pointer to an IEnumerator on the collection anyway?

2. From the help regarding Close() inside transaction boudaries:

"If you use the getObject() function to obtain an object pointer, you should never call close() on that object pointer. Calling close() is valid only if you obtained the pointer using acdbOpenObject() or the object was newly created. For more information on when you can call close() on an object pointer, see the following sections, Newly Created Objects and Transactions and Mixing the Transaction Model with the Open and Close Mechanism."

You seem to be mixing models here Kerry...use either a transaction/GetObject OR the Open/Close paradigm - not both.

Mick, as far as your question goes, if the CSC compiler is anything like a good C++ compiler, declaring an object inside a loop on every iteration is supposed to be 'optimised' away by the compiler........


Cheers,
Glenn.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block SymbolTable Iteration
« Reply #5 on: November 22, 2005, 06:19:10 AM »
Hi Glenn ,

Great to hear from you.

Thanks for the comments, much appreciated.

.. for some reason I got into an enumerator mindset.


I think I'd rather use a Transaction/GetObject model.   

Stay well
Kerry
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Layer and Block SymbolTable Iteration
« Reply #6 on: November 22, 2005, 07:14:44 AM »
Kerry,

Just for interest's sake, here's how I do it:

Code: [Select]
#region System Includes

using System;

#endregion

#region Autodesk Includes

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

using pAcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

#endregion

[assembly: CommandClass(typeof(SymbolTables.TCGSClass))]
[assembly: ExtensionApplication(typeof(SymbolTables.TCGSClass))]

namespace SymbolTables
{
/// <summary>
/// Summary description for TCGSClass.
/// </summary>
public class TCGSClass : IExtensionApplication
{
// Default ctor
public TCGSClass() { }

// Define Command "SymTabs"
[CommandMethod("SymTabs", CommandFlags.Modal)]
static public void SymTabsCommand()
{
Document pDoc = pAcadApp.DocumentManager.MdiActiveDocument;
Database pDb = pDoc.Database;
Editor pEd = pDoc.Editor;

// Kick off a transaction on the current dbase...
using (Transaction pTr = pDb.TransactionManager.StartTransaction())
{
try
{
// Get a pointer to the layer table...
LayerTable pLayTbl = (LayerTable)pTr.GetObject(pDb.LayerTableId, OpenMode.ForRead, false);

// Loop the table and print out all the layer names...
foreach (ObjectId ltrId in pLayTbl)
{
LayerTableRecord pLTR = (LayerTableRecord)pTr.GetObject(ltrId, OpenMode.ForRead);
// Print some stuff...
pEd.WriteMessage("\nLayer name: {0}", pLTR.Name);
}

// Last off, commit the transaction...
pTr.Commit();

}
catch (Autodesk.AutoCAD.Runtime.Exception aex)
{
pEd.WriteMessage("\nError: " + aex.Message);
return;
}
catch (System.Exception ex)
{
pEd.WriteMessage("\nError: " + ex.Message);
return;
}


}

}

#region IExtensionApplication Members

public void Terminate()
{
// TODO:  Add TCGSClass.Terminate implementation
}

public void Initialize()
{
// TODO:  Add TCGSClass.Initialize implementation
}

#endregion
}
}

Cheers,
Glenn.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block SymbolTable Iteration
« Reply #7 on: November 22, 2005, 07:35:29 AM »
Thanks Glenn,
I'll have a look tomorrow night .. seems pretty straight forward. < when it's done for me > :)

be good
Kerry

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Layer and Block SymbolTable Iteration
« Reply #8 on: November 22, 2005, 03:14:55 PM »


Mick, as far as your question goes, if the CSC compiler is anything like a good C++ compiler, declaring an object inside a loop on every iteration is supposed to be 'optimised' away by the compiler........


Cheers,
Glenn.

Thanks Glenn, always wondered that and your answer clears that up.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Layer and Block SymbolTable Iteration
« Reply #9 on: November 22, 2005, 03:19:40 PM »
On the iterator thing, I remember thumbing through Jim Awe's code and seeing something about the IEnumerable interface not being implemented properly in some class (I think it was to do with a resbuf) and he used an enumerator to get around it, that ws the 2005 build though and may explain the anomoly. Always handy to know the workaround I guess :)
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block SymbolTable Iteration
« Reply #10 on: November 23, 2005, 02:51:06 AM »
.. it WAS straight forward, thanks Glenn.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Layer and Block SymbolTable Iteration
« Reply #11 on: November 23, 2005, 03:58:20 AM »
Something that MAY be interesting ..

The Code Dissassembled using Lutz Roeder's .NET Reflector has a finally block added, so I thought the compiler may have added it.

.. but, the ILDASM output is different again. try's and finally's for the using statements are added, but none added after the catch ... weird. < or I need some sleep>

This is the Reflector code re-assembled...
Code: [Select]
        [CommandMethod("SymTabs", CommandFlags.Modal)]
        public static void SymTabsCommand()
        {
            Document document1 = Application.DocumentManager.MdiActiveDocument;
            Database database1 = document1.Database;
            Editor editor1 = document1.Editor;
            Transaction transaction1 = database1.TransactionManager.StartTransaction();
            try
            {
                LayerTable table1 = (LayerTable)transaction1.GetObject(database1.LayerTableId, OpenMode.ForRead, false);
                foreach (ObjectId id1 in table1)
                {
                    LayerTableRecord record1 = (LayerTableRecord)transaction1.GetObject(id1, OpenMode.ForRead);
                    object[] objArray1 = new object[] { record1.Name };
                    editor1.WriteMessage("\nLayer name: {0}", objArray1);
                }
                transaction1.Commit();
            } catch (Exception exception1)
            {
                editor1.WriteMessage("\nError: " + exception1.Message);
                return;
            } catch (Exception exception2)
            {
                editor1.WriteMessage("\nError: " + exception2.Message);
                return;
            } finally
            {
                if (transaction1 != null)
                {
                    transaction1.Dispose();
                }
            }
        }

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.