.NET

Reply
Active Contributor
JasonSelf
Posts: 35
Registered: ‎08-30-2010
Message 1 of 9 (1,341 Views)

eNoDatabase with Inserting a block (vb.net)

1341 Views, 8 Replies
09-06-2011 02:35 PM

I have written this code that adds a block to the block table but does not insert it.  In a test project it seems to work flawlessly:

    <CommandMethod("test")>
    Public Sub test()
        Dim blkname As String = "PS01-L2x2x0.25"
        Dim blockpath As String = "C:\"
        If blockpath = "" Then
            MsgBox("Path to blocks is not valid.")
            Return
        Else
            Dim fullpath As String = blockpath & blkname & ".dwg"
            Dim curdwg As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = curdwg.Editor
            If File.Exists(fullpath) Then
                Dim dwg As Database = ed.Document.Database
                Dim blkdwg As New Database
                blkdwg.ReadDwgFile(fullpath, FileOpenMode.OpenForReadAndAllShare, True, vbNullString)
                dwg.Insert(blkname, blkdwg, False)
                blkdwg.Dispose()
            Else
                MsgBox(fullpath & vbCr & "Does not exist")
                Return
            End If
        End If
    End Sub

 

This simular code is being called from inside a transaction in my primary program, but gives me a eNoDatabase error

    Public Shared Sub insb(ByVal blkname As String)
        Dim curdwg As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = curdwg.Editor
        Dim dwg As Database = ed.Document.Database
        Dim blockpath As String = GetSetting("AMG", "SupportIT", "BlockPath")
        If blockpath = "" Then
            MsgBox("Path to blocks is not valid.")
            Return
        Else
            Dim fullpath As String = blockpath & blkname & ".dwg"
            If File.Exists(fullpath) Then
                Try
                    Using doclock As DocumentLock = ed.Document.LockDocument
                        Dim blkdwg As New Database
                        blkdwg.ReadDwgFile(fullpath, FileOpenMode.OpenForReadAndAllShare, True, vbNullString)
                        'Error on line below!
                        dwg.Insert(blkname, blkdwg, False)
                        blkdwg.Dispose()
                    End Using
                Catch ex As Exception
                    MsgBox(ex.Message)
                End Try
            Else
                MsgBox(fullpath & vbCr & "Does not exist")
                Return
            End If
        End If
    End Sub
End Class

 I'm not sure why exactly it is throwing this error, however I have narrowed it down to the statement "dwg.Insert(blkname, blkdwg, False)"

 

Any help would be greatly appreciated.

 

Thank you,

Jason Self

*Expert Elite*
Alfred.NESWADBA
Posts: 8,866
Registered: ‎06-29-2007
Message 2 of 9 (1,332 Views)

Betreff: eNoDatabase with Inserting a block (vb.net)

09-06-2011 03:08 PM in reply to: JasonSelf

Hi,

 

first: I have not tried your code, just read it. I saw 2 "maybe"-problems:

 

1) in normal cases the locking of a document should be done before you start/commit/dispose a transaction. In you second code-snippet you start a document-locking during a transaction is active (at least you wrote there is one active).

However I never tried it in your way (first create transaction and then lock the document), but it's worth to try this to change!

 

2) when you create a new databaseobject and use it for reading a DWG-file, you have to end the read-connection/stop the access to the file. If you don't you will get an when you use it the next time (read the DWG). So after reading the DWG and before disposing the object you should add:

   blkdwg.CloseInput(True)

So I wonder if you get the problem with the first insert after you restarted AutoCAD, my feeling is, the problem occurs during the second call to this function.

 

Hoping that at least one of the above ideas helps,

 

- alfred -

-------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at
-------------------------------------------------------------------------
Board Manager
StephenPreston
Posts: 362
Registered: ‎05-22-2006
Message 3 of 9 (1,321 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-06-2011 10:30 PM in reply to: JasonSelf

I don't have the .NET Ref Guide in front of me right now, but the problem could be this line:

 

>>Dim blkdwg As New Database

 

In ObjectARX (which the .NET API closely follows), the Database constructor tales two arguments:

 

AcDbDatabase::AcDbDatabase(bool buildDefaultDrawing = true, bool noDocument = false); in ObjectARX

 

When creating a database to read a DWG file into (i.e. when using ReadDwgFile(), you must always set buildDefaultDrawing to false. Otherwise, you may experience unexpected (and possibly intermittent) errors.

 

So try changing your line of code to:

 

Dim blkdwg As New Database(False, False)

 

to see if it fixes the problem.

Cheers,

Stephen Preston
Autodesk Developer Network
Active Contributor
JasonSelf
Posts: 35
Registered: ‎08-30-2010
Message 4 of 9 (1,302 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-07-2011 08:43 AM in reply to: StephenPreston

Thank you both for your replies.  First, I have to admit that docklock was an accident, I added the statement while I was trying to resolve the issue and never removed it again...gone now.  Thanks and Good eye on that one.  Unfortunately dwg.closeinput(True) didn't have any effect on the reslut...it still returned eNoDatabase.

 

Adding (False, False) per your suggestion, Stephen, seems to have progressed the situation...instead of an FE with a eNoDatabase error it now drops through to my Catch statemtent with a eNoInputFiler.  Any Ideas....Below is all of the code in the offending class...The blockjig stuff isn't mine, it's....borrowed...from an example I pulled off ot the web and works great if the block already exists in the drawing....my code is at the bottom.

 

Thanks again,

Jason

 

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports System.Collections.Generic
Imports System.IO

'Namespace BlockJig
Class CBlockJig
    Inherits EntityJig
    Private _pos As Point3d
    Private _attPos As Dictionary(Of String, Point3d)
    Private _tr As Transaction
    Public Sub New(ByVal tr As Transaction, ByVal br As BlockReference)
        MyBase.New(br)
        _pos = br.Position
        ' Initialize our dictionary with the tag /
        ' AttributeDefinition position
        _attPos = New Dictionary(Of String, Point3d)()
        _tr = tr
        Dim btr As BlockTableRecord = DirectCast(_tr.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
        If btr.HasAttributeDefinitions Then
            For Each id As ObjectId In btr
                Dim obj As DBObject = tr.GetObject(id, OpenMode.ForRead)
                Dim ad As AttributeDefinition = TryCast(obj, AttributeDefinition)
                If ad IsNot Nothing Then
                    _attPos.Add(ad.Tag, ad.Position)
                End If
            Next
        End If
    End Sub

    Protected Overrides Function Update() As Boolean
        Dim br As BlockReference = TryCast(Entity, BlockReference)
        br.Position = _pos
        If br.AttributeCollection.Count <> 0 Then
            For Each id As ObjectId In br.AttributeCollection
                Dim obj As DBObject = _tr.GetObject(id, OpenMode.ForRead)
                Dim ar As AttributeReference = TryCast(obj, AttributeReference)
                ' Apply block transform to att def position
                If ar IsNot Nothing Then
                    ar.UpgradeOpen()
                    ar.Position = _attPos(ar.Tag).TransformBy(br.BlockTransform)
                End If
            Next
        End If
        Return True
    End Function

    Protected Overrides Function Sampler(ByVal prompts As JigPrompts) As SamplerStatus
        Dim opts As New JigPromptPointOptions(vbLf & "Select insertion point:")
        opts.BasePoint = New Point3d(0, 0, 0)
        opts.UserInputControls = UserInputControls.NoZeroResponseAccepted
        Dim ppr As PromptPointResult = prompts.AcquirePoint(opts)
        If _pos = ppr.Value Then
            Return SamplerStatus.NoChange
        End If
        _pos = ppr.Value
        Return SamplerStatus.OK
    End Function

    Public Function Run() As PromptStatus
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        Dim promptResult As PromptResult = ed.Drag(Me)
        Return promptResult.Status
    End Function
End Class


Public Class Insert_Lib
    Public Shared Sub BlockJig(ByVal blkname As String)
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Dim bt As BlockTable
        Dim tr As Transaction = doc.TransactionManager.StartTransaction()
        Using tr
            bt = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
            If Not bt.Has(blkname) Then
                insb(blkname)
            End If
        End Using
            Using tr
                bt = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
                Dim space As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead), BlockTableRecord)
                space.UpgradeOpen()
                Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt(blkname), OpenMode.ForRead), BlockTableRecord)
                Dim br As New BlockReference(New Point3d(), btr.ObjectId)
                space.AppendEntity(br)
                tr.AddNewlyCreatedDBObject(br, True)
                If btr.HasAttributeDefinitions Then
                    For Each id As ObjectId In btr
                        Dim obj As DBObject = tr.GetObject(id, OpenMode.ForRead)
                        Dim ad As AttributeDefinition = TryCast(obj, AttributeDefinition)
                        If ad IsNot Nothing AndAlso Not ad.Constant Then
                            Dim ar As New AttributeReference()
                            ar.SetAttributeFromBlock(ad, br.BlockTransform)
                            ar.Position = ad.Position.TransformBy(br.BlockTransform)
                            ar.TextString = ad.TextString
                            br.AttributeCollection.AppendAttribute(ar)
                            tr.AddNewlyCreatedDBObject(ar, True)
                        End If
                    Next
                End If
                ' Run the jig
                Dim myJig As New CBlockJig(tr, br)
                If myJig.Run() <> PromptStatus.OK Then
                    Return
                End If
                ' Commit changes if user accepted, otherwise discard
                tr.Commit()
            End Using
    End Sub
    Public Shared Sub insb(ByVal blkname As String)
        Dim curdwg As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = curdwg.Editor
        Dim dwg As Database = ed.Document.Database
        Dim blockpath As String = GetSetting("AMG", "SupportIT", "BlockPath")
        If blockpath = "" Then
            MsgBox("Path to blocks is not valid.")
            Return
        Else
            Dim fullpath As String = blockpath & blkname & ".dwg"
            If File.Exists(fullpath) Then
                Try
                    Dim blkdwg As New Database(False, False)
                    blkdwg.ReadDwgFile(fullpath, FileOpenMode.OpenForReadAndAllShare, True, vbNullString)
                    dwg.CloseInput(True)
                    dwg.Insert(blkname, blkdwg, False)
                    blkdwg.Dispose()
                Catch ex As Exception
                    MsgBox("Error: " & ex.Message)
                    Return
                End Try
            Else
                MsgBox(fullpath & vbCr & "Does not exist")
                Return
            End If
        End If
    End Sub
End Class
'End Namespace

 

 

 

 

 

Valued Mentor
jeff
Posts: 321
Registered: ‎05-12-2009
Message 5 of 9 (1,291 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-07-2011 09:54 AM in reply to: JasonSelf

(false, True)

 

Here are C#, VB, & F# examples

 

http://www.theswamp.org/index.php?topic=37686.msg427172#msg427172

You can also find your answers @ TheSwamp
Active Contributor
JasonSelf
Posts: 35
Registered: ‎08-30-2010
Message 6 of 9 (1,274 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-07-2011 01:28 PM in reply to: JasonSelf

(False, True) didn't seem to do it for me....I pulled my code out of the class I borrowed and it, on its own works fine.  The blockjig portion of the code I have modified and am using after the code I have written works when ran independantly but when it is called direclty after my code it errors on me.  Ill lay things out and maybe clear soem things up:

 

Here is my code...independantly it seems to run  (I will spare you the Imports)

Public Class Block_Lib
    Public Sub insb(ByVal blkname As String)
        Dim blockpath As String = GetSetting("AMG", "SupportIT", "BlockPath")
        If blockpath = "" Then
            MsgBox("Path to blocks is not valid.")
            Return
        Else
            Dim fullpath As String = blockpath & blkname & ".dwg"
            Dim curdwg As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = curdwg.Editor
            If File.Exists(fullpath) Then
                Dim dwg As Database = ed.Document.Database
                Dim blkdwg As New Database '(False, False)
                blkdwg.ReadDwgFile(fullpath, FileOpenMode.OpenForReadAndAllShare, True, vbNullString)
                Using docklock As DocumentLock = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument()
                    dwg.Insert(blkname, blkdwg, False)
                End Using
                MsgBox("block inserted into database")
                blkdwg.Dispose()
                dwg.Dispose()
            Else
                MsgBox(fullpath & vbCr & "Does not exist")
                Return
            End If
        End If
    End Sub
End Class

 Here is the code I borrowed and modified...It calls a custom class that I have removed for clairity...it is in my earlier post

Public Class Commands
    '<CommandMethod("BJ")> _
    Public Sub BlockJig() '(ByVal blkname As String)
        Dim blkname As String = "PS01-L2x2x0.25"
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        'Dim pso As New PromptStringOptions(vbLf & "Enter block name: ")
        'Dim pr As PromptResult = ed.GetString(pso)
        'If pr.Status <> PromptStatus.OK Then
        'Return
        'End If
        Dim tr As Transaction = doc.TransactionManager.StartTransaction()
        Using tr
            Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
            Dim space As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead), BlockTableRecord)
            'If Not bt.Has(pr.StringResult) Then
            If Not bt.Has(blkname) Then
                ed.WriteMessage(vbLf & "Block """ + blkname & """ not found.")
                'ed.WriteMessage(vbLf & "Block """ + pr.StringResult & """ not found.")
                Return
            End If
            space.UpgradeOpen()
            Dim btr As BlockTableRecord
            Try
                btr = DirectCast(tr.GetObject(bt(blkname), OpenMode.ForRead), BlockTableRecord)
                'btr = DirectCast(tr.GetObject(bt(pr.StringResult), OpenMode.ForRead), BlockTableRecord)
            Catch ex As Exception
                MsgBox(ex.Message)
                Return
            End Try

            ' Block needs to be inserted to current space before
            ' being able to append attribute to it
            Dim br As New BlockReference(New Point3d(), btr.ObjectId)
            space.AppendEntity(br)
            tr.AddNewlyCreatedDBObject(br, True)
            If btr.HasAttributeDefinitions Then
                For Each id As ObjectId In btr
                    Dim obj As DBObject = tr.GetObject(id, OpenMode.ForRead)
                    Dim ad As AttributeDefinition = TryCast(obj, AttributeDefinition)
                    If ad IsNot Nothing AndAlso Not ad.Constant Then
                        Dim ar As New AttributeReference()
                        ar.SetAttributeFromBlock(ad, br.BlockTransform)
                        ar.Position = ad.Position.TransformBy(br.BlockTransform)
                        ar.TextString = ad.TextString
                        br.AttributeCollection.AppendAttribute(ar)
                        tr.AddNewlyCreatedDBObject(ar, True)
                    End If
                Next
            End If
            ' Run the jig
            Dim myJig As New CBlockJig(tr, br)
            If myJig.Run() <> PromptStatus.OK Then
                Return
            End If
            ' Commit changes if user accepted, otherwise discard
            tr.Commit()
        End Using
    End Sub
End Class
'End Namespace

 I commented out the prompt stuff and gave it the block name (the same as what is added in my code) and if I call this by typing bj it does exactly what you would expect, it inserts the block using a jig.

 

If I take the next step and call this code with a byval for the blockname it errors out on me, seems like inconsistant places, the last place I found it doing it was during the upgradeopen statement.

 

Feels like I am getting close, just not there yet....

 

Thanks everyone for your help so far,

Jason

Valued Mentor
jeff
Posts: 321
Registered: ‎05-12-2009
Message 7 of 9 (1,260 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-07-2011 05:43 PM in reply to: JasonSelf

Just looking real quick and will have more time tommorrow

 

need to commit transaction

 

        Using tr
            bt = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
            If Not bt.Has(blkname) Then
                insb(blkname)
            End If
        End Using

 

When nested transaction are commited the objects used with them are passed up to the containing transaction.

 

Objects are updated when the outermost transaction is commited so anything modified in insb method even if inside a transaction and commited will not be modified, since all outer transactions must be commited to take effect

You can also find your answers @ TheSwamp
Valued Contributor
RPeter
Posts: 80
Registered: ‎01-09-2009
Message 8 of 9 (1,249 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-08-2011 03:15 AM in reply to: JasonSelf

I Use this code:

Where "bln" is the blockname, "dwg" is the path to the dwg, "pt" is the insertionpoint

 

    Public Sub BlockInvoegen(ByVal bln As String, ByVal dwg As String, ByVal pt As Point3d)
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        Dim db As Database = doc.Database
        Using tr As Transaction = db.TransactionManager.StartTransaction()
            Dim btbl As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
            Dim btblr As BlockTableRecord = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite)
            If btbl.Has(bln) = True Then
                Dim bref As New BlockReference(pt, btbl(bln))
                btblr.AppendEntity(bref)
                tr.AddNewlyCreatedDBObject(bref, True)
                Dim refbtr As BlockTableRecord = tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead)
                Dim attent As Entity
                For Each attid As ObjectId In refbtr
                    attent = tr.GetObject(attid, OpenMode.ForRead)
                    If TypeOf attent Is AttributeDefinition Then
                        Dim attdef As AttributeDefinition = attent
                        Dim attref As New AttributeReference()
                        attref.SetAttributeFromBlock(attdef, bref.BlockTransform)
                        Dim attrefid As ObjectId = bref.AttributeCollection.AppendAttribute(attref)
                        If attref.HasFields Then
                            Dim dic As DBDictionary = tr.GetObject(attref.ExtensionDictionary, OpenMode.ForRead)
                            Dim flddic As DBDictionary = tr.GetObject(dic.GetAt("ACAD_FIELD"), OpenMode.ForRead)
                            Dim fld As Field = tr.GetObject(flddic.GetAt("TEXT"), OpenMode.ForWrite)
                            Dim strid As String = bref.ObjectId.OldIdPtr.ToString()
                            Dim updtstr As String = "%<\_ObjID " & strid & ">%"
                            Dim fldcode As String = fld.GetFieldCode(FieldCodeFlags.AddMarkers)
                            Dim nwfldcode As String = fldcode.Replace("?BlockRefId", updtstr)
                            fld.SetFieldCode(nwfldcode)
                        End If
                        Dim occ As ObjectContextCollection = db.ObjectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES")
                        bref.UpgradeOpen()
                        bref.Annotative = AnnotativeStates.True
                        ObjectContexts.AddContext(bref, occ.CurrentContext)
                        tr.AddNewlyCreatedDBObject(attref, True)
                    End If
                Next
            Else
                If File.Exists(dwg) Then
                    Using oDB As New Database(True, False)
                        oDB.ReadDwgFile(dwg, IO.FileShare.Read, True, "")
                        Dim oBlockID As ObjectId = db.Insert(dwg, oDB, True)
                        Dim bref As New BlockReference(pt, oBlockID)
                        btblr.AppendEntity(bref)
                        tr.AddNewlyCreatedDBObject(bref, True)
                        Dim refbtr As BlockTableRecord = tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead)
                        Dim attent As Entity
                        For Each attid As ObjectId In refbtr
                            attent = tr.GetObject(attid, OpenMode.ForRead)
                            If TypeOf attent Is AttributeDefinition Then
                                Dim attdef As AttributeDefinition = attent
                                Dim attref As New AttributeReference()
                                attref.SetAttributeFromBlock(attdef, bref.BlockTransform)
                                Dim attrefid As ObjectId = bref.AttributeCollection.AppendAttribute(attref)
                                If attref.HasFields Then
                                    Dim dic As DBDictionary = tr.GetObject(attref.ExtensionDictionary, OpenMode.ForRead)
                                    Dim flddic As DBDictionary = tr.GetObject(dic.GetAt("ACAD_FIELD"), OpenMode.ForRead)
                                    Dim fld As Field = tr.GetObject(flddic.GetAt("TEXT"), OpenMode.ForWrite)
                                    Dim strid As String = bref.ObjectId.OldIdPtr.ToString()
                                    Dim updtstr As String = "%<\_ObjID " & strid & ">%"
                                    Dim fldcode As String = fld.GetFieldCode(FieldCodeFlags.AddMarkers)
                                    Dim nwfldcode As String = fldcode.Replace("?BlockRefId", updtstr)
                                    fld.SetFieldCode(nwfldcode)
                                End If
                                Dim occ As ObjectContextCollection = db.ObjectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES")
                                bref.UpgradeOpen()
                                bref.Annotative = AnnotativeStates.True
                                ObjectContexts.AddContext(bref, occ.CurrentContext)
                                tr.AddNewlyCreatedDBObject(attref, True)
                            End If
                        Next
                        If btbl.Has("") And Not btbl.Has(bln) Then
                            Dim bad As BlockTableRecord = tr.GetObject(btbl(""), OpenMode.ForWrite, True)
                            bad.Name = bln
                            bad.Dispose()
                        End If
                    End Using
                End If
            End If
            tr.Commit()
            ed.Regen()
        End Using
    End Sub

 

Active Contributor
JasonSelf
Posts: 35
Registered: ‎08-30-2010
Message 9 of 9 (1,231 Views)

Re: eNoDatabase with Inserting a block (vb.net)

09-08-2011 12:38 PM in reply to: RPeter

I think I have all working now, I realised that with moving between forms I needed to be smarter about using document locking.  So with that tidbit and the code and help you have all provided I am in good shape....This one has been a lesson, thanks.

 

-Jason

 

Hopefully, I won't need to come back to this thread again :smileyhappy:

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community