由于封送问题,无法从C#p/调用C方法 [英] Cannot p/invoke C method from C# due to marshalling issues

查看:76
本文介绍了由于封送问题,无法从C#p/调用C方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试调用下面的I2CTransfer函数,并立即获得System.NotSupportedException.我怀疑我的编组错了,但是无法解决问题.

I'm trying to invoke the I2CTransfer function below, and immediately getting a System.NotSupportedException. I suspect my marshalling is wrong, but cannot work out the problem.

这是C结构:

BOOL I2CTransfer(HANDLE hDev, PI2C_TRANSFER_BLOCK pI2CTransferBlock);


typedef struct {
    I2C_PACKET *pI2CPackets;
    INT32 iNumPackets;
} I2C_TRANSFER_BLOCK, *PI2C_TRANSFER_BLOCK;



typedef struct {
    BYTE byAddr;
    BYTE byRW;
    PBYTE pbyBuf;
    WORD wLen;
    LPINT lpiResult;
} I2C_PACKET, *PI2C_PACKET;


这是我正在尝试的c#结构:


And here are the c# structures I'm attempting:

[DllImport("i2csdk.dll", EntryPoint = "I2CTransfer")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool I2CTransfer(IntPtr hI2C,ref I2C_TRANSFER_BLOCK pI2CTransferBlock);


[StructLayout(LayoutKind.Sequential)]
public struct I2C_TRANSFER_BLOCK
{
    public I2C_PACKET[] pI2CPackets;
    public int iNumPackets;
}


[StructLayout(LayoutKind.Sequential)]
public struct I2C_PACKET
{
    public byte byAddr;
    public byte byRW;
    public byte[] pbyBuf;
    public UInt16 wLen;
    public IntPtr lpiResult;
}


呼叫代码:


Calling code:

I2C_TRANSFER_BLOCK i2CTransferBlock = new I2C_TRANSFER_BLOCK();
I2C_PACKET packet = new I2C_PACKET();
int result;
IntPtr resultPtr = IntPtr.Zero;


//Populating data...
byte[] pBuf = new byte[1 + pbData.Length];
pBuf[0] = (byte) ((regStart & 0x7F) << 1);
Array.Copy(pbData, 0, pBuf, 1, pbData.Length);

// Fill packet for register write
packet.pbyBuf = pBuf;
packet.wLen = (ushort) pBuf.Length;
packet.byRW = NativeConstants.I2C_RW_WRITE;
packet.byAddr = address;
packet.lpiResult = resultPtr;

// Fill transfer block
i2CTransferBlock.pI2CPackets = new I2C_PACKET[] {packet};
i2CTransferBlock.iNumPackets = 1;

// NotSupportedException here
bool brc = I2CTransfer(port, ref i2CTransferBlock);


在调用该方法之前,使用C#初始化数组.


The arrays are initialized in C# before calling the method.

我尝试添加 [MarshalAs(UnmanagedType.LPArray)]

I've tried adding [MarshalAs(UnmanagedType.LPArray)]

对阵列(pI2cPackets和pbyBuf)无济于事.

to the arrays (pI2cPackets, and pbyBuf) to no avail.

这是在Windows CE-精简框架.NET 3.5上.

This is on Windows CE - compact framework, .NET 3.5.

以上翻译明显有问题吗?

Is there something obviously wrong with the above translation?

非常感谢.

推荐答案

您的问题出在结构体中的指针中:

Your problems are in the pointers contained in the structs:

[StructLayout(LayoutKind.Sequential)]
public struct I2C_TRANSFER_BLOCK
{
    public I2C_PACKET[] pI2CPackets; // here ....
    public int iNumPackets;
}


[StructLayout(LayoutKind.Sequential)]
public struct I2C_PACKET
{
    public byte byAddr;
    public byte byRW;
    public byte[] pbyBuf; // .... and here
    public UInt16 wLen;
    public IntPtr lpiResult;
}

您不能说服p/invoke编组器将指向嵌套在结构内部的数组的指针编组.这种编组形式仅适用于功能参数.

You cannot persuade the p/invoke marshaller to marshal pointers to arrays that are embedded inside structs. That form of marshalling is only available for function parameters.

您需要将这两个字段都声明为IntPtr并手动进行编组.

You'll need to declare both of those fields as IntPtr and do the marshalling by hand.

这篇关于由于封送问题,无法从C#p/调用C方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆