Author Topic: Question about disposing.  (Read 14425 times)

0 Members and 1 Guest are viewing this topic.

BillZndl

  • Guest
Question about disposing.
« on: October 22, 2009, 12:15:59 PM »
VS2005, net 2.0, R2006 acad.

Trying to debug a problem with my modal form application.
Lately, when exiting AutoCAD, I sometimes get the dreaded "Fatal Error" before exit.

I've checked to be sure that I'm disposing all databases I've created and anything else outside of some "using (transaction" .

A while back, I added a global Hashtable along side (same Namespace)
as my main program form: "class public class PartMonitor : System.Windows.Forms.Form".
I use it to store info when a new group is added to the database.

public class Module
    {   
        private static Hashtable GrpInfoTable = new Hashtable();

        public static Hashtable GrpInfoTbl
        {
            get
            {
                return GrpInfoTable;
            }
        }
        public Module()
        {
        }       
    }

My question is, could the creation of this "Global" hashtable be the reason I'm getting the error?
Just wondering if somehow it needs to be "disposed"?






Glenn R

  • Guest
Re: Question about disposing.
« Reply #1 on: October 22, 2009, 12:25:31 PM »
Depends. You're not showing us enough. What's in the hashtable?

Also, have you implemented IExtensionApplication? If so, do you have anything in the Terminate method?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #2 on: October 22, 2009, 01:20:41 PM »
When an object is appended to the database event,
if it's a group, I send the e.object to be opened for read to get the name.
I add the name and either true or false to the hashtable.

using (Transaction trans = document.TransactionManager.StartTransaction())
                {               
                    DBDictionary GrpDic = (DBDictionary)trans.GetObject(db.GroupDictionaryId, OpenMode.ForRead);

                    if (GrpId.IsValid)
                    {
                        name = GrpDic.NameAt(GrpId);

                        if (!name.Contains("*"))
                        {
                            Module.GrpInfoTbl.Add(name, true);
                        }
                        else
                        {                           
                            Module.GrpInfoTbl.Add(name, false);
                        }
                    }
                    GrpDic.Dispose();
                }

Here's my IExtensionApp:

public class Initialization : Autodesk.AutoCAD.Runtime.IExtensionApplication
{
    public void Initialize()
    {
        Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
        ed.WriteMessage(" PartMon --- Loaded\r");
    }
    public void Terminate()
    {
        Console.WriteLine("Cleaning up...");
    }
}



Glenn R

  • Guest
Re: Question about disposing.
« Reply #3 on: October 22, 2009, 02:52:27 PM »
3 things I notice straight off:

1. Nix the Console.WriteLine statement in your terminate method. You don't have a console to write to and acad is shutting down fast.
2. There's no commit statement for the transaction.
3. There's no need to for this: GrpDisc.Dispose(); It will get called for you.

I suspect there's something else causing the problem, but without more information, I would only be guessing.

Try the suggestions above and see what happens and post back.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #4 on: October 22, 2009, 03:45:45 PM »
Quote from: Glenn R
1. Nix the Console.WriteLine statement in your terminate method. You don't have a console to write to and acad is shutting down fast.

Saw that right after I posted.  :lol:

I changed it to this:

public void Terminate()
    {       
    }

Quote from: Glenn R
2. There's no commit statement for the transaction.

Oooh, My understanding was that you only needed to commit the transaction if you made changes,
not just accessing a name or whatever.
I had about 12 places I added the trans.commit();  :-o


Quote from:  "Glenn R"
3. There's no need to for this: GrpDisc.Dispose(); It will get called for you.

Yeah, I was deperate and trying anything I could think of. Nixed it.  :ugly:


It may take a while for these changes to show up because it doesn't happen everytime and so far it seems to help.

I'll post up if it does it again.

Thanks!



Glenn R

  • Guest
Re: Question about disposing.
« Reply #5 on: October 22, 2009, 04:06:06 PM »
After doing C++/ARX for a few years you learn a few things and one that applies equally well to .NET is this:

If you 'new' it, delete/destroy/dispose of it - if you didn't, don't. There are exceptions to this, especially in ARX where functions will hand you back a string and the documentation explicitly tells you that you're responsible for deleting the string/memory.

A .NET example would be creating a new Database for use with ReadDwgFile - you 'new'ed it, so you're responsible for disposing of it, usually by wrapping the creation in a 'using' statement/block.

You're example where you're getting a group inside a transaction shows that you didn't 'new' it, autocad did behind the scenes, so it manages it's destruction/disposal - not you.

As far as the commit goes, it's been stated by a few from autodesk, that NOT commiting a transaction is expensive because it will cause a 'rollback', so you're better off commiting the transaction, even if you're only 'reading' objects, for performance reasons, rather than implicity (in your case) or explicitly causing an abort.

Make sense?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #6 on: October 22, 2009, 04:28:46 PM »
Sure does make sense.
Helps to reinforce what I'm learning.

This app is getting fairly complicated and I am a beginner at this.
It could be a memory issue as some of my methods do a lot of looping.
One example, I was refreshing my ListView by repopulating it everytime an item changed,
which meant looping through the DBdictionary, getting names, descriptions and checking ents for visible, yada yada
I re wrote parts so I can update just one item if it changes and am getting better at modularizing(?) so am hoping that helps.

Then again, I've had R2k6 crash once in a while for no apparant reason, with no code running so go figure. :lol:

BillZndl

  • Guest
Re: Question about disposing.
« Reply #7 on: October 25, 2009, 09:40:57 PM »
Didn't help.
When I exited Autocad at the end of the day,
it really locked up with the Fatal Error.

I do have an Idea what's wrong,
I'm opening the Group for read on the DatabaseAppended event,
that's probably causing the access violation.
I'm thinking I should store the objectId and do all the work on the commandEnded event.

I'll try that and see if I'm right.



It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #8 on: October 26, 2009, 01:08:10 AM »
what happens when you run it through the debugger?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #9 on: October 26, 2009, 06:20:16 AM »
what happens when you run it through the debugger?

As far as I know, nothing. Everything builds and runs fine.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #10 on: October 26, 2009, 07:50:55 AM »
I do have an Idea what's wrong,
I'm opening the Group for read on the DatabaseAppended event,
that's probably causing the access violation.
I'm thinking I should store the objectId and do all the work on the commandEnded event.

I'll try that and see if I'm right.


That didn't work.

I changed the objectId handling at the DatabaseAppended event to:
public class NewGroupObjectID
    {       
        public void GroupName(ObjectId GrpId)
        {
            if (GrpId.IsValid)
            {           
              Module.GrpInfoTbl.Add(GrpId, true);                               
            }               
        }
    }

Then I do the name and description checking at the commandEnded event but things still crashes hard at exit.





BillZndl

  • Guest
Re: Question about disposing.
« Reply #11 on: October 26, 2009, 10:18:21 AM »
Okay, this is what the error says:


My next suspect is where I delete groups, anyone see anything radiacally wrong with this class?
I feed it the group name as a string, get the group, erase the entities and remove the group from the DBdictionary.

Code: [Select]
class DeleteGroup
    {
        public void RemoveGroup(string Strline)
        {
            Document document = AcadApp.DocumentManager.MdiActiveDocument;
            Editor editor = document.Editor;
            Database database = AcadApp.DocumentManager.MdiActiveDocument.Database;

            using (DocumentLock doclck = document.LockDocument())
            {
                using (Transaction trans = database.TransactionManager.StartTransaction())
                {
                    DBDictionary GrpDic = (DBDictionary)trans.GetObject(database.GroupDictionaryId, OpenMode.ForRead);

                    ObjectId Did = ObjectId.Null;

                    try
                    {
                        Did = GrpDic.GetAt(Strline);
                    }
                    catch { }

                    if (!Did.IsNull)
                    {
                        Group EntGrpDic = (Group)trans.GetObject(Did, OpenMode.ForWrite);
                        ObjectIdCollection Eids = new ObjectIdCollection();

                        foreach (ObjectId id in EntGrpDic.GetAllEntityIds())
                        {
                            Eids.Add(id);

                            if (!id.IsErased)
                            {
                            Entity ent = (Entity)trans.GetObject(id, OpenMode.ForWrite);
                            ent.Erase();
                            }
                        }

                        if (Eids.Count > 0)
                        {
                            EntGrpDic.Remove(Eids);                           
                            database.Purge(Eids);
                        }
                        GrpDic.UpgradeOpen();
                        if (GrpDic.Contains(Did))
                        {
                        GrpDic.Remove(Did);
                        }
                       
                        Module.GrpInfoTbl.Clear();

                        editor.WriteMessage("\nDeleted Group: < " + Strline + " > \r");
                        editor.WriteMessage("\nCommand:\r");
                    }
                    trans.Commit();
                }
            }
            database.Dispose();
        }
    }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #12 on: October 26, 2009, 10:57:28 AM »
don't do this

Code: [Select]
database.Dispose();

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #13 on: October 26, 2009, 11:30:46 AM »
A couple questions.

Why do you think you should dispose the database?
What is your try catch statement supposed to do when it catches an exception?
How are you handling exceptions that are thrown outside of your try catch scope?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #14 on: October 26, 2009, 12:25:34 PM »
A couple questions.

Why do you think you should dispose the database?

I thought I saw that in an example somewhere. < shrug >

Quote
What is your try catch statement supposed to do when it catches an exception?

Here is how I been calling my methods:
Code: [Select]
private void document_CommandEnded(object sender, CommandEventArgs e)
        {           
           
            if (e.GlobalCommandName.Equals("COPY"))
            {
                try
                {
                    AddGroupDate agd = new AddGroupDate();
                    agd.AddDate();
                    FillListView();
                    SetLastSelected();
                }
                catch (SystemException exception)
                {
                    MessageBox.Show("AddGroupDate: failed" + exception.StackTrace);
                }
            }



Quote
How are you handling exceptions that are thrown outside of your try catch scope?

That's a good question, is there a "solution level" error handler?

BTW: I took out all the DB.Dispose(); stuff and still get the error when exiting.