2

I am trying to use marshalling in C#. In C++ I have a this struct:

struct aiScene { unsigned int mFlags; C_STRUCT aiNode* mRootNode; unsigned int mNumMeshes; C_STRUCT aiMesh** mMeshes; unsigned int mNumMaterials; C_STRUCT aiMaterial** mMaterials; unsigned int mNumAnimations; C_STRUCT aiAnimation** mAnimations; unsigned int mNumTextures; C_STRUCT aiTexture** mTextures; unsigned int mNumLights; C_STRUCT aiLight** mLights; unsigned int mNumCameras; C_STRUCT aiCamera** mCameras; } 

So, C# eqvivalent is:

[StructLayout(LayoutKind.Sequential)] public struct aiScene { public uint mFlags; public unsafe aiNode* mRootNode; public uint mNumMeshes; public unsafe aiMesh** mMeshes; public uint mNumMaterials; public unsafe aiMaterial** mMaterials; public uint mNumAnimations; public unsafe aiAnimation** mAnimations; public uint mNumTextures; public unsafe aiTexture** mTextures; public uint mNumLights; public unsafe aiLight** mLights; public uint mNumCameras; public unsafe aiCamera** mCameras; } 

But many on this structs are managed ( aiNode, aiMesh, aiLight ) etc. So, I have this error:

Cannot take the address of, get the size of, or declare a pointer to a managed type ('Assimp.aiNode')

Any ideas on how to solve this issue?

2 Answers 2

3

This could get very complicated depending on what you are trying to do. However, as you are working it could help you do declare each of the pointers in the C# code like this. It uses the very useful IntPtr, which was described on here earlier today. :)

Please note that this will not magically get your code to work. I'd need to see a lot more of what's going on before I could give you input on that.

public struct aiScene { public uint Flags; public IntPtr RootNode; ... } 
Sign up to request clarification or add additional context in comments.

2 Comments

Господи, что за изврат...лучше взять C++\CLI. Большое спасибо за ответ!
Using IntPtr for all these types quickly becomes a nightmare, because there is no type checking separating different types of IntPtr. It's better to use an unsafe struct . (define each type, such as aiNode, as a struct type, then use an unsafe aiNode)
0

The main problem you're having is that you've defined managed objects with the same names as the unmanaged types. The pointer types, like "aiNode", should be defined as structs, not classes. You can define differently named managed wrapper classes which provide managed access to the underlying unsafe struct data. For example:

public struct aiNode {} public struct aiScene { public uint mFlags; public unsafe aiNode* mRootNode; // ... } 

At a high level, it looks like you're trying to use AssImp from C#. That can be done today using assimp-net. However, in case someone runs into a marshalling situation like this and wants a generic answer..

I strongly recommend against using IntPtr for anything, because they are basically an untyped void* with no type checking. Unsafe-struct-pointers offer a safer disambiguation of unmanaged pointer types. SafeHandle is another option with better safety and handling of some race-conditions. See my article on the topic.

If you literally want to copy the data from unmanaged to managed land, then for each type (aiNode, aiMesh, etc) you need to define both an unsafe-struct (to match the unmanaged layout), and a managed class. Then, write (or generate) unsafe code to copy the unmanaged tree to managed objects. Be sure to be careful of any unmanaged objects with more than one reference.

Sometimes a better alternative is to write a wrapper which provides access to unmanaged data "in-place". If you are doing it "safely", then the managed wrappers should be thin-objects which manage lifetime for the unmanaged objects and have properties to access their data. Alternatively, you can do it unsafely by merely defining the unsafe structs and using them in an unsafe context.

Comments