我昨天发了一篇文章,如何创建最初用C ++编写的C#结构。
感谢您的回复。
我正在努力,在运行WinCE 6.0和.NET Compact框架2.0的ARM平台上使用DeviceIOControl,但是我试图实现的是控制端口引脚,这被证明是一场噩梦。 / p>
以下是PInvoke声明:
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern bool DeviceIoControlCE(int hDevice,
int dwIoControlCode,
byte[] lpInBuffer,
int nInBufferSize,
byte[] lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
PInvoke声明表明可以简单地将byte []传递给它。当然,将值写入结构的每个成员,将其转换为字节数组并将其传递给dll是一件容易的事。
我有以下内容:
[StructLayout(LayoutKind.Sequential)]
public struct pio_desc
{
unsafe byte* pin_name; //Length???
public uint pin_number; //4 bytes
public uint default_value; //4 bytes
public byte attribute; //1 byte
public uint pio_type; //4 bytes
}
和
pio_desc PA13 =新pio_desc();
现在肯定是做了类似的事情:
PA13.pin_number = AT91_PIN_PA13; //Length 4 bytes
PA13.default_value = 0; //Length 4 bytes
PA13.attribtue = PIO_DEFAULT; //Length 1 byte
PA13.pio_type = PIO_OUTPUT; //Length 4 bytes
并将(例如pin_number)转换为byte []:
byte[] temp = BitConverter.GetBytes(PA13.pin_number); //uints are 4 bytes wide
byteArray[++NumberOfChars] = temp[0];
byteArray[++NumberOfChars] = temp[1];
byteArray[++NumberOfChars] = temp[2];
byteArray[++NumberOfChars] = temp[3]; //Will need to check on Endianess
问题:
在结构PA13中,如何初始化不安全指针pin_name?该司机的作者指出,这可能是他的司机使用的。 Windows是否需要这个值?
PA13.pin_name = ??????
然后,如何将此指针转换为适合我的byte []数组的字节以传递给DeviceIOControl?
我对改变端口引脚电压的难度感到非常失望和沮丧 - 我几天来一直在努力解决这个问题。因为我来自硬件背景,所以我认为在另一个控制器上实现IO控制并通过COM端口将控制数据传递给它会更容易(并且更少资格)。
再次感谢任何(简单)帮助。
答案 0 :(得分:1)
你需要在这里做一些不同的事情。首先,替换此成员:
unsafe byte* pin_name; //Length???
使用:
[MarshalAs(UnmanagedType.LPStr)] public string pin_name;
然后将P / Invoke声明中的输入/输出缓冲区从byte[]
替换为IntPtr
。然后,您可以使用此代码转换数据:
pio_desc PA13;
// Set the members of PA13...
IntPtr ptr = IntPtr.Zero;
try {
var size = Marshal.SizeOf(PA13);
ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(PA13, ptr, false);
// Your P/Invoke call goes here.
// size will be the "nInBufferSize" argument
// ptr will be the "lpInBuffer" argument
} finally {
if (ptr != IntPtr.Zero) {
Marshal.DestroyStructure(ptr, typeof(pio_desc));
Marshal.FreeHGlobal(ptr);
}
}
答案 1 :(得分:1)
通过对[DllImport]声明的说明,你可以更轻松地做到这一点。只需将lpInBuffer参数声明为结构类型,pinvoke marshaller无论如何都会将其转换为指针。因此:
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern bool SetOutputPin(IntPtr hDevice,
int dwIoControlCode,
ref pio_desc lpInBuffer,
int nInBufferSize,
IntPtr lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);
将IntPtr用于lpOutBuffer,因为驱动程序可能不会返回任何内容。通过IntPtr.Zero。与结构相同的想法。如果未使用该字段,则只需将其声明为IntPtr:
[StructLayout(LayoutKind.Sequential)]
public struct pio_desc
{
public IntPtr pin_name; // Leave at IntPtr.Zero
public uint pin_number; //4 bytes
public uint default_value; //4 bytes
public byte attribute; //1 byte
public uint pio_type; //4 bytes
}
注意Packing属性,因为字节大小的字段,所以它在这里有所不同。你可能需要1但这只是一个猜测而不知道任何关于驱动程序。如果你有C代码,那么测试sizeof(pio_desc)的值并与Marshal.SizeOf()进行比较。将Marshal.SizeOf(typeof(pio_desc))作为nInBufferSize参数传递。如果您已经发布了C声明,那么这将更容易准确回答。
答案 2 :(得分:0)
将lpInBuffer和lpOutBuffer声明为IntPtr。使用Marshal.AllocHGlobal初始化它们(不要忘记最后将它们与Marshal.FreeHGlobal一起发布)。填充这些缓冲区并使用不同的Marshal.Copy重载读取它。