Using DropMany in a VSTO add-in (VB.NET)

Started by Visisthebest, December 21, 2020, 03:26:16 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Visisthebest

In the Microsoft Visio dev documentation, there is this helpful VBA example for using DropMany:
https://docs.microsoft.com/en-us/office/vba/api/visio.page.dropmany

I am trying to convert this to an altered VB.NET example in a VSTO Add-in, but obviously VB.NET does not allow Variants. Trying to create an Array of Objects (references) also raises an error.

I understand the first argument of the DropMany function:
ObjectsToInstance() should be a one-dimensional array of n >= 1 variants

Is a variant containing an array of variants, I guess this is the key issue why this generates an error. Marshaling this back and forth across the .net interop doesn't just work automatically it seems.

How can I use DropMany from a VB.NET addin?

Did some performance testing and just using Drop for 2000 shapes is MUCH slower than from VBA, so DropMany can certainly help reduce calls across the .NET interop hopefully improving performance. Thank you for your help!


Public Sub DropMany_Example()

On Error GoTo HandleError

Dim vsoMasters As Visio.Masters
Dim intMasterCount As Integer
Set vsoMasters = ThisDocument.Masters
intMasterCount = vsoMasters.Count

ReDim varObjectsToInstance(1 To intMasterCount) As Variant
ReDim adblXYArray(1 To intMasterCount * 2) As Double
Dim intCounter As Integer
For intCounter = 1 To intMasterCount

'Pass name of object to drop to DropMany.
varObjectsToInstance(intCounter) = vsoMasters.Item(intCounter).Name

'Set x components of where to drop to 2,4,6,2,4,6,2,4,6,...
adblXYArray (intCounter * 2 - 1) = (((intCounter - 1) Mod 3) + 1) * 2

'Set y components to 2,2,2,4,4,4,6,6,6,...
adblXYArray (intCounter * 2) = Int((intCounter + 2) / 3) * 2

Next intCounter

Dim aintIDArray() As Integer
Dim intProcessed As Integer

intProcessed = ThisDocument.Pages(1).DropMany(varObjectsToInstance, _
adblXYArray, aintIDArray)
Debug.Print intProcessed

For intCounter = LBound(aintIDArray) To UBound(aintIDArray)
Debug.Print intCounter; aintIDArray(intCounter)
Next intCounter

Exit Sub

HandleError:
MsgBox "Error"

Exit Sub

End Sub



Should I pass a VariantWrapper object as an argument in VB.NET as a replacement for the Variant in VBA?

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.variantwrapper?view=net-5.0
Visio 2021 Professional

Nikolay

#1
Replace the word "Variant" with "Object". You probably should be able to see this in the error message you get, just read it  :)
Other than that, make sure you use 0-based arrays and not 1-based in VB.NET.

Your example rewritten for VB.NET:


Public Sub DropMany_Example()

        Dim vsoMasters As Visio.Masters
        Dim intMasterCount As Integer

        Dim ThisDocument As Visio.Document
        ThisDocument = Globals.ThisAddIn.Application.ActiveDocument

        vsoMasters = ThisDocument.Masters
        intMasterCount = vsoMasters.Count

        Dim varObjectsToInstance(intMasterCount - 1) As Object
        Dim adblXYArray(intMasterCount * 2 - 1) As Double
        Dim intCounter As Integer
        For intCounter = 0 To intMasterCount - 1

            'Pass name of object to drop to DropMany.
            varObjectsToInstance(intCounter) = vsoMasters.Item(intCounter + 1).Name

            'Set x components of where to drop to 2,4,6,2,4,6,2,4,6,...
            adblXYArray(intCounter * 2) = (((intCounter - 1) Mod 3) + 1) * 2

            'Set y components to 2,2,2,4,4,4,6,6,6,...
            adblXYArray(intCounter * 2 + 1) = Int((intCounter + 2) / 3) * 2

        Next intCounter

        Dim aintIDArray() As Short
        Dim intProcessed As Integer

        intProcessed = ThisDocument.Pages(1).DropMany(varObjectsToInstance, adblXYArray, aintIDArray)
        Debug.WriteLine(intProcessed)

    End Sub

Visisthebest

Thank you Nikolay then I obviously did something else wrong as well, as the .NET COM interop does take care of this.

Will try it right away, still getting used to VB in .NET!
Visio 2021 Professional

Visisthebest

Tried it works really well thank you Nikolay!
Visio 2021 Professional

Nikolay

#4
Regarding performance, I think Visio 2003  + VBA is unbeatable, this combination could be 10x times faster than Visio 2019 + VB.NET :)

When I was really thinking about performance in one project, was considering pure XML generation as well (i.e. without Visio).
It does not seem to be impossible, just hard, considering there is no Open Xml SDK for Visio and no examples, just schema reference.
But packaging is still there, it's shared between all office document formats.

Visisthebest

Yes that is an interesting option no doubt would be much faster.

Just tested Manydropping 3000+ shapes with DropMany over the interop and it is a lot faster for sure!

I will benchmark the difference with Drop but now it was just a few seconds (on a 5+ year old laptop) versus Drop and thinking Visio crashed because it takes so long.

Thank you!

Visio 2021 Professional

Nikolay

Just out of curiosity, checked GitHub. There is a recent project popped up regarding this! And it does not look like someone else's clone or anything. The guy seems to actually trying to break through it  ;D
https://github.com/ihordeyneka/json2visio

Visisthebest

Wow amazing! Still plenty of projects going on with Visio!

Microsoft also published some impressive case studies like with Swiss rail.
Visio 2021 Professional

Visisthebest

Unofficial benchmark (timing with the stopwatch app on iPad) but for a 3000+ shape drop DropMany is at least 3 times as fast as using Drop!

If I also set:
Application.ShowChanges = False
Application.DeferRecalc = True
Application.Settings.UndoLevels = 0
(and restore settings afterwards)

another 2x speedup. (I don't know which of the three settings helps most though)

turning off page autosize (did it via the UI) is also essential (I turn it off in all drop tests) for speed.

I think with 500 shape drops DropMany is much faster than 3x because you see that Visio itself slows down with 3000+ shapes on the page.

Great thank you Nikolay!
Visio 2021 Professional

Visisthebest

For connecting up the shapes from an add-in in bulk, I got the advice on the forum earlier to use Page.SetFormulas:
https://docs.microsoft.com/en-us/office/vba/api/visio.page.setformulas

I guess the way to use it is:
1. Drop all the connectors with DropMany from the add-in
2. Wire up all the 1D connectors to the shapes by using Page.SetFormulas and setting in the 1-D Endpoints Section: the BeginX/BeginY and EndX/EndY to the specific shapes and connection points to be wired up.

Visio 2021 Professional