C
Join ServerC#
help
✅ Interoperability between incompatible types
Rrick_o_max12/9/2022
Hi!
I'm trying to pass a class back-and-forth from C# to CPP.
This class contains some members that I can't and don't need to translate to CPP types, but when I add these members to my interop classes, the application exits with a fatal error.
I'm trying to pass a class back-and-forth from C# to CPP.
This class contains some members that I can't and don't need to translate to CPP types, but when I add these members to my interop classes, the application exits with a fatal error.
Rrick_o_max12/9/2022
This is my CPP class:
This is my C# class:
If I use the classes as they are, it works fine, but if I uncomment the lines on C# and CPP, the application crashes. It might have something to do with the way these references are passed to CPP. I don't need their types in CPP, I just need to keep a reference to them.
typedef struct TModel
{
char* Name;
bool Used;
Vector3 LocalPosition;
Quaternion LocalRotation;
Vector3 LocalScale;
bool Visibility;
//void* Parent;
//void* Children;
//void* Bones;
//bool IsBone;
//void* GeometryGroup;
//void* BindPoses;
//void* MaterialIndices;
//void* UserProperties;
} Model;
This is my C# class:
[StructLayout(LayoutKind.Sequential, CharSet = Interoperability.DefaultCharSet)]
public class Model// : IModel
{
[field: MarshalAs(UnmanagedType.LPStr)]
public string Name { get; set; }
[field: MarshalAs(UnmanagedType.U1)]
public bool Used { get; set; }
public Vector3 LocalPosition { get; set; }
public Quaternion LocalRotation { get; set; }
public Vector3 LocalScale { get; set; }
[field: MarshalAs(UnmanagedType.U1)]
public bool Visibility { get; set; }
//public IModel Parent { get; set; }
//[field: MarshalAs(UnmanagedType.LPStruct)]
//public IList<IModel> Children { get; set; }
//[field: MarshalAs(UnmanagedType.LPStruct)]
//public IList<IModel> Bones { get; set; }
//[field: MarshalAs(UnmanagedType.U1)]
//public bool IsBone { get; set; }
//public IGeometryGroup GeometryGroup { get; set; }
//[field: MarshalAs(UnmanagedType.LPStruct)]
//public Matrix4x4[] BindPoses { get; set; }
//[field: MarshalAs(UnmanagedType.LPStruct)]
//public IList<int> MaterialIndices { get; set; }
//[field: MarshalAs(UnmanagedType.LPStruct)]
//public Dictionary<string, object> UserProperties { get; set; }
}
If I use the classes as they are, it works fine, but if I uncomment the lines on C# and CPP, the application crashes. It might have something to do with the way these references are passed to CPP. I don't need their types in CPP, I just need to keep a reference to them.
OOryp4ik12/9/2022
IModel is a managed type, since it's (probably) an interface
Rrick_o_max12/9/2022
I just realized I haven't added the LPStruct to the Parent member, let me see if that makes any difference
OOryp4ik12/9/2022
I have no idea if it will help
Rrick_o_max12/9/2022
No, it doesn't
Rrick_o_max12/9/2022
Yes, it is a managed type
Rrick_o_max12/9/2022
But can't I keep a reference to it as a
void*
when passing the struct to cpp?OOryp4ik12/9/2022
doesn't make sense to me, since GC is moving
Rrick_o_max12/9/2022
I don't need CPP to touch these commented out fields, but I have to keep them "alive" while passing the struct/class back and forth
Rrick_o_max12/9/2022
hmm
Rrick_o_max12/9/2022
I'll probably have to wrap the fields I can interop inside another class
OOryp4ik12/9/2022
if you need to keep them alive, just use GC.KeepAlive
OOryp4ik12/9/2022
call it after your native method
OOryp4ik12/9/2022
although it doesn't make sense to me
OOryp4ik12/9/2022
bc if you don't want to touch them but want to keep them alive... it's either that C++ does touch them, or you just have no reference to it afterwards, but then why keep alive?
Rrick_o_max12/9/2022
I don't want to create the structs on CPP heap, so I'm creating everything on C# and passing the objects to CPP. CPP can change the fields, but won't create anything (besides strings allocations)
Rrick_o_max12/9/2022
CPP calls a C# callback
C# creates the objects and send the pointer back to CPP
CPP modifies the objects
C# creates the objects and send the pointer back to CPP
CPP modifies the objects
Rrick_o_max12/9/2022
But well, thinking better
Rrick_o_max12/9/2022
I'm still not 100% sure about the best way to handle that
OOryp4ik12/9/2022
honestly, idk either
I usually do it all manually to ensure it works as I expect
but it's probably a bad advice
I usually do it all manually to ensure it works as I expect
but it's probably a bad advice
Rrick_o_max12/9/2022
Wdym with manually?
Rrick_o_max12/9/2022
Looks like I can pass the entire struct as pointer with
Rrick_o_max12/9/2022
Marshal.StructureToPtr
Rrick_o_max12/9/2022
That requires creating a buffer, tho
OOryp4ik12/9/2022
manually as in, with structs, pointers, and 0 managed objects whatsoever
Rrick_o_max12/9/2022
The only problem is I have to use some managed classes, and part of the classes holding these other classes must come from CPP
Rrick_o_max12/9/2022
I know I can make it field by field, by calling CPP methods and creating some system to track the classes by id or something like that
Rrick_o_max12/9/2022
But that is a lot of work
AAntonC12/9/2022
check out the actual layout of your class
AAntonC12/9/2022
layout sequential would put reference types on top anyway
AAntonC12/9/2022
if I remember correctly
AAntonC12/9/2022
you need layout explicit for it to actually apply
AAntonC12/9/2022
from the docs:
For non-blittable types, it controls the layout when the class or structure is marshaled to unmanaged code, but does not control the layout in managed memory. Use the attribute with LayoutKind.Explicit to control the precise position of each data member. This affects both managed and unmanaged layout, for both blittable and non-blittable types.
For non-blittable types, it controls the layout when the class or structure is marshaled to unmanaged code, but does not control the layout in managed memory. Use the attribute with LayoutKind.Explicit to control the precise position of each data member. This affects both managed and unmanaged layout, for both blittable and non-blittable types.
AAntonC12/9/2022
by non-blittable they mean types with fields of reference type
AAntonC12/9/2022
or show us how you marshal the object
Rrick_o_max12/9/2022
Interesting
Rrick_o_max12/9/2022
Is there a way to set a type blitting as a pointer only?
Rrick_o_max12/9/2022
Bc the only thing I need, is keep the same structure from the C# class in CPP
Rrick_o_max12/9/2022
I don't need CPP to touch some fields
Rrick_o_max12/9/2022
There are classes I can't interop anyway, like
Dictionary
instances from my C# classesRrick_o_max12/9/2022
If there is no way to do that, I'll have to create simpler structures to work on CPP, and wrap these in the final C# classes which contains all the properties I need
Rrick_o_max12/10/2022
The point is that, I don't want to create huge wrappers around my classes or using Swig to do that
Rrick_o_max12/10/2022
Can't use CLI either
Rrick_o_max12/10/2022
So my idea is letting C# handle the objects creation while CPP only fires C# callbacks
Rrick_o_max12/10/2022
Well, I guess I don't need to read any specific data form the C# classes in CPP anyway
Rrick_o_max12/10/2022
So using callbacks might work fine
Rrick_o_max12/10/2022
So, looks like it should work
Rrick_o_max12/10/2022
But Idk if what I'm doing is "Ilegal", like
Rrick_o_max12/10/2022
I'm passing a struct containing all my callbacks to CPP
Rrick_o_max12/10/2022
But when CPP calls these callbacks, program crashes
Rrick_o_max12/10/2022
It used to work fine when these callbacks were outside the struct
Rrick_o_max12/10/2022
But I use the struct to pass all callbacks at once
Rrick_o_max12/10/2022
I'm passing a
CallbackData
struct by val to CPP, it seems to get the values right, but throws an error when calling any callback methodRrick_o_max12/10/2022
Nvm, values are messed up somehow...hmm
AAntonC12/10/2022
generally use properties if possible, then you don't have to care about the layout. You just get a pointer to some memory on the cpp side, and then use properties to work with that
AAntonC12/10/2022
that's generally how library abstraction works in C too
AAntonC12/10/2022
they pass around an opaque pointer (handle), and have a bunch of operations defined for it
AAntonC12/10/2022
here you'd just have the operations be methods, which is arguably easier to work with
AAntonC12/10/2022
Unity does it the other way — they define the layout on the cpp side, and have wrappers with properties on the C# side
Rrick_o_max12/10/2022
I ended up doing everything differently
Rrick_o_max12/10/2022
Since I just care about the final objects created in C#
Rrick_o_max12/10/2022
I pass a series of callbacks to C
Rrick_o_max12/10/2022
So it can pass the data C# needs to create and update the structures
Rrick_o_max12/10/2022
I'm not sure about C to C# callback performance, tho
Rrick_o_max12/10/2022
But it is working as expected
AAccord12/11/2022
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.