Read UserData stored in object by C++ plug-in with RhinoCommon plug-in

Hi all,

I need to solve following problem. I have custom UserData class which is appended to the object by C++ plug-in.
Now I’m trying to rewrite this plug-in into C# using RhinoCommon and I’m facing the problem, I can’t read this user data class at all, even when I use the same GUIDs for plug-in and custom user data class.

Object detail says Unknown user data. (Definition of class was not available when object was read.) and in debugger there is no try to read this user data.

How can I do that, if it is possible? (I hope so, I have many objects with user data attached).

It should be possible. Is your RhinoCommon plug-in installed so Rhino knows to load it?

Hi Steve,
Can you let me know how to address this legacy userdata problem? I don’t want to open a new topic if I can use this old thread for discussion.

Srini

Hi Srini,

There are a couple of challenges in re-writing a C++ plug-in that utilizes custom user data in C#.

First, your user data is owned by a plug-in, and this ownership is based on the UUID of the plug-in that wrote the data. Thus, your replacement C# plug-in will need to use the same UUID as your C++ plug-in.

The biggest challenge is to be able read the user data, written in C++, in exactly the same manner, bit by bit, in C#.

An alternative approach is to refactor your C++ plug-in a bit so your C# can access the user data.

The following sample demonstrates how to share user data between 2 (or more) C++ plug-ins. This is done by having all of the user data reading and writing code in a Rhino-dependent DLL.

https://github.com/mcneel/Rhino5Samples_CPP/tree/master/SampleSharedUserData

And here is a solution that demonstrates how to have both a C++ and a C# plug-in call the same functions.

With these two samples, you should be able to see how you can refactor your C++ plug-in so it just reads the old user data. This data could be read by your C# plug-in. And, the C# plug-in would write the new user data format, thus migrating away from the old mechanism over time.

Hi Dale,
Thanks for the info. While the shared user data part is clear, the Moose project doesn’t seem to be helpful for me as I am interested in calling C# functions within my C++ layer. Unfortunately in our case the C# layer has the data I/O methods and we don’t want to move them into a C++ layer all over again.

In this case, I suppose the only option for me is to go with mixed mode C++ code, which would allow me to call an unmanaged C++ and C# methods. Am I right?

Srini

Here is exactly I would like to do in a high-level:

  1. User selects one or more solids in Rhino
  2. For each solid model our converter command retrieves the user data attached to it and converts to the new format
  3. The list of all the new data is passed on to the Rhino doc and we trigger a save to attach the data to the current Rhino doc

The steps 2 & 3 require a call into C# layer and hence I thought that it would be best to write this converter command using managed C++. However I am not sure if RhinoCommon is supported in managed C++ or not. In fact, early when we started re-architecting our plugin using .NET, this was a question I had.

Can you let me know if the above scenario is possible?

Don’t use managed C++, its…bad…

What I describe above does exactly what you want to do.

Refactor your C++ plug-in so its only purpose is to read your old user data. Make sure the user data reading code is in a DLL (as demonstrated by the first sample).

Then:

  1. User selects one or more solids in Rhino

  2. For each solid model our converter command retrieves the user data attached to it and converts to the new format. This is done by calling into your C++ DLL from your C# code as demonstrated in the second sample. While your there, call your ‘Delete User Data’ function to purge the object of the old user data.

  3. The list of all the new data is passed on to the Rhino doc and we trigger a save to attach the data to the current Rhino doc

Done!

Ok I get it. Based on your approach, the “front-end” of the converter is in C# and the “back-end” is
in unmanaged C++. But, is there a way to get the converted data from the back-end to the front-end? If it is, then I can reuse a most of my existing code for this process. Otherwise, I may be write some new code.

Another approach I can take is to write the converter entirely in unmanaged C++.

Not sure which one would be better (in terms of code reuse, etc).

This topic has come up a few times recently. I actually think writing all of the code in C# for reading the user data should be possible in Mac Rhino and in Rhino 6. Unfortunately for Rhino 5 I would definitely go with the route that Dale recommends (mixing some C++ with C#)

Thanks Steve and Dale for your ideas. From this and also from my snooping around our code, I came to the decision of sticking with unmanaged C++ implementation completely, as I don’t require to get into managed layer at all!

Dale/Steve, one question related to the user data and plugin relationship. Is it necessary to use architecture suggested by your SharedUserData example? Can’t we use the same user data id in two different plugins?

I don’t understand the question. What other architecture would you use?

No. User data is owned by one, and only one, plug-in.

Ok thanks for the clarification!

So this implies that any existing plugins that our customers have will need to be updated with the new plugin using this architecture, am I right?

One more complication you may want to think about: what happens when customer1 has upgraded and shares their work with customer2 that has not upgraded?

Hmmm…that sounds plausible. Btw, would it help avoid this new architecture if we give our new plug-in the same UUID as our old plugin?

Dale/Steve,
Can you guys answer my last question:

  • Is it possible to avoid the above architecture for sharing user data by using the same plugin ID between the two plugins?

Thanks,
Srini

Plug-in IDs must be unique. Rhino will not load plug-ins with duplicate IDs.