Eri*_*ler 10 c# pinvoke pointers
我一直在尝试创建一个结构类型的句柄,因为我需要一个指向它的固定指针,但我收到错误"对象包含非原始或非blittable数据"
我的结构看起来像这样:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U1)]
public bool Test;
}
Run Code Online (Sandbox Code Playgroud)
现在,当我打电话的时候
var mystruct = new MyStruct();
var handle = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
Run Code Online (Sandbox Code Playgroud)
我收到错误"对象包含非原始或非blittable数据".现在我明白bool字段是一个非blittable类型.但我的印象是,通过添加MarshalAs属性,我可以告诉marshaller如何转换类型.(我也试过UnmanagedType.Bool)
这个结构必须全局定义,因为我的课程需要它.我需要指针的唯一原因是因为我有一个非托管API,必须将此结构作为指针传递.然后我必须在回调和读取/更新成员中获得该结构.
所以这是基本情景.
我试图使用,Marshal.StructureToPtr但这只创建一个副本,所以如果在我的托管类中我更新成员,当引发回调时,更新的值不存在.
有谁知道如何获得指向我的结构的固定指针,以便我可以读取/修改公共成员并让它们在回调中可用?
谢谢
Han*_*ant 14
你在这里遇到了不止一个问题.使用结构是非常不可取的.它将在GCHandle.Alloc()调用之前被装箱,并且该盒装对象被固定.您无法通过mystruct变量看到任何更新.请改用一个班级.
并且避免bool,由于其高度可变的实现,它是一种非blittable类型.它是C中的4个字节,C++中的1个字节,COM中的2个字节.只需改为一个字节.你可以写一个属性让它回到一个布尔.
所以:
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{
private byte _test;
public bool Test {
get { return _test != 0; }
set { _test = value ? 1 : 0; }
}
}
Run Code Online (Sandbox Code Playgroud)
小智 7
你告诉编组人如何编组这种类型你是对的.
但是当你试图绕过编组时,这对你没有任何好处.
您需要决定是否要使用编组器,或者是否希望非托管代码直接写入托管内存.
如果你想使用marshaller:
通常,处理此问题的一种好方法是在两个方向上使用它.您可以使用Marshal.StructureToPtr(如您所见)调用外部函数,然后使用Marshal.PtrToStructure它将其转换回您的托管表示.
或者,您可以使用以自动编组方式设置的方法,而无需手动指定.例如,调用带有ref MyStruct参数的本机方法将允许这种情况发生.
如果您不想使用marshaller:
不要使用任何需要编组的类型.正如Hans Passant所说,使用不同的类型,byte可能是一个不错的选择.
(我将不再评论在这里使用结构的优点和缺点,除了已经提出的关于它的要点非常值得阅读和理解.)
| 归档时间: |
|
| 查看次数: |
2031 次 |
| 最近记录: |