Jump to content
Alex_AMF

Retrieve AutoCAD Block Records from .NET WinForm

Recommended Posts

Alex_AMF

Hello,

 

My goal is to set up a batch printing on all AutoCAD drawings. Each drawing will have a record similar to this:

 

pmz53.jpg

 

The PartNo records underlined in red are other drawings that my recursive function will go through. That's why I must access this information. I believe I must access an object named "BLOCKNT" in order to do so but I'm unsure about the syntax.

 

FYI, for some reason, whenever I try to use this code:

ApplicationServices.Application.DocumentManager.MdiActiveDocument

 

I get the following error:

An unhandled exception of type 'System.IO.FileNotFoundException' occurred in Unknown Module.

Additional information: Could not load file or assembly 'acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

 

This is a .exe application and I have read that I cannot use NETLOAD commands in a .exe project? Does this make sense?

 

Thank you!

Alex

Edited by Alex_AMF

Share this post


Link to post
Share on other sites
BlackBox

Tabling the immense topic of printing drawings through batch processing for now, if you're using a stand alone EXE, then you should be accessing AutoCAD via COM, and not .NET API.

 

http://through-the-interface.typepad.com/through_the_interface/2010/02/handling-com-calls-rejected-by-autocad-from-an-external-net-application.html

 

 

 

Separately, hard to tell for sure as you've not posted your calling code, but seemingly your System.IO.FileNotFoundException results from attempting to pass the MdiActiveDocument Object to a System.IO.File.Exists() Method call (or the like), when you'd instead need to supply the qualified FilePath and FileName instead.

Share this post


Link to post
Share on other sites
Alex_AMF

I see ... I think the documentation of AutoCAD that I've been using is for .NET API. As for the calling code itself, here's what it looked like:

 

Private Sub ACAD()
    'The application crashes here and I receive the error posted above.
    GetBlockContents()
End Sub

Private Sub GetBlockContents()
    Dim test = Application.DocumentManager.MdiActiveDocument
End Sub

Share this post


Link to post
Share on other sites
BlackBox

Start here: My First Plug-in Training

 

Regardless of if you're adept at .NET development outside of AutoCAD, or if this is your first attempt at both, you need to better understand the nature of the .NET and COM APIs before your effort(s) will be successful.

 

 

 

** Note - Autodesk's .NET Documentation assumes a basic understanding of .NET Development concepts.

Share this post


Link to post
Share on other sites
Alex_AMF

Thank you. I'll look into that. I am pretty decent when it comes to .NET development outside of AutoCAD. Pretty new in the AutoCAD concept though. I've done some SolidEdge before but now I'm expanding on this.

 

Thanks again!

Share this post


Link to post
Share on other sites
BlackBox
Thank you. I'll look into that. I am pretty decent when it comes to .NET development outside of AutoCAD. Pretty new in the AutoCAD concept though. I've done some SolidEdge before but now I'm expanding on this.

 

Thanks again!

 

No worries; we all start somewhere... Methinks your prior .NET Development experience will come in handy very soon. You just need to familiarize yourself with the API Objects' Properties, Methods, and Events.

Share this post


Link to post
Share on other sites
Alex_AMF

I've learned quite a bit from going through those tutorials. I also checked out the site http://through-the-interface.typepad.com/ which had an insane amount of information.

 

I'm still pretty perplexed on how to retrieve the block records from a drawing. I'm not creating a plug-in, and it that the .NET API is loaded in my project even though I must only communicate with AutoCAD via the COM. I'm not sure which of these references is .NET because I thought I only took them from the COM tab:

AcDbMgd

AcMgd

AutoCAD

AXDBLib

 

Anyway, I'll try to advance my project further. I'll post the answer once I get it.

Share this post


Link to post
Share on other sites
fixo

Just for the quick example try this to open drawings multiple to read,

better yet to see Database.ReadDwg method though

Code:

 
        <CommandMethod("bah")> _
       Public Shared Sub BatchStart()
           Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("SDI", 0)
           Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor
           ' Get drawings to process
           Dim dwgsForm As New Autodesk.AutoCAD.Windows.OpenFileDialog("Drawings to Process", "", "dwg", "", Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.AllowMultiple)
           If dwgsForm.ShowDialog() <> Windows.Forms.DialogResult.OK Then
               Return
           End If
           Dim dwgfiles As String() = dwgsForm.GetFilenames()
           Using doclock As DocumentLock = doc.LockDocument()
               For i As Integer = 0 To dwgfiles.GetLength(0) - 1
                   Dim newdoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.Open(dwgfiles(i), False)
                   'your rest code to retrieve desired things from opened document here
                   '__________________________________________________'
                   ed.WriteMessage(vbLf & dwgfiles(i).ToString())
                   ' close doc without changes
                   newdoc.CloseAndDiscard()
               Next
           End Using
       End Sub

Share this post


Link to post
Share on other sites
BlackBox

You need to add references to the Interop assemblies for your application's target processing environment... As an example, these Interop assemblies can be found here in the ObjectARX 2014 SDK for 32-Bit, or 64-Bit respectively:

 

C:\Autodesk\ObjectARX 2014\inc-win32\Autodesk.AutoCAD.Interop.dll

 

C:\Autodesk\ObjectARX 2014\inc-x64\Autodesk.AutoCAD.Interop.dll

Share this post


Link to post
Share on other sites
Alex_AMF

Hello Fixo,

 

I've seen you post quite a bit on topics related to AutoCAD. Glad you came and helped me! Appreciate it. In any case, every time I seem to include the "MdiActiveDocument" portion with the document manager, my .exe program crashes and gives me the following error:

An unhandled exception of type 'System.IO.FileNotFoundException' occurred in Unknown Module.

Additional information: Could not load file or assembly 'acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

 

Thanks again

Share this post


Link to post
Share on other sites
BlackBox
Hello Fixo,

 

I've seen you post quite a bit on topics related to AutoCAD. Glad you came and helped me! Appreciate it. In any case, every time I seem to include the "MdiActiveDocument" portion with the document manager, my .exe program crashes and gives me the following error:

 

 

Thanks again

 

http://www.cadtutor.net/forum/showthread.php?71118-ThisDrawing-Property-with-AutoCAD-2013

Share this post


Link to post
Share on other sites
Alex_AMF
You need to add references to the Interop assemblies for your application's target processing environment... As an example, these Interop assemblies can be found here in the ObjectARX 2014 SDK for 32-Bit, or 64-Bit respectively:

 

C:\Autodesk\ObjectARX 2014\inc-win32\Autodesk.AutoCAD.Interop.dll

 

C:\Autodesk\ObjectARX 2014\inc-x64\Autodesk.AutoCAD.Interop.dll

 

Wouldn't this do the same?

Imports Autodesk.AutoCAD.Interop

 

I tried importing what you said (I have the ObjectARX 2010 though ...) and it said the namespace was ambiguous. Probably because I already had that code before? It only error'ed out when I imported the Autodesk.AutoCAD.Interop.dll

Share this post


Link to post
Share on other sites
BlackBox
Wouldn't this do the same?

Imports Autodesk.AutoCAD.Interop

 

I tried importing what you said (I have the ObjectARX 2010 though ...) and it said the namespace was ambiguous. Probably because I already had that code before? It only error'ed out when I imported the Autodesk.AutoCAD.Interop.dll

:facepalm:

 

The Interop assembly must be added as a reference to your solution, only then will your Imports statement (using in C#) be successful.

 

 

 

Additional info you may find helpful: http://forums.autodesk.com/t5/NET/how-to-access-AutoCAD-2012-from-Vb-net-Standard-Exe/td-p/3363237

Share this post


Link to post
Share on other sites
Alex_AMF

Derp. XD Thank you haha I'll try that out.

Share this post


Link to post
Share on other sites
BlackBox
Derp. XD Thank you haha I'll try that out.

 

No worries :beer:.... Check out this thread: VB.NET - Open an Existing Dwg from Stand-Alone exe

 

... Bill and I went back and forth here at CADTutor and there over a few weeks, there's plenty of related threads by us on this small litany of topics, given the related threads a look.

Share this post


Link to post
Share on other sites
BlackBox
Just for the quick example try this to open drawings multiple to read,

better yet to see Database.ReadDwg method though

 

Hi Fixo, I get now that you were just posting some sample code for the OP to pull from (I removed my earlier post), but I did want to ask about ReadDwg... Is that relegated to plug-in, or can stand alone EXE also use ReadDwg?

 

Separately, can one print via ReadDwg (i.e., side Database)?

 

TIA

Share this post


Link to post
Share on other sites
fixo

No You could not use ReadDwdgFile in side database, just using API,say

for example get tables from multiple files and write to csv

 

 
Public Function GetDirectoryDrawings(directoryFullName As String, subDirsBrowse As Boolean) As List(Of FileInfo)
           Dim dir As New DirectoryInfo(directoryFullName)
           If Not dir.Exists Then
               Throw New DirectoryNotFoundException()
               Return Nothing
           End If
           Dim opt As SearchOption = SearchOption.AllDirectories
           If subDirsBrowse = False Then opt = SearchOption.TopDirectoryOnly
           Return dir.GetFiles("*dwg", opt).AsEnumerable().OrderBy(Function(x) x.FullName).ToList()
       End Function

       <CommandMethod("wtb", CommandFlags.Session)> _
       Public Sub testDirFiles()
           Dim folder As String = "C:\Test\"
           Dim csvfile As String = "C:\Test\atable.csv"
           Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
           Dim db As Database = doc.Database
           Dim ed As Editor = doc.Editor
           Dim fd As List(Of FileInfo) = GetDirectoryDrawings(folder, False) ''     True for processing the subdirectories
           Dim collect As New StringBuilder
           If fd.Count = 0 Then Return

           Try
               Using doclock As DocumentLock = doc.LockDocument()
                   For n As Integer = 0 To fd.Count - 1
                       Dim dwgname As String = fd(n).FullName
                       Using newdb As Database = New Database(False, True)
                           ed.WriteMessage(vbLf + dwgname + vbLf)
                           Try
                               newdb.ReadDwgFile(dwgname, FileOpenMode.OpenForReadAndAllShare, False, Nothing)
                           Catch ex As Autodesk.AutoCAD.Runtime.Exception
                               If ex.ErrorStatus = ErrorStatus.DwgNeedsRecovery Then
                                   Continue For
                               End If
                           End Try

                           Using newtr As Transaction = newdb.TransactionManager.StartTransaction
                               ' Open dictionary for reading 
                               Dim layoutDict As DBDictionary = DirectCast(newtr.GetObject(newdb.LayoutDictionaryId, OpenMode.ForRead), DBDictionary)
                               ' Loop through dictionary entries
                               For Each entry As DictionaryEntry In layoutDict
                                   Dim ltr As Layout = DirectCast(newtr.GetObject(DirectCast(entry.Value, ObjectId), OpenMode.ForRead), Layout)
                                   Dim btr As BlockTableRecord = DirectCast(newtr.GetObject(ltr.BlockTableRecordId, OpenMode.ForRead), BlockTableRecord)
                                   For Each id As ObjectId In btr
                                       Dim obj As DBObject = DirectCast(newtr.GetObject(id, OpenMode.ForRead), DBObject)
                                       If TypeOf obj Is Table Then
                                           Dim tbl As Table = TryCast(obj, Table)
                                           If tbl IsNot Nothing Then
                                               collect.AppendLine(String.Format("---------------------------------------"))
                                               collect.AppendLine(String.Format("Drawing name: {0}", dwgname))
                                               collect.AppendLine(String.Format("Tab: {0}", ltr.LayoutName))
                                               Dim numrows As Integer = tbl.Rows.Count
                                               Dim numcols As Integer = tbl.Columns.Count
                                               For i As Integer = 0 To numrows - 1
                                                   Dim rowline As New List(Of String)
                                                   Dim line As String = String.Empty
                                                   For j = 0 To numcols - 1
                                                       Dim cel As Cell = tbl.Cells(i, j)
                                                       rowline.Add(cel.TextString)
                                                       line = line + cel.TextString + vbTab
                                                   Next
                                                   collect.AppendLine(line.TrimEnd(vbTab))
                                               Next
                                           End If
                                       End If
                                   Next
                               Next
                               newtr.Commit()
                           End Using
                       End Using
                   Next
               End Using
               WriteTableToFile(csvfile, collect)
           Catch ex As System.Exception
               ed.WriteMessage(vbLf + ex.ToString + vbLf)
           Finally
               ed.WriteMessage(vbLf + vbTab + "--->   File saved as: {0}   <---" + vbLf, csvfile)
           End Try
       End Sub

       Public Sub WriteTableToFile(fpath As String, data As StringBuilder)
           'If Not (File.Exists(fpath)) Then
           '    Using frs As New FileStream(fpath, FileMode.Create)
           '        frs.Flush()
           '    End Using
           'End If
           Using fs As New FileStream(fpath, FileMode.Append, FileAccess.Write)
               Using sw As New StreamWriter(fs, Encoding.ASCII)
                   sw.WriteLine(data.ToString)
               End Using
           End Using
       End Sub

Share this post


Link to post
Share on other sites
Alex_AMF

 

After reading the URLs you've provided, I came to a conclusion that I do not need the AcDbMgd.dll and AcMgd.dll files since those are used for Internal AutoCAD applications whilst I'm using an outside executable to gather information from AutoCAD. Here's how my project looks:

 

References

ztg1w3.png

 

Imports

vq4k5u.png

 

Variable declarations (my problem at the moment)

54ynoh.png

 

I referenced it correctly ... No? :(

Share this post


Link to post
Share on other sites
fixo

Try change on this:

 
Public vAcadApp as Autodesk.AutoCAD.Interop.AcadApplication
Public vAcadDoc as Autodesk.AutoCAD.Interop.AcadDocument

ETC

Share this post


Link to post
Share on other sites
Alex_AMF
Try change on this:

 
Public vAcadApp as Autodesk.AutoCAD.Interop.AcadApplication
Public vAcadDoc as Autodesk.AutoCAD.Interop.AcadDocument

ETC

 

That was my initial move and I also thought it was going to work. Oddly enough, it still tells me it is ambiguous :shock:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...