PInvoke 'class' Versus 'ref struct'

后端 未结 1 1938
难免孤独
难免孤独 2021-02-09 08:03

When I googled around I saw posts saying that passing a C# class is the same as passing ref struct to a C API while using PInvoke (here is one the post

1条回答
  •  夕颜
    夕颜 (楼主)
    2021-02-09 08:34

      [StructLayout(LayoutKind.Sequential, ...)]
    

    This is what matters. You had to apply that attribute to the class declaration. You also applied it to the struct declaration but that wasn't actually necessary, the C# compiler emits this automatically for structs. Modulo the CharSet property.

    The default [StructLayout] attribute for classes is not LayoutKind.Sequential, it is LayoutKind.Auto. Which is something the CLR takes advantage of, it will reorganize the fields in a class to come up with the best possible layout. You can read more about it in this post.

    The big difference is that it makes a class non-blittable. Which is a hundred dollar word that means that the pinvoke marshaller cannot just pass a plain pointer to the managed object, it has to convert the managed object to an unmanaged one that has the requested layout. It does so by allocating memory and copying the fields. With the consequence that any changes that the native code makes to the copy doesn't get propagated back to the original managed object.

    Unless you explicitly tell the pinvoke marshaller to do this. Fix:

        [DllImportAttribute(...)]
        public static extern void ChangeName([In, Out]Animal pAnimal);
    

    The [OutAttribute] tells it to propagate changes back.

    0 讨论(0)
提交回复
热议问题