Sie sind auf Seite 1von 32

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

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 1


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”.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 2


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 3


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 4


3. Add References to the following files:
accoremgd.dll, acdbmgd.dll, acmgd.dll
We do this by going to the menu. Project -> Add
Reference

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 5


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

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 6


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 7


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”.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 8


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 9


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

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 10


Once we are in the correct directory, we want to select our DLL.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 11


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 12


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 13


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”.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 14


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?

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 15


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 16


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 17


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 18


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 19


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 20


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 21


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

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 22


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

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 23


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 24


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”.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 25


<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:

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 26


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 27


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 28


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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 29


<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.

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 30


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
jerryw@vbcad.com

SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 31


SD197926-L - Hands-on Introduction to VB.NET Add-Ins for AutoCAD Page 32

Das könnte Ihnen auch gefallen