C# 当结构包含bool时,如何将GCHandle分配给结构

C# 当结构包含bool时,如何将GCHandle分配给结构,c#,pointers,pinvoke,C#,Pointers,Pinvoke,我一直在尝试创建一个结构类型的句柄,因为我需要一个指向它的固定指针,但是我得到了一个错误“对象包含非基本的或不可blittable的数据” 我的结构如下所示: [StructLayout(LayoutKind.Sequential)] public struct MyStruct { [MarshalAs(UnmanagedType.U1)] public bool Test; } 现在,当我打电话时 var mystruct = new MyStruct(); var han

我一直在尝试创建一个结构类型的句柄,因为我需要一个指向它的固定指针,但是我得到了一个错误“对象包含非基本的或不可blittable的数据”

我的结构如下所示:

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    [MarshalAs(UnmanagedType.U1)]
    public bool Test;
}
现在,当我打电话时

var mystruct = new MyStruct();
var handle = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
我得到的错误是“对象包含非基本数据或不可删除的数据”。现在我知道布尔场是一种不可空降的类型。但我的印象是,通过添加MarshalAs属性,我可以告诉封送员如何转换类型。(我还尝试了
UnmanagedType.Bool

这个结构必须在全局范围内定义,因为它在整个类中都是必需的。我需要指针的唯一原因是因为我有一个非托管API,它必须作为指针传递此结构。然后我必须在回调中获取该结构并读取/更新成员

这就是基本情况

  • 结构是在托管类中全局创建的
  • 获取指向结构的指针
  • 指向结构的指针被传递到API中
  • API调用一个静态方法回调,然后我需要在其中获取结构和读取/更新成员
  • 我尝试使用
    Marshal.StructureToPtr
    ,但这只会创建一个副本,因此如果在托管类中我更新了成员,则在引发回调时,更新的值不存在

    有人知道如何获得指向我的结构的固定指针,以便读取/修改公共成员并使它们在回调中可用吗


    谢谢你这里有不止一个问题。使用结构是非常不可取的。它将在GCHandle.Alloc()调用之前装箱,并且装箱的对象将被固定。您无法通过mystruct变量看到对它的任何更新。改为使用类

    避免bool,因为它的实现高度可变,所以它是一种不可blittable类型。C中有4字节,C++中有1字节,COM中有2字节。把它改成一个字节。您可以编写一个属性以将其返回到bool

    因此:


    你告诉封送员如何封送类型是对的

    但是当你试图绕过元帅时,这对你没有任何好处

    您需要决定是使用封送拆收器,还是希望非托管代码直接写入托管内存

    如果要使用封送拆收器:

    通常,处理这个问题的一个好方法是在两个方向上使用它。您可以使用
    Marshal.StructureToPtr
    (如您所发现的),调用外部函数,然后使用
    Marshal.PtrToStructure
    将其转换回托管表示形式

    或者,您可以使用设置为自动进行编组的方法,而无需手动指定。例如,使用
    ref MyStruct
    参数调用本机方法将允许这种情况发生

    如果您不想使用封送拆收器:

    不要使用任何需要编组的类型。正如Hans Passant评论的那样,使用另一种类型,
    byte
    可能是一个不错的选择


    (我不会在这里评论使用struct的优点和缺点,除非已经提到的要点非常值得阅读和理解。)

    下面是可blittable类型的列表,我确实也尝试过将其作为一个类使用,但我一直在尝试强制它使用bool类型。我读了@hvd的答案,他是对的。看起来马绍拉斯在那里什么也没做。我曾尝试将其作为int,只是想看看是否可以创建一个
    GCHandle
    ,我可以,但我不喜欢它的想法。我将此标记为答案,因为我没有考虑使用属性包装成员。我要试试这个!谢谢ECMA-335 11.7.4说“布尔值。4字节整数值,其中任何非零值表示真,0表示假。”这在我听来并不是高度可变的。我将假设这是一个疏忽,或者可能是因为语义不同于常规整数类型,而不是一个技术决定。
    [StructLayout(LayoutKind.Sequential)]
    public class MyStruct
    {
        private byte _test;
        public bool Test {
           get { return _test != 0; }
           set { _test = value ? 1 : 0; }
        }
    }