C# 当结构包含bool时,如何将GCHandle分配给结构
我一直在尝试创建一个结构类型的句柄,因为我需要一个指向它的固定指针,但是我得到了一个错误“对象包含非基本的或不可blittable的数据” 我的结构如下所示: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
[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,它必须作为指针传递此结构。然后我必须在回调中获取该结构并读取/更新成员
这就是基本情况
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; }
}
}