.NET vs VBA

Stephen A

.NET vs VBA

Hello,

I have been trying to develop new macros in c# .NET, but have now noticed that tasks take many time longer than the same operation in VBA

Just curious if anyone else programs in .NET and has any tips or workarounds to speed it up?

I've tried invoking a VBA script with SystemService.Evaluate, but it's extremely inconvenient and actually seems to be even slower if I am only sending one line of code through it.

I am fairly new to .NET, so any examples would be much appreciated.

Thanks!

Little Cthulhu

RE: .NET vs VBA
(in response to Stephen A)

Hi.

In terms of speed:

CAA -> CATScript -> VBA

Formally .NET is on par with CATScript in making Automation calls. However, performance drops drastically because of how .NET manages COM objects, that is all objects that are exposed by CATIA via Automation.

Each time you access COM object .NET CLR creates Runtime Callable Wrapper (RCW) that implicitly marshals all calls to actual COM object's methods. It does so in a decent way, but it is a construction of RCW that takes a lot of time.

At this time it's important to understand how CATIA itself creates COM objects to be consumed by Automation clients.  CATIA is written in a C++ framework named CAA that is "Component Application Architecture". Each logical "object" (say, a point) is represented with a set of components each providing certain behavior (implementing interface): visualization, geometrical model, update mechanism etc. So when an object gets exposed to Automation (you access it with a script) another component gets created that allows access to a certain object properties and methods, exposing this object to a client application. And the key thing is that such component is created (almost) each time you access underlying object.

So when you go:

var firstObject = CATIA.ActiveDocument.Selection.Item(1);
var objectOne = CATIA.ActiveDocument.Selection.Item(1);

you get two COM-objects that point to the same CATIA object. The problem here is that for .NET CLR these objects are not identical, so it creates RCW for each of them wasting twice as much time.

So what you want to do is to make sure that for each COM object RCW is created exactly once. Basically, you keep reference to every object retrieved (for instance store it in a collection of any sort) and then reuse it throughout the whole application.

 

In real life we use .NET for applications that implement any business logic and CATScript for small utilities. Calling CATScript from .NET is not only tedious, but also has a significant performance cost since a script engine should be created in order to execute a given script. So if you have to call a CATScript from .NET, do it once per application lifetime or seriously benchmark performance otherwise.

Stephen A

RE: .NET vs VBA
(in response to Little Cthulhu)

Thanks for such a detailed response. It definitely sounds like the exact issue that I am running in to.

We have some licenses of CAA at my company, but I do not currently have access to one (or have any experience with C++). I will have to look in to that if you think it would help my situation.

I tried as you said and stored the retrieved objects in a collection, but then ran in to the problem of having no way to compare a new object against my collection to see if it had already gone through the RCW.

An example of what I'm trying to do is loop through all products/parts in an assembly, and retrieve the PLM attribute values.

So if my product has two instances of the same bolt/washer, how can I avoid wrapping both of those objects?
I tried comparing the object but no matter what I tried it returned as not equal.
(Even product1 == product1.Instances.Parent returns false)

And then once I have the object inside of .NET I have another loop that is similar to this:
product1.GetAttributeValue("Name")
product1.GetAttributeValue("Revision")
product1.GetAttributeValue("Description"), etc.

25 attributes in all and it takes a VERY long time to gather them, but is almost instantaneous in VBA.

Is there a different methodology for that kind of repeated query on a wrapped object?

Thanks again for the help!

Little Cthulhu

RE: .NET vs VBA
(in response to Stephen A)

If you measure .GetAttributeValue calls alone time spent should be identical to CATScript as this method returns scalar value that is marshaled directly.

Comparing two CATIA COM-objects is absolutely the key in both CATScript and .NET. Unfortunately there's no way to do it in V5, so we've developed CAA extension that exposes to Automation an object identifier that is unique throughout CATIA session:

product1.GetItem("OurExtension").UniqueIdentifier

This identifier is actually a memory address of underlying CAA object so it has the same value for all COM wrappers of the same CAA object.

Stephen A

RE: .NET vs VBA
(in response to Little Cthulhu)

That CAA extension does sound very useful. We use V6 and 3DX here, but it doesn't seem like any unique object identifier exists in these versions either.

I asked one of our CAA developers and got this response:
"It is possible and we have documentation on how to do it… but we have never been able to get it to work. We do have a working way to expose CAA to EKL, but not to .NET."

I will have to do more research on what we've tried. Thanks again for the help.

Little Cthulhu

RE: .NET vs VBA
(in response to Stephen A)

.NET consumes any COM interfaces provided there's a .tlb that can be used to generate interop .dlls with tlbimp.exe

A way to expose CAA to Automation (that is to COM) is described in Creating Interfaces for Automation and Implementing Interfaces for Automation artices of CAA Encyclopedia. There's even a use-case.

It works as expected both in CATScript and .NET, we've implemented dozens of custom interfaces with hundreds of functions in total.