hands on introduction to v.net add ins for autoad sd197926
TRANSCRIPT
Page 1
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
SD197926-L
Hands-on Introduction to VB.NET Add-Ins for AutoCAD - SD197926-L
Speaker
Jerry Winters, VB CAD, Inc.,
Lab Assistants
Karl Hill, Alaska Native Tribal Health Consortium, IT Manager/CAD Equipment Manager
James Johnson, Synergis Technologies LLC Sr. Application Developer
Gyorgy Ordody, Autodesk, Inc Software Engineer
Learning Objectives
• Learn how to create a new AutoCAD add-in in VB.NET
• Learn how to create a new AutoCAD command in VB.NET
• Learn the basics of drawing in AutoCAD through the .NET API
• Learn how to extract block and attribute information through the .NET API
Lab Description
Knowing how to write AutoCAD add-ins lets us create new AutoCAD commands that automate routine tasks, perform complex cal-
culations, or integrate multiple systems to help us be more productive, more precise, and more effective. The use of Microsoft's
free Visual Studio Community together with the information presented in this class will help anyone immediately begin creating
AutoCAD add-ins with VB.NET.
Speaker Bio
Page 2
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
First Things First
We will be using Visual Studio 2017 Community Edition during this Lab. This can be downloaded from the page with the URL:
https://visualstudio.microsoft.com/vs/community/
The download will be a 1.2 MB file. When this file is executed, it will download and install Visual Studio Community Edition.
During the installation process, you may be asked for your preferred language. If you are asked this, select “Visual Basic”.
Page 3
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Learn how to create a new AutoCAD add-in in VB.NET
This first step we work on is the most difficult, complex, challenging thing we will do during this lab. This is not
intended to scare you but to prepare you. There are very specific steps that need to be followed and if we
leave even one of these steps out we will not be able to do anything else.
Pre-requisites
• Visual Studio 2017 Community Edition is installed
• AutoCAD 2019 is installed
Here are the steps to creating a new AutoCAD Add-In in VB.NET:
1. Start Visual Studio
Create a New VB.NET Class Library Project
Add References to the following files: accoremgd.dll, acdbmgd.dll, acmgd.dll
Set the acad.exe file as the Debug Startup Application
Write amazing, fantastic, mind-blowing code
We will go through steps 1-4 multiple times because if we return home after attending Autodesk University
and can not create a new Add-In for AutoCAD, well, that would not be good.
1. Start Visual Studio
After installing Visual Studio, you will be able to start Visual Studio just as
you do any other application in Windows. If you plan on writing AutoCAD
Add-Ins on a regular basis, you may want to pin Visual Studio to your Task
Bar.
Page 4
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
2. Create a New VB.NET Class Library Project
In Visual Studio, go to the menu and click File -> New -> Project.
Now we need to select the type of project we want to create. There are 5 things we need to do here. First,
make sure the Visual Basic—Windows Desktop node is selected in the Tree (on the left). Second, select
“Class Library (.NET Framework)” is selected. Third, give the project a Name. Fourth, uncheck the “Create
directory” checkbox. Fifth, set the Framework to “.NET Framework 4.7”
Pay attention to the “Location” setting.
Page 5
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
3. Add References to the following files:
accoremgd.dll, acdbmgd.dll, acmgd.dll
We do this by going to the menu. Project -> Add
Reference
Page 6
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Click on “Browse” in the left-hand side list, then the “Browse” button.
Browse to the path, “C:\Program Files\Autodesk\AutoCAD 2019”
Next, in the File name combobox, type “ac*mgd.dll” and hit Enter
This filter reduces the number of files that show up in the list. We are looking for 3 files: accoremgd,dll,
acdbmgd.dll, and acmgd.dll
Page 7
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
After selecting the 3 magic .dll files, click on the “Add” button.
Next, click the “OK” button.
What did we just do? By adding References to these 3 DLLs, we added their capabilities to our program.
These DLLs are used to speak to AutoCAD, to ModelSpace, PaperSpace, they have the definitions of Lines,
Circles, Arcs, etc.
Page 8
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
4. Set the acad.exe file as the Debug Startup Application
Without doing anything else, we could jump right in and
start writing code. However, if we perform Step 4, we can
debug our code while AutoCAD is running which will help
us be much more productive.
Go to the menu Project -> Program A Properties
Click on the Debug tab.
Click the “Start external program” button, then either type
or browse to:
“C:\Program Files\Autodesk\AutoCAD 2019\acad.exe”.
Page 9
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Step 5 is to write amazing code. We’ll do plenty of code writing in a little while. Before we do that, let’s try
compiling and loading our application. This is done by clicking on the “Start” button.
If we set up the Startup Application correctly (from Step 4), clicking the “Start” button will start AutoCAD for
us. When this happens, we’ll start a new Drawing.
Page 10
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
When we click the “Start” button, here’s what happens in the background:
• Visual Studio saves all the files in the project.
• Visual Studio compiles the project into a .dll file.
• Visual Studio starts the program in the “Start external program” Debug page.
• A ‘link’ between Visual Studio and AutoCAD is created so Visual Studio ‘listens’ to what is happening in-
side AutoCAD.
Now, our code is compiled and AutoCAD is started. The next step is to have AutoCAD load our .NET Add-In.
Netload is the command we run to load our
program into AutoCAD. When we run
“Netload”, we browse to the directory where
the .dll is compiled into. Where is that, you
ask? What a great question.
When we created our project, the “Location” was put in for us by Visual Studio. It may or may not match what
we see below. But the important thing is that we take note of the Location because based on our settings
here, the path we want to browse to right now is:
C:\Users\JerryWinters\source\repos\ProgramA\bin\debug
Page 11
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Once we are in the correct directory, we want to select our DLL.
Page 12
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Now, if we have all of our steps completed correctly, after we select our DLL and click the “Open” button, we
will be taken back to AutoCAD.
Now, what do we do? Nothing. We didn't write any code so there’s nothing to do. Let’s close AutoCAD now.
That may seem like we didn't accomplish very much but that’s not the case. Here’s what we just did:
1. Start Visual Studio
Create a New VB.NET Class Library Project
Add References to the following files: accoremgd.dll, acdbmgd.dll, acmgd.dll
Set the acad.exe file as the Debug Startup Application
Started the debugging process
Netloaded our application.
If we can go through those steps a few more times during this Lab, we will be able to create a new project
when we get back home and are ready write amazing, incredible code.
Page 13
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Learn how to create a new AutoCAD command in VB.NET
Here’s code you can copy and paste into your Visual Studio project:
<Autodesk.AutoCAD.Runtime.CommandMethod("RunMe")>
Public Sub RunMe()
MsgBox("I hope this works.")
End Sub
Let’s talk about what this does.
<Autodesk.AutoCAD.Runtime.CommandMethod("RunMe")>
This code is used to define a new command in AutoCAD. The command name is “RunMe”. It is placed
directly above a Public Sub statement.
Public Sub RunMe()
This line tells Visual Studio that we are beginning a new procedure named “RunMe”. You may notice the
name of the Sub is the same as the name of the CommandMethod. This does not have to be the case but my
personal preference is to have them named the same.
MsgBox("I hope this works.")
This line is used to display a MessageBox with the text “I hope this works” in it.
End Sub
This line closed the procedure named “RunMe”. The code between “Sub” and “End Sub” runs line by line
when the “RunMe” command is run.
Page 14
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Let’s try debugging our program again. We are going to do this by clicking the “Start” button again.
Next, let’s start a new AutoCAD drawing.
Then use the Netload command and select your .DLL.
Now that we have defined a new AutoCAD command, we can run it by typing “RunMe” at the command line.
I really hope the program works on your computer. If it does, you will see a message box as shown above.
Now, before we close down AutoCAD, let’s see if we can debug our program.
Switch back over to Visual Studio and click in the grey column on line 4. This is called adding a “Breakpoint”.
Page 15
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Now, switch back over to AutoCAD and run the “RunMe” command again. What should happen is AutoCAD
should pass the code execution over to the Stop we created on Line 4.
The line of code highlighted yellow is the next line of code that will be run.
Hit the F11 button on the keyboard. This will run the line of code highlighted yellow.
There’s our MessagBox. After we click the “OK” button, we are taken back to
Visual Studio on Line 5.
Now that we are successfully debugging, let’s make a little change to our code. After all, the code does work.
Right?
Page 16
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Let’s change the MessageBox from “I hope this works.” to “I’m glad this works.”.
Now, remember, the line highlighted yellow is the next line to run. And while it’s true our wonderful command
only has one line of code inside it, this will not always be the case. You will notice the yellow arrow in the gray
column.
Let’s click and drag the yellow arrow from Line 5 up back to Line 4.
Now if we hit the F11 button again, Line 4 will be executed but with the new message.
Page 17
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Now, think about what just happened. We started the Debug process by
clicking the Start button. After netloading our application, we ran our
awesome command, “RunMe”. Since we added a Breakpoint, the
command’s execution jumped back over to Visual Studio. Once there we
were able to step through our code by using the F11 key on the keyboard.
We also modified our code and dragged the execution cursor back up to the
new code and ran it again by using the F11 key.
The better we get at the debugging process, the more efficient we become at
writing code. It takes time for Visual Studio to compile our code. And it takes
time to start AutoCAD. And it takes time to start a new Drawing. And it takes
time to Netload our application. If we add a breakpoint, we can modify our
code and try running it again without taking all of that time just discussed.
Dragging and dropping a little yellow arrow may work in some situations. But more often than not, there is a
better way to move execution to a different line.
If we Right-Click on the line of code we want to move execution to, one of the options is “Set Next
Statement”. Clicking on this is far more accurate than dragging and dropping a little arrow.
Page 18
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Learn the basics of drawing in AutoCAD through the .NET API
If we were to start AutoCAD and want to draw a line, we might click on an icon to start the “Line” command.
Then we would click in ModelSpace to select the line’s Start Point. Then we may click somewhere else in
ModelSpace to specify the line’s End Point. Then magically, a line would appear in ModelSpace. That’s what
most of us see in AutoCAD over and over and over again. But there’s more going on than what we see.
Here’s what’s going on ‘under the hood’:
1. A new Transaction is started for the current file under which all of the following actions take place.
2. ModelSpace is Opened “For Write” because a new line is going to be added to ModelSpace.
3. The first point is selected in ModelSpace.
4. Then a second point is selected while we see a ‘rubber band’ between the first point and the cursor.
5. Next, a new Line Entity is created using the selected points.
6. The Line is appended to ModelSpace.
7. The Line is added to the Transaction.
8. The Transaction is committed.
Before we look at the code, we need to add the following at the very top of the Class file.
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.ApplicationServices.Application
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Here’s the code:
<Autodesk.AutoCAD.Runtime.CommandMethod("DrawLine")>
Public Sub DrawLine()
Dim myDoc As Document = DocumentManager.MdiActiveDocument
Dim myDB As Database = myDoc.Database
Dim myEditor As Editor = myDoc.Editor
Using myTrans As Transaction = myDoc.TransactionManager.StartTransaction
Dim myBTR As BlockTableRecord = myDB.CurrentSpaceId.GetObject(OpenMode.ForWrite)
Dim startPoint As Point3d = myEditor.GetPoint("Select Start Point:").Value
Dim myPPO As New PromptPointOptions("Select End Point:")
myPPO.BasePoint = startPoint
myPPO.UseBasePoint = True
Dim endPoint As Point3d = myEditor.GetPoint(myPPO).Value
Dim myLine As New Line(startPoint, endPoint)
myBTR.AppendEntity(myLine)
myTrans.AddNewlyCreatedDBObject(myLine, True)
myTrans.Commit()
End Using
End Sub
Let’s copy and paste this code from the handout into our project. Then let’s add a Breakpoint, begin
debugging, run the command, and step through the code line by line.
Page 19
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Here’s another command to take a look at:
<Autodesk.AutoCAD.Runtime.CommandMethod("DrawGrid")>
Public Sub DrawGrid()
Dim myDoc As Document = DocumentManager.MdiActiveDocument
Dim myDB As Database = myDoc.Database
Dim myEditor As Editor = myDoc.Editor
Using myTrans As Transaction = myDoc.TransactionManager.StartTransaction
Dim myBTR As BlockTableRecord = myDB.CurrentSpaceId.GetObject(OpenMode.ForWrite)
For X As Double = 0 To 10 Step 0.5
For Y As Double = 0 To 10 Step 0.5
Dim startPoint As New Point3d(X, 0, 0)
Dim endPoint As New Point3d(X, 10, 0)
Dim myLine As New Line(startPoint, endPoint)
myBTR.AppendEntity(myLine)
myTrans.AddNewlyCreatedDBObject(myLine, True)
startPoint = New Point3d(0, Y, 0)
endPoint = New Point3d(10, Y, 0)
myLine = New Line(startPoint, endPoint)
myBTR.AppendEntity(myLine)
myTrans.AddNewlyCreatedDBObject(myLine, True)
Next
Next
myTrans.Commit()
End Using
End Sub
The result of this code is a 10x10 grid with 0.5 increments.
Let’s take a look at a little more code. First we will add a Function named “DrawLineFunction”. Then we will
create a new Command named “DrawLineTest”. Notice how the DrawLineFunction allows us to specify X, Y,
and Z values for both the Start and End points. Then “DrawLineTest” calls “DrawLineFunction” repeatedly.
Page 20
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Public Function DrawLineFunction(Xs As Double, Ys As Double, Zs As Double,
Xe As Double, Ye As Double, Ze As Double) As ObjectId
Dim myDoc As Document = DocumentManager.MdiActiveDocument
Dim myDB As Database = myDoc.Database
Using myTrans As Transaction = myDoc.TransactionManager.StartTransaction
Dim myBTR As BlockTableRecord = myDB.CurrentSpaceId.GetObject(OpenMode.ForWrite)
Dim startPoint As New Point3d(Xs, Ys, Zs)
Dim endPoint As New Point3d(Xe, Ye, Ze)
Dim myLine As New Line(startPoint, endPoint)
myBTR.AppendEntity(myLine)
myTrans.AddNewlyCreatedDBObject(myLine, True)
myTrans.Commit()
Return myLine.ObjectId
End Using
End Function
<Autodesk.AutoCAD.Runtime.CommandMethod("DrawLineTest")>
Public Sub DrawLineTest()
'draw square first
DrawLineFunction(0, 0, 0, 4, 0, 0)
DrawLineFunction(4, 0, 0, 4, 4, 0)
DrawLineFunction(4, 4, 0, 0, 4, 0)
DrawLineFunction(0, 4, 0, 0, 0, 0)
'now draw corner to corner
DrawLineFunction(0, 0, 0, 4, 4, 0)
DrawLineFunction(0, 4, 0, 4, 0, 0)
End Sub
If we create a Function like “DrawLineFunction” we can call it whenever we need to create a Line and we will
be more productive and our code will be easier to maintain.
Page 21
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Learn how to extract block and attribute information through the .NET API
Block attribute extraction is a very common requirement in AutoCAD Add-Ins. Before we jump into the code
to do this we need to discuss how Blocks, Block References, and Attributes are stored in an AutoCAD .dwg
file.
The Database
The first thing we need to understand is that an AutoCAD .dwg file is a database. And this database is
organized into Tables and Records.
Layers are in a Table called “LayerTable” with records called “LayerTableRecord”.
TextStyles are in a Table called “TextStyleTable” with records called “TextStyleTableRecord”.
Blocks are in a Table called “BlockTable” with records called “BlockTableRecord”.
Let’s take a look at this code:
Public Function GetAllBlockTableRecords() As List(Of String)
Dim myDB As Database = HostApplicationServices.WorkingDatabase
Dim retList As New List(Of String)
Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
Dim myBT As BlockTable = myDB.BlockTableId.GetObject(OpenMode.ForRead)
For Each myBTRid As ObjectId In myBT
Dim myBTR As BlockTableRecord = myBTRid.GetObject(OpenMode.ForRead)
retList.Add(myBTR.Name)
Next
End Using
Return retList
End Function
You will notice a few things.
• We are using a variable named “myDB” and it is being assigned to the WorkingDatabase
(the current file open in AutoCAD).
• Before we read or write from/to an AutoCAD Database we always open a Transaction.
• Since we are Reading from the database we open the BlockTable “ForRead”. Objects in
AutoCAD are opened through their Object IDs.
• We want to look at each ‘record’ inside the BlockTable. We use a For Each loop to do
this. When we loop through the BlockTable, we are given an ObjectID that belongs to a
BlockTableRecord.
• We declare a variable as a BlockTableRecord and get that through its ObjectID.
• In this example we are adding the Name of the BlockTableRecord to a List.
Page 22
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Here’s some code that will use the Function we just looked at on the prior page:
<Autodesk.AutoCAD.Runtime.CommandMethod("GetBTRNames")>
Public Sub GetBTRNames()
For Each myBName As String In GetAllBlockTableRecords()
MsgBox(myBName)
Next
End Sub
If we run this code on a totally new AutoCAD drawing, we will see the following:
If you are familiar with AutoCAD, these names may look like something familiar.
ModelSpace is a BlockTableRecord in an AutoCAD Database.
PaperSpace Layouts are BlockTableRecords in an AutoCAD Database.
If I draw a dimension in my new AutoCAD drawing and run this same command again, we
will see this:
Dimensions are BlockTableRecords in an AutoCAD Database.
XRefs are BlockTableRecords in an AutoCAD Database.
And, as you may have guessed, Blocks are BlockTableRecords in an AutoCAD Database.
Go to this page:
https://knowledge.autodesk.com/support/autocad/downloads/caas/downloads/content/autocad-sample-files.html
Download one of the “Blocks and Tables” dwg files and open it in AutoCAD. If we run this same
GetBTRNames command we will see
Page 23
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Now we can see some actual ‘Blocks’ such as “Lighting Fixture”, “Label”, “ARCHBDR-D”, and “Window”.
Then we see something like “*B5”. What’s that about?
There was a time when we used to create Blocks in AutoCAD and insert them. For example, we may create a
Window Block that was for a 3’0” x 5’-0” window. We may have named it “Window 36x60”. Then we may have
added attributes to that Block for the Manufacturer, Supplier, Cost, etc. Then one magical day, Autodesk
introduced “Dynamic Blocks”. Dynamic Blocks are amazing. But they introduce a challenge or two when it
comes time to extract Blocks. Each time a Dynamic Block is inserted into AutoCAD and then ‘Dynamicized’, a
new BlockTableRecord is created called “*B1”, then “*B2” and so on. While we are not going to spend a great
deal of time discussing Dynamic Blocks, it was worth mentioning.
OK. Let’s get down to Block and Attribute Extraction.
Block Extraction
We are going to make a few assumptions here for a few minutes. First off, we are going to be extracting
Blocks from ModelSpace in an AutoCAD file. We are going to copy and past the following Function into our
Add-In:
Public Function GetBlockReferencesInModelSpace(DBin As Database) _
As Dictionary(Of String, List(Of ObjectId))
Dim retVal As New Dictionary(Of String, List(Of ObjectId))
Using myTrans As Transaction = DBin.TransactionManager.StartTransaction
Dim myBT As BlockTable = DBin.BlockTableId.GetObject(OpenMode.ForRead)
Dim myBTR As BlockTableRecord =
myBT(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)
For Each myEntID As ObjectId In myBTR
If myEntID.ObjectClass.DxfName = "INSERT" Then
Dim myBRef As BlockReference = myEntID.GetObject(OpenMode.ForRead)
If myBRef.Name.StartsWith("*") Then
Dim parentBTR As BlockTableRecord =
myBRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)
If retVal.ContainsKey(parentBTR.Name) = False Then
retVal.Add(parentBTR.Name, New List(Of ObjectId))
End If
retVal(parentBTR.Name).Add(myEntID)
Else
If retVal.ContainsKey(myBRef.Name) = False Then
retVal.Add(myBRef.Name, New List(Of ObjectId)) End If retVal(myBRef.Name).Add(myEntID) End If End If Next myTrans.Commit() End Using Return retVal End Function
Page 24
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
This Function gets all of the Block References in an AutoCAD Drawing and returns them in a Dictionary.
Dictionaries are storage containers that have a Key and a Value. In this instance, the Dictionary’s Key is the
Block Name. The Value is a List of ObjectID Objects. It ‘looks’ something like this:
Window
ObjectIDa
ObjectIDb
ObjectIDc
Receptacle
ObjectIDd
ObjectIDe
ObjectIDf
ObjectIDg
Light
ObjectIDh
ObjectIDi
With this structure, we can look into the Dictionary and pull out whichever block we want to access.
<Autodesk.AutoCAD.Runtime.CommandMethod("WriteBlocksOut")>
Public Sub WriteBlocksOut()
Dim myDB As Database = HostApplicationServices.WorkingDatabase
Dim myBlocks As Dictionary(Of String, List(Of ObjectId)) =
GetBlockReferencesInModelSpace(myDB)
For Each myKVP As KeyValuePair(Of String, List(Of ObjectId)) In myBlocks
If myKVP.Key.ToUpper = "WINDOW" Then
Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
Dim myDesktop As String =
My.Computer.FileSystem.SpecialDirectories.Desktop
Dim myOutput As New IO.StreamWriter(IO.Path.Combine(myDesktop,
"Windows.txt"))
For Each myOID As ObjectId In myKVP.Value
Dim myBRef As BlockReference = myOID.GetObject(OpenMode.ForRead)
myOutput.WriteLine(DateTime.Now.ToString & vbTab &
myKVP.Key & vbTab &
myBRef.Position.X & vbTab &
myBRef.Position.Y & vbTab &
myBRef.Position.Z & vbTab &
myBRef.ScaleFactors.X & vbTab &
myBRef.Rotation) Next myOutput.Close() End Using End If Next End Sub We will discuss this code in detail during the Lab. If we run this code, a file named “Windows.txt” is created on
our Desktop.
Page 25
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
There’s the output. Of course, there’s a lot more we could put out. And we could format it differently. But let’s
get some Attributes out first. Then we’ll take a look at other options.
Here’s the magic code that will write the Attributes out.
For Each myAttID As ObjectId In myBRef.AttributeCollection
Dim myAtt As AttributeReference =
myAttID.GetObject(OpenMode.ForRead)
myOutput.WriteLine(vbTab & myAtt.Tag & vbTab & myAtt.TextString)
Next
We are going to copy and paste ‘WriteBlocksOut” and create a new Command named
“WriteBlocksAndAttributesOut”.
Page 26
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
<Autodesk.AutoCAD.Runtime.CommandMethod("WriteBlocksAndAttributesOut")>
Public Sub WriteBlocksAndAttributesOut()
Dim myDB As Database = HostApplicationServices.WorkingDatabase
Dim myBlocks As Dictionary(Of String, List(Of ObjectId)) =
GetBlockReferencesInModelSpace(myDB)
For Each myKVP As KeyValuePair(Of String, List(Of ObjectId)) In myBlocks
If myKVP.Key.ToUpper = "WINDOW" Then
Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
Dim myDesktop As String = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim myOutput As New IO.StreamWriter(IO.Path.Combine(myDesktop, "WindowsAtts.txt"))
For Each myOID As ObjectId In myKVP.Value
Dim myBRef As BlockReference = myOID.GetObject(OpenMode.ForRead)
myOutput.WriteLine(DateTime.Now.ToString & vbTab &
myKVP.Key & vbTab &
myBRef.Position.X & vbTab &
myBRef.Position.Y & vbTab &
myBRef.Position.Z & vbTab &
myBRef.ScaleFactors.X & vbTab &
myBRef.Rotation)
For Each myAttID As ObjectId In myBRef.AttributeCollection
Dim myAtt As AttributeReference =
myAttID.GetObject(OpenMode.ForRead)
myOutput.WriteLine(vbTab & myAtt.Tag & vbTab & myAtt.TextString)
Next
Next
myOutput.Close()
End Using
End If
Next
End Sub
Here’s the output generated by this code:
Page 27
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Extra Content
It is always difficult to determine how long it will take for a group to work through a tutorial. In the event we
have enough time to continue, we’ll work through this section as well:
Let’s write our Blocks and Attributes out to Excel:
<Autodesk.AutoCAD.Runtime.CommandMethod("WriteBlocksAndAttributesOutToExcel")>
Public Sub WriteBlocksAndAttributesOutToExcel()
Dim myDB As Database = HostApplicationServices.WorkingDatabase
Dim myBlocks As Dictionary(Of String, List(Of ObjectId)) =
GetBlockReferencesInModelSpace(myDB)
For Each myKVP As KeyValuePair(Of String, List(Of ObjectId)) In myBlocks
If myKVP.Key.ToUpper = "WINDOW" Then
Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
Dim myDesktop As String = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim myExcel As Object = CreateObject("Excel.Application")
myExcel.Visible = True
Dim myWB As Object = myExcel.Workbooks.Add
Dim curRow As Integer = 1
For Each myOID As ObjectId In myKVP.Value
Dim myBRef As BlockReference = myOID.GetObject(OpenMode.ForRead)
myExcel.ActiveSheet.Cells(curRow, "A").value = DateTime.Now.ToString
myExcel.ActiveSheet.Cells(curRow, "B").value = myKVP.Key
myExcel.ActiveSheet.Cells(curRow, "C").value = myBRef.Position.X
myExcel.ActiveSheet.Cells(curRow, "D").value = myBRef.Position.Y
myExcel.ActiveSheet.Cells(curRow, "E").value = myBRef.Position.Z
myExcel.ActiveSheet.Cells(curRow, "F").value = myBRef.ScaleFactors.X
myExcel.ActiveSheet.Cells(curRow, "G").value = myBRef.Rotation
curRow += 1
For Each myAttID As ObjectId In myBRef.AttributeCollection
Dim myAtt As AttributeReference =
myAttID.GetObject(OpenMode.ForRead)
myExcel.ActiveSheet.Cells(curRow, "B").value = myAtt.Tag
myExcel.ActiveSheet.Cells(curRow, "C").value = myAtt.TextString
curRow += 1 Next Next myWB.SaveAs(IO.Path.Combine(myDesktop, "WindowsAtts.xlsx")) myWB = Nothing myExcel = Nothing End Using End If Next End Sub
Now, I understand this is an Introductory Lab. No one would expect anyone else to understand each and
every line of code here. However, if I were to ask you to put the Rotation in column “H” instead of column “G”,
my guess is that you would be able to find that and make that change.
As always, we will add a BreakPoint in our code so when it runs we can stop it and step through it.
By the way, this code assumes Microsoft Excel is installed on the machine it is run on.
Page 28
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
Here’s the output in Excel. It should look very similar to
the output in the .txt file we created.
More Extra Content
Let’s look at this one line of code. You will find it at the top of the “GetBlockReferencesInModelSpace” Func-
tion:
Public Function GetBlockReferencesInModelSpace(DBin As Database) _
As Dictionary(Of String, List(Of ObjectId))
This function has been used by a few of our commands thus far. If we break down this declaration’s individual
parts we would find the following:
Public Function—This is Public so it can be called by other pieces of code even outside of the Class in
which this Function resides. It is a Function which means it will be returning some sort of value for us.
GetBlockReferencesInModelSpace—This is the name of the Function.
(DBin As Database)—This Function has one Parameter. It wants a Database Object.
As Dictionary(Of String, List(Of ObjectId))—If we ask for it, this Function will return a Dictionary with a
String for the Key and a List of ObjectIDs as the value.
It may seem a little late in the game to be digging into the anatomy of a Function Call. But there’s a reason
why we’re doing it now.
(DBin As Database)
This Function asks for a Database. If we can give it a Database, it can give us the return value. In the exam-
ples we have worked with thus far, we have been giving it the “WorkingDatabase” which is the database of
the document currently in focus in AutoCAD. But it doesn’t have to be the WorkingDatabase.
Page 29
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
VERY IMPORTANT STEP WARNING:
Before we continue, we need to add a new Windows Form to our Project.
The name of the Form is not
important for this example. Go
ahead and click the “Add” button.
We added the Form to our Project for 1 reason only. It’s one of the easiest ways to get a Reference to the
System.Windows.Forms namespace.. And we need that for what we’re about to do.
This is an Introductory Tutorial. IF we can squeeze it in, I would like to introduce you to the power of VB.NET.
Page 30
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
<Autodesk.AutoCAD.Runtime.CommandMethod("WriteBlocksAndAttributesOutToExcel3")>
Public Sub WriteBlocksAndAttributesOutToExcel3()
Dim myOFD As New System.Windows.Forms.OpenFileDialog()
myOFD.Multiselect = True
myOFD.Filter = "AutoCAD Drawing (*.dwg)|*.dwg"
If myOFD.ShowDialog = System.Windows.Forms.DialogResult.OK Then
Dim myExcel As Object = CreateObject("Excel.Application")
myExcel.Visible = True
Dim myWB As Object = myExcel.Workbooks.Add
Dim myDesktop As String = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim curRow As Integer = 1
For Each myFileName As String In myOFD.FileNames
Dim myDB As New Database(False, True)
myDB.ReadDwgFile(myOFD.FileName, FileOpenMode.OpenForReadAndAllShare, False, "")
Dim myBlocks As Dictionary(Of String, List(Of ObjectId)) =
GetBlockReferencesInModelSpace(myDB)
For Each myKVP As KeyValuePair(Of String, List(Of ObjectId)) In myBlocks
Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
For Each myOID As ObjectId In myKVP.Value
Dim myBRef As BlockReference = myOID.GetObject(OpenMode.ForRead)
myExcel.ActiveSheet.Cells(curRow, "A").value = DateTime.Now.ToString
myExcel.ActiveSheet.Cells(curRow, "B").value = myFileName
myExcel.ActiveSheet.Cells(curRow, "C").value = myKVP.Key
myExcel.ActiveSheet.Cells(curRow, "D").value = myBRef.Position.X
myExcel.ActiveSheet.Cells(curRow, "E").value = myBRef.Position.Y
myExcel.ActiveSheet.Cells(curRow, "F").value = myBRef.Position.Z
myExcel.ActiveSheet.Cells(curRow, "G").value = myBRef.ScaleFactors.X
myExcel.ActiveSheet.Cells(curRow, "H").value = myBRef.Rotation
curRow += 1
For Each myAttID As ObjectId In myBRef.AttributeCollection
Dim myAtt As AttributeReference =
myAttID.GetObject(OpenMode.ForRead)
myExcel.ActiveSheet.Cells(curRow, "C").value = myAtt.Tag
myExcel.ActiveSheet.Cells(curRow, "D").value = myAtt.TextString curRow += 1 Next Next End Using Next myDB.Dispose() Next myWB.SaveAs(IO.Path.Combine(myDesktop, "WindowsAtts.xlsx")) myWB = Nothing myExcel = Nothing End If End Sub
In this example, we ask the user to select the file(s) they want to extract. Yes, more than one file can be
selected. Then we go through each of the selected files and open them IN MEMORY only. This means the
code can run very fast because the file does not have to be opened in the editor. And we have removed the
code that is looking just for the Window Block. So we get everything from every file selected.
Page 31
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD
There’s the output.
REVIEW
We have had 90 minutes to provide an Introduction to creating AutoCAD Add-Ins using VB.NET. That’s not a
lot of time. We could have spent that time discussing different variable types. We could have discussed
syntax. We could have discussed a million different things. But we didn’t. We showed the following:
• How to create a new AutoCAD add-in in VB.NET
• How to create a new AutoCAD command in VB.NET
• The basics of drawing in AutoCAD through the .NET API
• How to extract block and attribute information through the .NET API
I would love to help you continue on your journey to learning VB.NET Add-In Development. Please email me
and let me know how I can help.
Thanks for your time.
Jerry Winters
Page 32
SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD