Author Topic: Re-writing a lisp app in vb.net - time to learn  (Read 2553 times)

0 Members and 1 Guest are viewing this topic.

mkweaver

  • Bull Frog
  • Posts: 352
Re-writing a lisp app in vb.net - time to learn
« on: November 29, 2008, 12:22:29 PM »
I have a lisp application that I want to re-write in vb.net as an learning excersize.  Some of the approaches I use in lisp work well, but I'm thinking they may not work well in dot net.

For example, I have a function that takes a fully qualified pathname to a drawing file and returns a document object.  This is done by first checking the active document, then the documents collection, and if it still hasn't found the target drawing it then tries to open the drawing using objectdbx.  The one thing I have to be careful with is that the calling routine has to be sure to release the document object when it's done with it.

I use this procedure in a variety of programs where I need a document object.

Below is the vb.net code I have developed for this:

Suggestions are welcome.
Code: [Select]
  Private Function GetRemoteDb(ByVal DocPathName As String) As Autodesk.AutoCAD.DatabaseServices.Database
    Dim colDocs As Autodesk.AutoCAD.ApplicationServices.DocumentCollection
    Dim ActiveDoc As Autodesk.AutoCAD.ApplicationServices.Document
    ActiveDoc = ApplicationServices.Application.DocumentManager.MdiActiveDocument

    'if our document is the active document, then return it.
    If ActiveDoc.Name = DocPathName Then
      Return ActiveDoc.Database
      Exit Function
    End If

    'if our document is already open then return it
    colDocs = ApplicationServices.Application.DocumentManager
    For Each doc As ApplicationServices.Document In colDocs
      If doc.Name = DocPathName Then
        Return doc.Database
        Exit Function
      End If
    Next


    'if the document doesn't exist, then throw an error
    If Not My.Computer.FileSystem.FileExists(DocPathName) Then
      Throw New System.IO.FileNotFoundException
    End If
    'it exists, and isn't open, so let's open and return it
    Dim dbTarget As New Database(False, True)
    Try
      dbTarget.ReadDwgFile(DocPathName, FileOpenMode.OpenForReadAndAllShare, False, "")
      If dbTarget.Filename = DocPathName Then
        Return dbTarget
        Exit Function
      End If

    Catch ex As Exception
      Debug.Print("Oops, we seem to have had an error " & ex.Message)
    End Try

    GetRemoteDb = dbTarget

  End Function

Now the question.  Should I be building a RemoteDoc class to ensure handle the disposing of the objects that this procedure generates?  Is there a better way (probably many) to skin this cat?

TonyT

  • Guest
Re: Re-writing a lisp app in vb.net - time to learn
« Reply #1 on: November 29, 2008, 05:15:12 PM »
First, use case-insensitive string comparison on file names.

Second, you don't need to worry about whether a Database is
open in the editor, or not. If the database is open in the editor,
it's AutoDelete property will be false, otherwise it will be true.
You only need to call Dispose() on a database if it is not open
in the editor:

   Database db = // call your function to assign db
   try
   {

   // use db here

   }
   finally
   {
       if( db.AutoDelete )
          db.Dispose();
   }

You can also use 'Using' and call Dispose() on the
Database in any case, because a Database knows
what to do when you call its Dispose(), depending
on whether it's open in the editor, or not.

I've said in the past that one should not call Dispose()
on a Database that's open in the editor, but my own
opinion on that now is that it's ok in cases where you
may be dealing both types (databases that are open
in the editor, and ones created by calling the new()
constructor and ReadDwgFile()).

If for another reason you need to know if a Database
is open in the editor, you can tell by just looking at
its AutoDelete property.

As far as disposing objects you get from a database, you
don't have to do that unless disposing an object has a
side-effects (which is the case with Transactions). For
other objects, you don't need to call Dispose().

You can also not bother calling Dispose() on any DBObject
that you get from a Transaction, because the transaction
manages the object for you.

Other things I noticed you calling Dispose() on (like the
TransactionManager for example), you should not call
Dispose() on, because in many cases, those objects are
managed by an 'owner' object (the object that you get
them from via referencing a property or calling a method
of the 'owner' object).

While in most cases needless calls to Dispose() will do
no harm, that is not the case for the Document object,
and is why you have to be careful about what you call
Dispose() on.

My personal opinion about the seemingly massive and
widepsread confusion that exists on the matter of what
should be disposed and what shouldn't be disposed, is
that it is largely a product of extremely poor API design
on Autodesk's part.

I have a lisp application that I want to re-write in vb.net as an learning excersize.  Some of the approaches I use in lisp work well, but I'm thinking they may not work well in dot net.

For example, I have a function that takes a fully qualified pathname to a drawing file and returns a document object.  This is done by first checking the active document, then the documents collection, and if it still hasn't found the target drawing it then tries to open the drawing using objectdbx.  The one thing I have to be careful with is that the calling routine has to be sure to release the document object when it's done with it.

I use this procedure in a variety of programs where I need a document object.

Below is the vb.net code I have developed for this:

Suggestions are welcome.
Code: [Select]
  Private Function GetRemoteDb(ByVal DocPathName As String) As Autodesk.AutoCAD.DatabaseServices.Database
    Dim colDocs As Autodesk.AutoCAD.ApplicationServices.DocumentCollection
    Dim ActiveDoc As Autodesk.AutoCAD.ApplicationServices.Document
    ActiveDoc = ApplicationServices.Application.DocumentManager.MdiActiveDocument

    'if our document is the active document, then return it.
    If ActiveDoc.Name = DocPathName Then
      Return ActiveDoc.Database
      Exit Function
    End If

    'if our document is already open then return it
    colDocs = ApplicationServices.Application.DocumentManager
    For Each doc As ApplicationServices.Document In colDocs
      If doc.Name = DocPathName Then
        Return doc.Database
        Exit Function
      End If
    Next


    'if the document doesn't exist, then throw an error
    If Not My.Computer.FileSystem.FileExists(DocPathName) Then
      Throw New System.IO.FileNotFoundException
    End If
    'it exists, and isn't open, so let's open and return it
    Dim dbTarget As New Database(False, True)
    Try
      dbTarget.ReadDwgFile(DocPathName, FileOpenMode.OpenForReadAndAllShare, False, "")
      If dbTarget.Filename = DocPathName Then
        Return dbTarget
        Exit Function
      End If

    Catch ex As Exception
      Debug.Print("Oops, we seem to have had an error " & ex.Message)
    End Try

    GetRemoteDb = dbTarget

  End Function

Now the question.  Should I be building a RemoteDoc class to ensure handle the disposing of the objects that this procedure generates?  Is there a better way (probably many) to skin this cat?


mkweaver

  • Bull Frog
  • Posts: 352
Re: Re-writing a lisp app in vb.net - time to learn
« Reply #2 on: November 29, 2008, 06:20:39 PM »
Tony,
I really appreciate your feedback.

I can see the benefit of using case sensitive string comparisons for file names.

Thanks for the pointer on the AutoDelete property.  That will be handy.

My first reaction, then, is that I don't even need to check the documents collection for the drawing I want.  ReadDwgFile will get the database from the open drawing rather than from the file on disk?  If that is the case, then this routine reduces to:
Code: [Select]
  Private Function GetRemoteDb(ByVal DocPathName As String) As Autodesk.AutoCAD.DatabaseServices.Database

    'if the document doesn't exist, then throw an error
    If Not My.Computer.FileSystem.FileExists(DocPathName) Then
      Throw New System.IO.FileNotFoundException
    End If
    'it exists, let's open and return it
    Dim dbTarget As New Database(False, True)
    Try
      dbTarget.ReadDwgFile(DocPathName, FileOpenMode.OpenForReadAndAllShare, False, "")
      If dbTarget.Filename = DocPathName Then
        Return dbTarget
        Exit Function
      End If

    Catch ex As Exception
      Debug.Print("Oops, we seem to have had an error " & ex.Message)
    End Try

    GetRemoteDb = dbTarget

  End Function

I will have to spend some time digesting your comments regarding disposing of objects.  I agree, there is "massive and widespread confusion" on that subject.

Mike Weaver



TonyT

  • Guest
Re: Re-writing a lisp app in vb.net - time to learn
« Reply #3 on: November 29, 2008, 09:52:45 PM »
No, you still have to check the documents collection. ReadDwgFile()
knows nothing about what's open in the editor.  Just do it the way
you were with the addition of case-insensitive string comparisons,
and you can still call Dispose() on the database regardless of where
you got it.

Tony,
I really appreciate your feedback.

I can see the benefit of using case sensitive string comparisons for file names.

Thanks for the pointer on the AutoDelete property.  That will be handy.

My first reaction, then, is that I don't even need to check the documents collection for the drawing I want.  ReadDwgFile will get the database from the open drawing rather than from the file on disk?  If that is the case, then this routine reduces to:
Code: [Select]
  Private Function GetRemoteDb(ByVal DocPathName As String) As Autodesk.AutoCAD.DatabaseServices.Database

    'if the document doesn't exist, then throw an error
    If Not My.Computer.FileSystem.FileExists(DocPathName) Then
      Throw New System.IO.FileNotFoundException
    End If
    'it exists, let's open and return it
    Dim dbTarget As New Database(False, True)
    Try
      dbTarget.ReadDwgFile(DocPathName, FileOpenMode.OpenForReadAndAllShare, False, "")
      If dbTarget.Filename = DocPathName Then
        Return dbTarget
        Exit Function
      End If

    Catch ex As Exception
      Debug.Print("Oops, we seem to have had an error " & ex.Message)
    End Try

    GetRemoteDb = dbTarget

  End Function

I will have to spend some time digesting your comments regarding disposing of objects.  I agree, there is "massive and widespread confusion" on that subject.

Mike Weaver




mkweaver

  • Bull Frog
  • Posts: 352
Re: Re-writing a lisp app in vb.net - time to learn
« Reply #4 on: November 30, 2008, 12:15:46 AM »
Thanks!