Autocad VBA Font Tables

Tablestyles can be added and programmed without duplicating code by using a global variable for the AcadTableStyle object. This is a flexible method for getting a handle on them.

but first – make font tables in autocad – run a loop from 0 to 255 to advance the Chr(#), change the textstyle of the table style to instantly change the table.

Sub test_array_to_acadtable3()

'0 to 255 ascii table
'font style is set in the table style
'send the array to the maketable routine

Call connect_acad
Dim rows As Integer, i As Integer
Dim columns As Integer, j As Integer

rows = 16
columns = 16

Dim ar_mult() As String
ReDim ar_mult(1 To rows, 1 To columns)

For i = 1 To rows
For j = 1 To columns
ar_mult(i, j) = Chr((i - 1) * 16 + (j - 1))
Next j
Next i

Call makethetable3(ar_mult)
End Sub

2016-08-07_3

2016-08-07_2

2016-08-07_4

2016-08-07_1

2016-08-07_5

2016-08-07_6

VBA Arrays and Autocad Tables

Here is the basic routine for making an autocad table from an array in its simplest form from a one-based array, and a generalized form that creates a table from any two-dimensional array.


Sub test_array_to_acadtable1()
'test to make a one-based two dimensional array of numbers
'and send the array to the maketable routines

Call connect_acad
Dim rows As Integer, i As Integer
Dim columns As Integer, j As Integer
'change these to anything you like
rows = 14
columns = 16

Dim ar_mult() As Integer
ReDim ar_mult(1 To rows, 1 To columns)

For i = 1 To rows
For j = 1 To columns
ar_mult(i, j) = i * j
Next j
Next i

'makes two identical tables
Call makethetable2(ar_mult)
Call makethetable3(ar_mult)
End Sub


Sub test_array_to_acadtable2()
'test to make a random-based two dimensional array of numbers
'and send the array to the maketable routine
'that has been generalized to accept an array of any base

Call connect_acad
Dim rows As Integer, i As Integer
Dim columns As Integer, j As Integer
'change these to anything you like
rows = 14
columns = 16

Dim ar_mult() As Integer
ReDim ar_mult(3 To rows + 2, 3 To columns + 2)

For i = 3 To rows + 2
For j = 3 To columns + 2
ar_mult(i, j) = (i - 2) * (j - 2)
Next j
Next i

Call makethetable3(ar_mult)
End Sub


Sub makethetable3(ar As Variant)
'table is two-dimensional and any-base
    Dim tbl As AcadTable
    Dim i As Integer, j As Integer
    Dim rowcount As Integer, colcount As Integer
    Dim rowLbound As Integer, colLbound As Integer
    Dim rowUbound As Integer, colUbound As Integer
    
    Dim drowh As Double, dcolw As Double
    Dim pt0(0 To 2) As Double
    
    rowLbound = LBound(ar, 1)
    colLbound = LBound(ar, 2)
    rowUbound = UBound(ar, 1)
    colUbound = UBound(ar, 2)
    rowcount = rowUbound - rowLbound + 1
    colcount = colUbound - colLbound + 1
        
        drowh = 0.125
        dcolw = 0.625
    Set tbl = acadDoc.ModelSpace.AddTable(pt0, rowcount, colcount, drowh, dcolw)
        tbl.UnmergeCells 0, 0, 0, 0
        tbl.TitleSuppressed = True
        tbl.HeaderSuppressed = True

    For i = rowLbound To rowUbound
        For j = colLbound To colUbound
        tbl.SetText i - colLbound, j - rowLbound, ar(i, j)
        Next j
    Next i
End Sub


Sub makethetable2(ar As Variant)
'the simpler routine
'assume table is two-dimensional and one-base
'no attempt to set up a tablestyle
'which makes the unmerge method necessary
 
    Dim tbl As AcadTable
    Dim i As Integer, j As Integer
    Dim rowcount As Integer, colcount As Integer
    Dim drowh As Double, dcolw As Double
    Dim pt0(0 To 2) As Double
    
    rowcount = UBound(ar, 1)
    colcount = UBound(ar, 2)
    drowh = 0.125
    dcolw = 0.625
    'create the table sized for the array
   Set tbl = acadDoc.ModelSpace.AddTable(pt0, rowcount, colcount, drowh, dcolw)
    tbl.UnmergeCells 0, 0, 0, 0
    tbl.TitleSuppressed = True
    tbl.HeaderSuppressed = True

    For i = 1 To rowcount
     For j = 1 To colcount
     tbl.SetText i - 1, j - 1, ar(i, j)
     Next j
    Next i

End Sub

any selection of data on a spreadsheet can be saved to an array with a single line of code, and the array fed to the makethetable routine. of course the formatting is terrible but we have tools for that.


Sub make_table_from_selection()
Dim ar_tbl As Variant
ar_tbl = Selection.Value
 'a selection assigned to a variant
 'creates a one-based two-dimension array
 'the first dim is the row, the second is the column
  
'MsgBox LBound(ar_tbl, 1)  returns 1
'MsgBox LBound(ar_tbl, 2)  returns 1

Call connect_acad
Call makethetable3(ar_tbl)

End Sub

Autocad VBA Tables

Autocad has over 200 table and table style methods and properties. Many of these are overlapping uncertain as to application. The ActiveX help is not much. I imagine whoever turned it over to his/her boss said this is just a framework, i need to put as many hours in to finish it. and there it stands. however, the multitude of options show how fully it is implemented. the autocad interfaces are very good. in fact that is the only way to learn how to use the methods, study the user interfaces and find their vba counterparts. The realization comes that there is not much to be gained by duplicating the user interface in vba. the work flow is to assemble data in excel, format it in excel, then use the pastespecial command in autocad to paste the data to a table complete with formatting.

you can start to sort out the activex help by copy pasting the methods page to an excel sheet. the links transfer and you can begin to assemble the most required methods and add your own notes.

the > 200 table methods. these encompass the table and the tabledit command. tabledit is accessed by rightclicking the table, and by the properties window, as well as the ribbon panel for tables.
Autocad 2016 Table Methods and Properties ActiveX VBA

there are fewer tablestyle methods.
Autocad 2016 TableStyle Methods and Properties ActiveX VBA

2016-07-28_1

here is some barebones beginning code to create a multiplication table, any size, with an array. Arrays are natural tools to use with tables, whether in excel or autocad. Feed the array to a make table subprocedure which makes the autocad table and sizes it the same as the array. There is no attempt to create a tablestyle, which makes it necessary to run the unmerge method. Even though no tablestyle is selected, the table has a default, whatever is current, which is likely the “Standard” that automatically merges the first row and makes it a “Title” row. There is also some commented out code that writes the data to a new sheet. And some commented out code which demonstrates how to obtain the data for the autocad table from a spreadsheet.


Sub test()
DelSht ("new_sheet1")
CreateSheet ("new_sheet1")

Dim rows As Integer, i As Integer
Dim columns As Integer, j As Integer

'change these to anything you like
rows = 12
columns = 12

Dim ar_mult() As Integer
ReDim ar_mult(1 To rows, 1 To columns)

For i = 1 To rows
For j = 1 To columns
ar_mult(i, j) = i * j
Next j
Next i

'this comment block demonstrates taking spreadsheet data to autocad table
'Dim rng As Range
'Worksheets("new_sheet1").Activate
'Set rng = Range("B2", Cells(rows + 1, columns + 1))
'rng = ar_mult

'Dim ar2 As Variant
'ar2 = rng
'Call makethetable1(ar2)

Call makethetable1(ar_mult)

End Sub


Sub makethetable1(ar As Variant)
'first attempt assume table is two-dimensional and one-base
'no attempt to set up a tablestyle
'which makes the unmerge method necessary

    Call connect_acad
    Dim tbl As AcadTable
    Dim i As Integer, j As Integer
    Dim rowcount As Integer, colcount As Integer
    Dim drowh As Double, dcolw As Double
    Dim pt0(0 To 2) As Double
    
    rowcount = UBound(ar, 1)
    colcount = UBound(ar, 2)
    drowh = 0.125
    dcolw = 1
    'create the table sized for the array
    Set tbl = acadDoc.ModelSpace.AddTable(pt0, rowcount, colcount, drowh, dcolw)

      'object.UnmergeCells minRow, maxRow, minCol, maxCol
    tbl.UnmergeCells 0, 0, 0, 0

With tbl

For i = 1 To rowcount
 For j = 1 To colcount
  If Not IsEmpty(ar(i, j)) Then
   .SetText i - 1, j - 1, ar(i, j)
  End If
 Next j
Next i

End With

tbl.Update
ZoomExtents

End Sub

2016-07-29_1

to conquer the tablestyle creation, you need to remember the enumeration constants, such as acdatarow and acHorzBottom can be added up. their values can be obtained for reference by typing in the immediate window. if you want your entire grid to be blue, you can do it with one line of code.


Sub table_style_full()
  'sets a full table style with title and header
    Call connect_acad
    
    Dim dictionaries As AcadDictionaries
    Dim dictObj As AcadDictionary
    Set dictionaries = acadDoc.Database.dictionaries
    Set dictObj = dictionaries.Item("acad_tablestyle")
     
    Dim keyName As String, className As String
    Dim TS As AcadTableStyle
    keyName = "Tb_full"
    className = "AcDbTableStyle"
    Set TS = dictObj.AddObject(keyName, className)
    TS.Name = "Tb_full"
    TS.Description = "Style data"
  
    TS.TitleSuppressed = False
    TS.HeaderSuppressed = False
    TS.BitFlags = 1
    TS.FlowDirection = acTableTopToBottom
        
    TS.EnableMergeAll "Title", True
          
    TS.HorzCellMargin = 0.06
    TS.VertCellMargin = 0.03 ' affects the height of the cell
    
    TS.SetTextHeight acTitleRow, 0.25
    TS.SetTextHeight acHeaderRow, 0.1875
    TS.SetTextHeight acDataRow, 0.125
        
   'doesnt like it if these are not already created
    TS.SetTextStyle acTitleRow, "Arial"
    TS.SetTextStyle acHeaderRow, "Arial"
    TS.SetTextStyle acDataRow, "ArialN"

    TS.SetAlignment acTitleRow, acMiddleCenter
    TS.SetAlignment acHeaderRow, acMiddleCenter
    TS.SetAlignment acDataRow, acMiddleRight
    
  Dim col As AcadAcCmColor
  Set col = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.20")
    'Blue
  Call col.SetRGB(0, 0, 255)

'gridlinetypes
'acHorzBottom 4
'acHorzInside 2
'acHorzTop 1
'acVertInside 16
'acVertLeft 8
'acVertRight 32
'border sum is 63

'rowtypes
'acdatarow 1
'acTitleRow 2
'acHeaderRow 4
'row sum is 7

    'setgridcolor gridlinetypes, rowtypes, color
    TS.SetGridColor 63, 7, col
    TS.SetGridVisibility 63, 7, True
    
     Call col.SetRGB(0, 0, 0)
     'setcolor rowtypes, color
     TS.SetColor 7, col
    'Set col = TS.GetColor(acDataRow)
    'MsgBox col.Red & col.Green & col.Blue
      
    'Set col = TS.GetBackgroundColor(acDataRow)
    'MsgBox col.Red & col.Green & col.Blue
    TS.SetBackgroundColor 7, col
    TS.SetBackgroundColorNone 7, True
     
    acadDoc.SetVariable ("ctablestyle"), "Tb_full"
    acadDoc.SetVariable ("clayer"), "0"
    
End Sub

well i thought that i could create a tablestyle with a comprehensive sub procedure, setting nearly every variable, set it to current, then create a new tablestyle and it would inherit the current values, but it does not. the user interface works that way, it starts with the the current style, but vba creation does not. i wanted to have a tablestyle library that did not duplicate code. i tried changing the “Standard” style, as it seems that is the template, setting that current, but still the inherited values in the new unset tablestyle seem to come from an intrinsic standard, not the “Standard.” thats ok, we will refine our basic tablestyle routine and copy / modify it as required.

i need to learn how to format, for example displaying a calculated double like 1/3 with a desired number of decimal places, and investigate the difference between SetTextString and SetText and SetValue and SetCellValue, and the difference between SetFormat and SetCellFormat and SetDataFormat, some jobs like that, other than that, we have many if not most of the tools we need demonstrated.

2016-07-31_1

Sub test()
Call connect_acad
acadApp.Preferences.Display.GraphicsWinModelBackgrndColor = 16250871
acadDoc.SetVariable "LWDISPLAY", 1
Call set_text_style

Dim rows As Integer, i As Integer
Dim columns As Integer, j As Integer

'change these to anything you like
rows = 14
columns = 14

Dim ar_mult() As Integer
ReDim ar_mult(1 To rows, 1 To columns)

For i = 1 To rows
For j = 1 To columns
ar_mult(i, j) = i * j
Next j
Next i

'this comment block demonstrates taking spreadsheet data to autocad table
'DelSht ("new_sheet1")
'CreateSheet ("new_sheet1")
'Dim rng As Range
'Worksheets("new_sheet1").Activate
'Set rng = Range("B2", Cells(rows + 1, columns + 1))
'rng = ar_mult

'Dim ar2 As Variant
'ar2 = rng
'Call makethetable1(ar2)

Call table_style_data
Call makethetable1(ar_mult)
End Sub
Sub table_style_data()
'doesnt influence
'Call table_style_full

    Dim dictionaries As AcadDictionaries
    Dim dictObj As AcadDictionary
    Set dictionaries = acadDoc.Database.dictionaries
    Set dictObj = dictionaries.Item("acad_tablestyle")
     
    Dim keyName As String, className As String
    Dim TS As AcadTableStyle
    keyName = "Tb_data"
    className = "AcDbTableStyle"
    Set TS = dictObj.AddObject(keyName, className)
    TS.Name = "Tb_data"
    TS.Description = "Style data"
  
    TS.TitleSuppressed = True
    TS.HeaderSuppressed = True
    
    TS.HorzCellMargin = 0.03
    TS.VertCellMargin = 0.03 ' affects the height of the cell

    TS.SetTextHeight acTitleRow, 0.125
    TS.SetTextHeight acHeaderRow, 0.125
    TS.SetTextHeight acDataRow, 0.125


    Dim col As AcadAcCmColor
  Set col = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.20")
'    'Blue
  Call col.SetRGB(0, 0, 255)
   TS.SetGridColor 63, 7, col
   
    TS.SetGridLineWeight 63, 7, acLnWt030
     TS.SetTextStyle acDataRow, "Tempus Sans ITC"
      
    acadDoc.SetVariable ("ctablestyle"), "Tb_data"
    acadDoc.SetVariable ("clayer"), "0"
End Sub
Sub makethetable1(ar As Variant)
'first attempt assume table is two-dimensional and one-base
'no attempt to set up a tablestyle
'which makes the unmerge method necessary

    Call connect_acad
    Dim tbl As AcadTable
    Dim i As Integer, j As Integer
    Dim rowcount As Integer, colcount As Integer
    Dim drowh As Double, dcolw As Double
    Dim pt0(0 To 2) As Double
    
    rowcount = UBound(ar, 1)
    colcount = UBound(ar, 2)
    drowh = 0.125
    dcolw = 0.5
    'create the table sized for the array
    Set tbl = acadDoc.ModelSpace.AddTable(pt0, rowcount, colcount, drowh, dcolw)

      'object.UnmergeCells minRow, maxRow, minCol, maxCol
    tbl.UnmergeCells 0, 0, 0, 0
    
    tbl.TitleSuppressed = True
    tbl.HeaderSuppressed = True

With tbl
    For i = 1 To rowcount
     For j = 1 To colcount
      If Not IsEmpty(ar(i, j)) Then
       .SetText i - 1, j - 1, ar(i, j)
      End If
     Next j
    Next i
End With

ZoomExtents
 'tbl.GenerateLayout
End Sub

AcadTableStyle

I confess to not fully understanding dictionaries in autocad VBA. They seem like a storage closet. A storage closet has no rules. Items in the dictionaries collection are not necessarily dictionaries. Dictionary objects do not always have names or pass all the tests for dictionary objects. Its not likely we have much reason to iterate through the dictionaries collection except for curiosity, mostly just need to reach in and get what we know is there. The dictionaries collection is a collection of dictionaries. Here is some orientation code to get the idea what is in the upper level dictionaries collection. This will print to the immediate window for information only.


Sub Listdictionary()
'very important statement
On Error Resume Next

Call connect_acad
Dim i As Integer, intcount As Integer
Dim acadobj As AcadObject
Dim dicts As AcadDictionaries
Dim dict As AcadDictionary
Set dicts = acadDoc.Database.dictionaries

For Each acadobj In dicts
    'everything in dicts is an acadobject
    Debug.Print acadobj.ObjectName
    'not everything has a name property
    Debug.Print acadobj.Name
    Debug.Print " "
Next acadobj

Debug.Print " "
'from this point no errors generated
On Error GoTo 0

For Each acadobj In dicts
    If TypeOf acadobj Is AcadDictionary Then
    Debug.Print acadobj.Name
    End If
Next acadobj

Debug.Print " "
'alternate loop method, same results
intcount = dicts.Count
For i = 0 To intcount - 1
Set acadobj = dicts.Item(i)
If TypeOf acadobj Is AcadDictionary Then
    Debug.Print acadobj.Name
    End If
Next i
Debug.Print " "

On Error Resume Next
'this does not work, generates error
'inexplicably only retrieves 2 dicts
For Each dict In dicts
    Debug.Print dict.ObjectName
    Debug.Print dict.Name
    Debug.Print " "
Next dict

End Sub

For instance the code above returns in an empty drawing (excising the duplicate results) –

AcDbXrecord
ACAD_CIP_PREVIOUS_PRODUCT_INFO

AcDbDictionary
ACAD_COLOR

AcDbDictionary
ACAD_DETAILVIEWSTYLE

AcDbDictionary

AcDbDictionary

AcDbDictionary

AcDbDictionary
ACAD_MLEADERSTYLE

AcDbDictionary
ACAD_MLINESTYLE

AcDbDictionary

AcDbDictionaryWithDefault
ACAD_PLOTSTYLENAME

AcDbRapidRTRenderSettings

AcDbDictionary
ACAD_RENDER_RAPIDRT_SETTINGS

AcDbDictionary
ACAD_SCALELIST

AcDbDictionary
ACAD_SECTIONVIEWSTYLE

AcDbDictionary
ACAD_TABLESTYLE

AcDbDictionary
ACAD_VISUALSTYLE

AcDbDictionary
AcDbVariableDictionary

ACAD_COLOR
ACAD_DETAILVIEWSTYLE
ACAD_MLEADERSTYLE
ACAD_MLINESTYLE
ACAD_PLOTSTYLENAME
ACAD_RENDER_RAPIDRT_SETTINGS
ACAD_SCALELIST
ACAD_SECTIONVIEWSTYLE
ACAD_TABLESTYLE
ACAD_VISUALSTYLE
AcDbVariableDictionary

The Dictionaries collection retrieved as a property of the document is composed of named dictionary items. The one we want is called “ACAD_TABLESTYLE”. This is a single dictionary but it is itself a collection. It contains instances of a class called “AcadTableStyle”. The only such named instance in a blank drawing is called “Standard”. We are going to add a new one to work on.


Sub make_tb_styl_1()
    
    Dim dictionaries As AcadDictionaries
    Set dictionaries = acadDoc.Database.dictionaries
  
    Dim dictObj As AcadDictionary
    Set dictObj = dictionaries.Item("acad_tablestyle")
  
    ' Create the custom TableStyle object in the dictionary
    Dim keyName As String
    Dim className As String
    Dim customObj As AcadTableStyle
    keyName = "Tb_Styl_1"
    className = "AcDbTableStyle"
    Set customObj = dictObj.AddObject(keyName, className)
       
    customObj.Name = "Tb_Styl_1"

now we have an object in the drawing of type AcadTableStyle with name “Tb_Styl_1” set to a VBA object named customobj and we can set its properties as we wish.

the autocad activex (VBA) help reference for AcadTableStyle
there are about 60 AcadTableStyle methods and 17 properties. Some of these have sample code. There is a compiled HTML file of the same information in
Program Files\Common Files\Autodesk Shared\acadauto.chm

The table object activex help
has more than 200 methods and properties.

The third component of linking tables with excel is the datalink object. However i do not see any activex reference. I believe that is beyond routine access. datalinks are very cool, i use them every day at work, though they tend to crash the drawing if you re-use them, their links get broken, there are more than one in a drawing, and you try to delete them. A lot of conditions but they do occur if nearly every drawing has a datalink. The advanatage – data is live, when it is changed in excel the acad table reflects it – make it worthwhile to carefully handle them. For our table application, we will write a program that makes a table of user selected excel data and formats it to user satisfaction. It wont be linked, but we will make the table creation so that it is easily remade. That has its own advantages of lightweight simplicity.

Programming Autocad Tables

Since Autocad’s smashing success in replacing mechanical drafting boards worldwide in the 1980’s and 1990’s, it has had 3 great needs. One of these is a Bill of Material. Tables were introduced in 2005, unfortunately well after the autocad buzz was silent. They did not get as much attention as they would have much earlier, but they have wide capabilities. Clearly the autocad programmers studied excel and tried to bring in many of its features, although a mobile table in a 3D graphics space is much different than a spreadsheet. Excel is still the bill of material autocad always needed. That has been the case for a long time. The autocad bill is best thought of as a reflection of data in excel. The drawing is not an entity to itself. Nearly every autocad user building a product has some sort of database that interfaces back to their shipping, purchasing or accounting system.

Finding the right form and scope for the on-drawing bill of material is probably something that most firms struggle with. Is the bill instruction for fabrication, for ordering, for the customer, for the shipping department, or to show design intent? Autocad tables are not where most designers want to bury crucial information, but most drawings need a bill to summarize what is being shown and direct the output of fabrication, a list of parts or material used, a list of items produced to know when the drawing is fabricated completely. Autocad tables have a huge number of features, both user interface and vba interface. They can mirror information in excel which in turn can translate back and forth to the system database, but they are not restricted to being bills of material. They are in the fine autocad tradition of a basic tool.

2016-07-16_1

2016-07-16_3

2016-07-17_1

the data shown here is prepared in excel in the polar coordinate graphing form.

2016-07-17_5

Polar Coordinate Graphing with Autocad

2016-07-04_2

Polar coordinate graphing calculates position with a point format (Radius, Angle) rather than (X, Y). Radius is the distance from the origin, called the Pole, and Angle is measured from the horizontal X axis. The Formula is written with Angle as the independent variable. The programming loop increments the angle and calculates the Radius or R distance from the pole. For instance a circle is defined by the equation R = Sin (A) where A varies from 0 to 360. The start and end angle is taken from the user form, supplied by the user, along with the increment. The normal stop and start values are 0 to 360 with a step of 1 degree. However there are cases where many revolutions are used.

One line has two endpoints, two connected lines have 3 points. If you plot any sequence of connected lines, you always have one more point than lines. The graphing program takes the minimum and maximum Angle values, the increment Angle value, and calculates the number of points and lines to be drawn. It uses the calculated variable numpts to size the array for the point data, each point having two values X and Y. Even though we are polar graphing, the program still converts back to X and Y with some simple trigonometry to draw the graph.

Excel VBA wants trig function input to be Radians. We collect the input in degrees and convert to Radians in the program. Conversion of (R, A) to (X,Y) is through the simple Sin and Cos functions. X = R * Cos(A) and Y = R * Sin(A)

Thats the core of the program. There are a few enhancements, not shown below, such as an option to write the point data to an excel sheet.

numpts = (Amax - Amin) / A_inc 'num of lines
numpts = numpts + 1
ReDim pt(1 To numpts * 2)

For i = 1 To numpts
A = Amin + ((i - 1) * A_inc)

'user works in degrees but trig functions use radians
A_rad = deg2rad(A)

R = eval_polar_func(strfunc, A_rad)

X = R * Cos(A_rad)
Y = R * Sin(A_rad)
pt(i * 2 - 1) = X: pt(i * 2) = Y

Next i

The function to evaluate the user typed in equation has an error handler to exit after 3 invalid results. I was a little surprised how robust the Evaluate function was in handling typed in equations. You must always indicate multiplication with the “*” and trig functions must always enclose data in parentheses without a space, but otherwise precise spacing between elements is not usually necessary in arithmetic operators.

Function eval_polar_func(ByVal strfunc As String, A_rad As Double) As Double
On Error GoTo HandlError
Static errorcounter As Integer

strfunc = Replace(strfunc, "A", A_rad, , , vbTextCompare)
eval_polar_func = Evaluate(strfunc)

ExitHere:
Exit Function
'runtime error 13 type mismatch
HandlError:
If Err.number = 13 Then
MsgBox "type mismatch div by zero or bad equation"
eval_polar_func = ylim + 1
errorcounter = errorcounter + 1
If errorcounter = 3 Then
MsgBox "errorcounter at 3 - exiting"
End
End If

End If
End Function

2016-07-04_3

2016-07-04_4

2016-07-04_5