How to Create Attribute Title + Data in C#

Hello,

I was looking to create attributes in C#. I found the CreatePRCCubes example does create attributes but it doesn’t look like a data/value is set.

Are there any examples for this? I see there is the A3DMiscSingleAttributeWrapper + A3DMiscAttributeWrapper. The A3DMiscAttributeWrapper has the m_asSingleAttributesData array with the “smart” setter but I am having trouble tying it all together.

C# example

            using var attr = new A3DMiscAttributeWrapper();
            attr.m_pcTitle = "Prototype PO, holding data.";
            Util.AppendAttribute(_po.A3DEntity, attr);

        public static A3DStatus AppendAttribute(IntPtr entity, A3DMiscAttributeWrapper attribute)
        {
            if (entity == IntPtr.Zero)
                return A3DStatus.A3D_INVALID_ENTITY_NULL;
            attribute.Create();
            IntPtr attrEntity = attribute.A3DEntity;
            return API.A3DRootBaseAttributeAppend(entity, 1, out attrEntity);
        }

The c++ example does set the data but I am not sure exactly how to replicate this in C#.

	A3DMiscSingleAttributeData Single;
	A3D_INITIALIZE_DATA(A3DMiscSingleAttributeData, Single);

	Single.m_eType   = kA3DModellerAttributeTypeString;
	Single.m_pcTitle = (char*) "Title";
	Single.m_pcData  = (char*) "Simple B-rep building demonstration";

	A3DMiscAttributeData sAttribs;
	A3D_INITIALIZE_DATA(A3DMiscAttributeData, sAttribs);

	sAttribs.m_pcTitle               = Single.m_pcTitle;
	sAttribs.m_asSingleAttributesData = &Single;
	sAttribs.m_uiSize                = 1;
	A3DMiscAttributeCreate(&sAttribs, &pAttr[0]);

Edit—

As a follow-up, I put together the following code and while it does set the attribute value - I seem to sporadically have some memory errors so I think there may be something off with the pointers/m_pcData value so still looking for verification on proper attribute value setting.

            using var attrData = new A3DMiscSingleAttributeWrapper();
            attrData.m_eType = A3DEModellerAttributeType.kA3DModellerAttributeTypeString;
            attrData.m_pcTitle = "TEST";
            var attrValue = "VALUE";
            IntPtr attrValuePtr = Marshal.StringToCoTaskMemUTF8(attrValue);
            attrData.m_pcData = attrValuePtr;

            using var attr = new A3DMiscAttributeWrapper();
            attr.m_pcTitle = attrData.m_pcTitle;
            var data = attrData.Data;
            attr.m_asSingleAttributesData = new[] { data };
            attr.Create();
            IntPtr attrEntity = attr.A3DEntity;
            API.A3DRootBaseAttributeAppend(rootProductOcc.A3DEntity, 1, out attrEntity);

Any help would be appreciated.
-Ben

I wanted to follow up and say I got the original code above working by editing the ExchangeSharp helper Utils.cs WriteStructArray(). Changing 1 boolean value to not clear memory lets the code run through. I believe it cannot clear what has not yet been set. It is possible there is another side effect to this change but it has been working successfully for me. I would be open to any input on the change.

Marshal.StructureToPtr(array[i], element, true);

to

Marshal.StructureToPtr(array[i], element, false);

Full function

        public static IntPtr WriteStructArray<T>(T[] array)
        {
            if (array.Length > 0)
            {
                var structSize = Marshal.SizeOf(typeof(T));
                IntPtr unmanagedArray = Marshal.AllocHGlobal(structSize * array.Length);
                IntPtr element = new IntPtr(unmanagedArray.ToInt64());

                for (var i = 0; i < array.Length; i++)
                {
                    Marshal.StructureToPtr(array[i], element, false);
                    element = new IntPtr(element.ToInt64() + structSize);
                }
                return unmanagedArray;
            }
            else
                return IntPtr.Zero;
        }
1 Like