C#:指向结构内部结构的指针

时间:2022-09-06 11:23:31

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

我试图在C#中使用编组。在C ++中我有一个这样的结构:

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:

所以,C#eqvivalent是:

[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:

但很多关于这个结构的管理(aiNode,aiMesh,aiLight)等等。所以,我有这个错误:

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

无法获取地址,获取大小,或声明指向托管类型的指针('Assimp.aiNode')

Any ideas on how to solve this issue?

关于如何解决这个问题的任何想法?

2 个解决方案

#1


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. :)

根据您的尝试,这可能会变得非常复杂。但是,正如您正在使用它可以帮助您像这样声明C#代码中的每个指针。它使用非常有用的IntPtr,这在今天早些时候已有描述。 :)

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;
    ...
}

#2


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:

您遇到的主要问题是您已经定义了与非托管类型具有相同名称的托管对象。指针类型,如“aiNode”,应该定义为结构,而不是类。您可以定义不同名称的托管包装类,它们提供对基础不安全结构数据的托管访问。例如:

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..

从较高的层面来看,您似乎正在尝试使用C#中的AssImp。今天可以使用assimp-net完成。但是,如果有人遇到像这样的编组情况并想要一个通用的答案..

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.

我强烈建议不要使用IntPtr,因为它们基本上是一个无类型的void *,没有类型检查。不安全结构指针提供了非托管指针类型的更安全的消歧。 SafeHandle是另一种选择,可以更好地安全地处理某些竞争条件。请参阅我关于该主题的文章。

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.

如果您真的想要将数据从非托管域复制到托管域,那么对于每种类型(aiNode,aiMesh等),您需要定义unsafe-struct(以匹配非托管布局)和托管类。然后,编写(或生成)不安全的代码以将非托管树复制到托管对象。请务必小心任何具有多个引用的非托管对象。

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.

有时,更好的选择是编写一个包装器,它可以“就地”访问非托管数据。如果您“安全地”执行此操作,则托管包装器应该是瘦对象,它们管理非托管对象的生命周期并具有访问其数据的属性。或者,您可以通过仅定义不安全的结构并在不安全的上下文中使用它们来不安全地执行此操作。

#1


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. :)

根据您的尝试,这可能会变得非常复杂。但是,正如您正在使用它可以帮助您像这样声明C#代码中的每个指针。它使用非常有用的IntPtr,这在今天早些时候已有描述。 :)

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;
    ...
}

#2


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:

您遇到的主要问题是您已经定义了与非托管类型具有相同名称的托管对象。指针类型,如“aiNode”,应该定义为结构,而不是类。您可以定义不同名称的托管包装类,它们提供对基础不安全结构数据的托管访问。例如:

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..

从较高的层面来看,您似乎正在尝试使用C#中的AssImp。今天可以使用assimp-net完成。但是,如果有人遇到像这样的编组情况并想要一个通用的答案..

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.

我强烈建议不要使用IntPtr,因为它们基本上是一个无类型的void *,没有类型检查。不安全结构指针提供了非托管指针类型的更安全的消歧。 SafeHandle是另一种选择,可以更好地安全地处理某些竞争条件。请参阅我关于该主题的文章。

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.

如果您真的想要将数据从非托管域复制到托管域,那么对于每种类型(aiNode,aiMesh等),您需要定义unsafe-struct(以匹配非托管布局)和托管类。然后,编写(或生成)不安全的代码以将非托管树复制到托管对象。请务必小心任何具有多个引用的非托管对象。

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.

有时,更好的选择是编写一个包装器,它可以“就地”访问非托管数据。如果您“安全地”执行此操作,则托管包装器应该是瘦对象,它们管理非托管对象的生命周期并具有访问其数据的属性。或者,您可以通过仅定义不安全的结构并在不安全的上下文中使用它们来不安全地执行此操作。