Following on from my blog about the Microsoft Visio Viewer, I am delighted that Microsoft have published a developer reference for it (long overdue, but very welcome). See the MSDN pages at http://msdn.microsoft.com/en-us/library/cc297217.aspx and Visio Insight blog http://blogs.msdn.com/visio/archive/2009/01/14/developer-reference-for-visio-2007-viewer-released.aspx
Visio
Turning OFF The Cross Functional Flowchart Addon in Visio
Following on from my last blog, my colleague also needs to stop the Cross Functional Flowchart behaviour in a Visio Diagram. Well, I was almost fooled again into thinking that it might be as simple as removing the Persistent Events using the tool in the Visio SDK.
[Read more…] about Turning OFF The Cross Functional Flowchart Addon in Visio
Closing Shape Data Sets window in Visio 2007
A colleague recently asked me how to close the Shape Data Sets window so that it does not automatically re-open when you open the drawing again. My first thoughts was that this is surely a simple matter of saving the workspace, but it appears that this is not the case! I found that other Visio users have had the same problem, so I thought I would present my solution (until Microsoft fix it!).
[Read more…] about Closing Shape Data Sets window in Visio 2007
Using the Microsoft Visio Viewer (and introducing visViewer)
Microsoft Outlook 2007 installs the Microsoft Visio Viewer (vviewer.dll via vpreview.exe) by default, so that native Visio files can be seen in all their glory (almost). In this blog I’ll show that the Visio Viewer actually provides access to the Shape Data (Custom Properties), Hyperlinks, Reviewers Markup and Layers. All this without even having Visio installed!

This is great because multiple page documents can be browsed, panned and zoomed.

However, this presentation of the Microsoft Office Visio previewer hides quite a lot of its functionality of this, so it is difficult to toggle layer and reviewers markup visibility, or to view the shape data/custom properties.
There is an existing web article which demonstrates how to use the Visio Viewer in SharePoint (http://www.wssdemo.com/Pages/visio.aspx), and the same method can be used in a web page. This presentation of the Visio Viewer does enable the user to get the extra functionality, but it does not allow the shape data to be searched, listed or extracted. Neither does it allow you to print easily.
Well, I wrote visViewer as a vb.net wrapper for the Microsoft Visio Viewer 2003 version several years ago, and now I have updated it for the Microsoft Visio Viewer 2007 (see http://www.bvisual.net/Products/visViewer.aspx). The newer version provides access to shapes with shapes, just as the reporting tool full version of Visio was enhanced to provide access to shapes within shapes. This time I have released it as shareware, so feel free to try it, and, if you like it and use it commercially, you may wish to donate towards its development.
visViewer demonstrates that all the Shape Data on all of the shapes on each page in the Visio document are visible to code. The main principle is that the CurrentPageIndex of the Viewer control needs to be set to an integer number up to the PageCount before the shapes can be read. For example the following block of code shows how you can
With Me.AxViewer1 .CurrentPageIndex = n For lShape As Integer = 1 To .ShapeCount ‘You can use .get_ShapeName(lShape) For lProperty As Integer = 1 To .get_CustomPropertyCount(lShape) ‘ You can use .get_CustomPropertyName(lShape, lProperty) ‘ and .get_CustomPropertyValue(lShape, lProperty) Next lProperty For lHyperlink As Integer = 1 To .get_HyperlinkCount(lShape) ‘ You can use .get_HyperlinkAddress(lShape, lHyperlink) Next lProperty Next lShape End With

Once you have read the data inside each shape, then you can provide searching and exporting.

In addition to reading the Shape Data, I also collect the Hyperlinks, and thus it is possible to show multiple hyperlinks on shapes, and to provide the ability to follow them.

One shortcoming of the Visio Viewer is the lack of any method to zoom to a shape in the document. Strangely, there is a method to the shape at any xy co-ordinate (get_ShapeAtPoint), but not one to get the xy co-ordinate of a shape.
Another shortcoming of the Visio Viewer is the lack of printing, but I have been able to partially address this by using the PrintForm method from the Visual Basic Power Packs. However, this only outputs raster, which is never going to be as crisp as vectors.
I decided to use the Microsoft ReportViewer (because it is simple and royalty free) for the reports that provide printing, or export to Excel or Pdf, of the shape data.

Lastly, I provided the ability to open a Visio document from the menu, or by dropping a Visio document on to the Visio Viewer panel, or by opening from Window Explorer (if the msi installation is used rather than the ClickOnce).
I hope that visViewer proves useful to non-Visio and Visio users alike, and hope that it encourages the use of Visio files as a portable data graphic file format.
Tech-Ed EMEA 2008 IT Professionals Conference
I am on the Office Client Ask the Experts booth on Wednesday, Thursday, Friday this week in sunny Barcelona. I am hoping that there will be some enlightened IT Pros who can see the value of using Visio to analyse, plan and deploy various network and systems. I have been an an ATE booth at Tech-Ed twice before, but that was at the developers side of the conference, rather than the IT pros, and I was disappointed with the lack of understanding of the power of Visio, so I am looking forward to presenting the built-in capabilities of Visio Professional and the number of IT Pro related add-ins that have become available.
Importing KML Files into Visio
In my last blog, I demonstrated how you can import a map image from Maps Live, and calibrate it in preparation for importing any KML files into it (Moving Between Visio and KML). In this blog, I will complete the import of KML files exported from Maps Live.
I created two base map images in Visio, side by side, so that I can demonstrate that the import can be done to any prepared image, anywhere in Visio. Of course, you could have the two images on top of each other, on different layers, so that you can switch between Road and Aerial view by just changing the visibility of their layers.

In my demonstration, I have prepared a KML file with an area (polygons), three paths (linestrings) and three pushpins (points). You may spot that there are only two shown on each map, well, that is because I have put a filter in the import to only bring in those parts that are within the map image boundary.

In addition to the geometry for each shape, I have added Shape Data/Custom Properties and assigned the different types of shapes on to discrete layers in Visio.

In order to convert the KML files into Visio, I had to choose how the different types of Placemarks are to be represented:
Getting the Map
Firstly, you need to get the size and position of the selected map shape and read its Shape Data/Custom Properties in order to understand the extents of the earth under consideration. Then the only difficulty was transforming the geometry from longitudes/latitudes of each Placemark relative to the selected map shape.
If shpMap.CellExists(“Prop.MinLon”, Visio.visExistsAnywhere) = 0 Then
MsgBox “Please select a map shape”
Exit Sub
End If
Dim nod As MSXML2.IXMLDOMNode
Set nod = xdoc.SelectSingleNode(“//kml/Document/Placemark/name”)
If Not nod Is Nothing Then
setProp shpMap, “Name”, “Name”, 0, “””” & nod.Text & “”””
Else
setProp shpMap, “Name”, “Name”, 0, “”
End If
Set nod = xdoc.SelectSingleNode(“//kml/Document/Placemark/description”)
If Not nod Is Nothing Then
setProp shpMap, “Description”, “Description”, 0, “””” & nod.Text & “”””
Else
setProp shpMap, “Description”, “Description”, 0, “”
End If
Dim dWidth As Double
dWidth = shpMap.Cells(“Width”).ResultIU
Dim dHeight As Double
dHeight = shpMap.Cells(“Height”).ResultIU
Dim dLeft As Double
dLeft = shpMap.Cells(“PinX”).ResultIU – shpMap.Cells(“LocPinX”).ResultIU
Dim dBottom As Double
dBottom = shpMap.Cells(“PinY”).ResultIU – shpMap.Cells(“LocPinY”).ResultIU
Dim dMinLon As Double
dMinLon = shpMap.Cells(“Prop.MinLon”).ResultIU
Dim dMinLat As Double
dMinLat = shpMap.Cells(“Prop.MinLat”).ResultIU
Dim dMaxLon As Double
dMaxLon = shpMap.Cells(“Prop.MaxLon”).ResultIU
Dim dMaxLat As Double
dMaxLat = shpMap.Cells(“Prop.MaxLat”).ResultIU
Collecting the Styles, etc
Every Placemark created by the export from Maps Live to KML has a corresponding Style element for its line color, weight and transparency and fill color and transparency. These values are stored separately within the KML file created by Maps Live (note that this is not necessary in the KML specification, and some tools do export the style information within the Placemark element).
Dim i As Integer
Dim j As Integer
Dim styles As MSXML2.IXMLDOMNodeList
Dim style As MSXML2.IXMLDOMElement
Dim dicStyles As New Dictionary
‘Collect the styles into a dictionary
Set styles = xdoc.getElementsByTagName(“Style”)
For i = 1 To styles.Length
Set style = styles.Item(i – 1)
setStyle style, dicStyles
Next i
Dim name As String
Dim description As String
Dim styleUrl As String
Dim aStyle(2) As String
Dim lineStyleColor As String
Dim lineStyleWidth As String
Dim polyStyleColor As String
Dim placemark As MSXML2.IXMLDOMElement
Dim vertexes As Variant
Dim shpNew As Visio.Shape
Dim xyArray() As Double
Areas (Polygons)
The choice of geometry type was pretty straight forward because Visio has a DrawPolyline(…) method for a Page object, so, after converting from lonlats to Visio geometry, the ShapeSheet looks something like this:

The partial code that achieves this is shown below:
Dim polygons As MSXML2.IXMLDOMNodeList
Dim polygon As MSXML2.IXMLDOMElement
'Loop thru the polygons
Set polygons = xdoc.getElementsByTagName("Polygon")
addLayer shpMap.ContainingPage, "Polygon"
For i = 1 To polygons.Length
Set polygon = polygons.Item(i - 1)
setCoords polygon, vertexes
For j = 0 To UBound(vertexes, 2)
ReDim Preserve xyArray(1 To ((j + 1) * 2))
xyArray(((j + 1) * 2) - 1) = dLeft + ((CDbl(vertexes(0, j) - dMinLon) / (dMaxLon - dMinLon)) * dWidth)
xyArray((j + 1) * 2) = dBottom + ((CDbl(vertexes(1, j) - dMinLat) / (dMaxLat - dMinLat)) * dHeight)
Next j
'Ensure that the shape starts or ends within the map shape
If shpMap.HitTest(xyArray(1), xyArray(2), 0) > 0 _
And shpMap.HitTest(xyArray(UBound(xyArray) - 3), xyArray(UBound(xyArray) - 2), 0) > 0 Then
Set placemark = polygon.ParentNode
setAttribs placemark, name, description, styleUrl
lineStyleColor = dicStyles(Mid(styleUrl, 2))(0)
lineStyleWidth = dicStyles(Mid(styleUrl, 2))(1)
polyStyleColor = dicStyles(Mid(styleUrl, 2))(2)
Set shpNew = shpMap.ContainingPage.DrawPolyline(xyArray, 0)
shpNew.Cells("LineColor").FormulaU = "=RGB(" & HexToDecimal(Mid(lineStyleColor, 7, 2)) & _
"," & HexToDecimal(Mid(lineStyleColor, 5, 2)) & "," & HexToDecimal(Mid(lineStyleColor, 3, 2)) & ")"
shpNew.Cells("LineColorTrans").FormulaU = "=" & CInt(HexToDecimal(Mid(lineStyleColor, 1, 2)) * 100 / 255) & " %"
shpNew.Cells("LineWeight").FormulaU = "=" & lineStyleWidth & " pt"
shpNew.Cells("FillForegnd").FormulaU = "=RGB(" & HexToDecimal(Mid(polyStyleColor, 7, 2)) & _
"," & HexToDecimal(Mid(polyStyleColor, 5, 2)) & "," & HexToDecimal(Mid(polyStyleColor, 3, 2)) & ")"
shpNew.Cells("FillForegndTrans").FormulaU = "=" & CInt(HexToDecimal(Mid(polyStyleColor, 1, 2)) * 100 / 255) & " %"
shpNew.name = "Polygon_" & Format(i, "000")
setProp shpNew, "Name", "Name", 0, """" & name & """"
setProp shpNew, "Description", "Description", 0, """" & description & """"
shpMap.ContainingPage.Layers("Polygon").Add shpNew, 0
End If
Next i
Paths (LineStrings)
I decided to use the DrawPolyline method for LineStrings too, however, I discovered there is a bug in Visio that means that a Polyline with NoFill set to True cannot be found by SpatialNeighbors. This is important because I plan to use the SpatialNeighbors function later for exporting Kml. However, I found a workaround, which is to set the NoFill to False, but to set the FillPattern to 0 (None).

Dim linestrings As MSXML2.IXMLDOMNodeList
Dim linestring As MSXML2.IXMLDOMElement
Set linestrings = xdoc.getElementsByTagName("LineString")
addLayer shpMap.ContainingPage, "LineString"
For i = 1 To linestrings.Length
Set linestring = linestrings.Item(i - 1)
setCoords linestring, vertexes
For j = 0 To UBound(vertexes, 2)
ReDim Preserve xyArray(1 To ((j + 1) * 2))
xyArray(((j + 1) * 2) - 1) = dLeft + ((CDbl(vertexes(0, j) - dMinLon) / (dMaxLon - dMinLon)) * dWidth)
xyArray((j + 1) * 2) = dBottom + ((CDbl(vertexes(1, j) - dMinLat) / (dMaxLat - dMinLat)) * dHeight)
Next j
'Ensure that the shape starts or ends within the map shape
If shpMap.HitTest(xyArray(1), xyArray(2), 0) > 0 _
And shpMap.HitTest(xyArray(UBound(xyArray) - 1), xyArray(UBound(xyArray)), 0) > 0 Then
Set placemark = linestring.ParentNode
setAttribs placemark, name, description, styleUrl
'Exclude the MDL shape, if present
If Not name = MDDLName Then
lineStyleColor = dicStyles(Mid(styleUrl, 2))(0)
lineStyleWidth = dicStyles(Mid(styleUrl, 2))(1)
Set shpNew = shpMap.ContainingPage.DrawPolyline(xyArray, 0)
shpNew.Cells("LineColor").FormulaU = "=RGB(" & HexToDecimal(Mid(lineStyleColor, 7, 2)) & _
"," & HexToDecimal(Mid(lineStyleColor, 5, 2)) & "," & HexToDecimal(Mid(lineStyleColor, 3, 2)) & ")"
shpNew.Cells("LineColorTrans").FormulaU = "=" & CInt(HexToDecimal(Mid(lineStyleColor, 1, 2)) * 100 / 255) & " %"
shpNew.Cells("LineWeight").FormulaU = "=" & lineStyleWidth & " pt"
shpNew.name = "Linestring_" & Format(i, "000")
setProp shpNew, "Name", "Name", 0, """" & name & """"
setProp shpNew, "Description", "Description", 0, """" & description & """"
'A Polyline with NoFill set to True cannot be found by SpatialNeighbors
shpNew.Cells("Geometry1.NoFill").FormulaU = False
shpNew.Cells("FillPattern").FormulaU = 0
shpMap.ContainingPage.Layers("LineString").Add shpNew, 0
End If
End If
Next i
PushPins (Points)
I could have considered translating a pushpin as an instance of a Visio master, but I thought that I would keep it simple (for now) and use the DrawEllipse function. Of course, you need to do a little displacement to account for PinX/Y of the ellipse being in the centre of the shape.

Dim pins As MSXML2.IXMLDOMNodeList
Dim pin As MSXML2.IXMLDOMElement
Const PinRadius As Double = 0.1
Set pins = xdoc.getElementsByTagName(“Point”)
addLayer shpMap.ContainingPage, “Point”
For i = 1 To pins.Length
Set pin = pins.Item(i – 1)
setCoords pin, vertexes
For j = 0 To UBound(vertexes, 2)
ReDim Preserve xyArray(1 To ((j + 1) * 2))
xyArray(((j + 1) * 2) – 1) = dLeft + ((CDbl(vertexes(0, j) – dMinLon) / (dMaxLon – dMinLon)) * dWidth)
xyArray((j + 1) * 2) = dBottom + ((CDbl(vertexes(1, j) – dMinLat) / (dMaxLat – dMinLat)) * dHeight)
Next j
‘Ensure that the shape is within the map
If shpMap.HitTest(xyArray(1), xyArray(2), 0) > 0 Then
Set placemark = pin.ParentNode
setAttribs placemark, name, description, styleUrl
Set shpNew = shpMap.ContainingPage.DrawOval(xyArray(1) – PinRadius, xyArray(2) + PinRadius, _
xyArray(1) + PinRadius, xyArray(2) – PinRadius)
shpNew.Cells(“LineColor”).FormulaU = “=RGB(255,0,0)”
shpNew.Cells(“FillForegnd”).FormulaU = “=RGB(255,0,0)”
shpNew.name = “Point_” & Format(i, “000”)
setProp shpNew, “Name”, “Name”, 0, “””” & name & “”””
setProp shpNew, “Description”, “Description”, 0, “””” & description & “”””
shpMap.ContainingPage.Layers(“Point”).Add shpNew, 0
End If
Next i
Finally
Just to finish off neatly, I returned the selection to the original target map shape
Visio.ActiveWindow.DeselectAll
Visio.ActiveWindow.Select shpMap, Visio.VisSelectArgs.visSelect
Well, that completes my demonstration of how you can import KML files into Visio, although there are some refinements and additions that one can make. For example, it would be fairly trivial to create hyperlinks on each shape for any moreInfoUrl or photoUrl elements that are found.
I have uploaded the Visio file and sample KML file for downloading from : VisioKML.zip
I have started looking at creating KML files from Visio now…..