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

时间:2009-07-19 02:16:26

标签: c# marshalling

我正在尝试在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;
}

所以,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;
}

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

  

不能拿地址,拿到   size的大小,或声明指向a的指针   托管类型('Assimp.aiNode')

有关如何解决此问题的任何想法?

2 个答案:

答案 0 :(得分:3)

这可能会变得非常复杂,具体取决于您要做的事情。但是,正如您正在使用它可以帮助您像这样声明C#代码中的每个指针。它使用very useful IntPtr, which was described on here earlier today。 :)

请注意,这不会让你的代码神奇地工作。在我给你提供意见之前,我需要看到更多正在发生的事情。

public struct aiScene
{
    public uint Flags;
    public IntPtr RootNode;
    ...
}

答案 1 :(得分:0)

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

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

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

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

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

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