如何通过Pinvoke传递指向结构的指针?

时间:2010-02-12 15:06:37

标签: c# compact-framework pinvoke marshalling

我正在尝试将C#写成以下内容:

typedef struct BATT_ID
{
    UINT8       nBattID[8];
} BATT_ID, *PBATT_ID;

HANDLE  g_hDevice;

// Connect to the driver
g_hDevice = CreateFile(L"BAT1:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

void GetBattID(PBATT_ID pBattId)
{
    // ... snipped code to check g_hDevice is valid ...

    DeviceIoControl(g_hDevice, SOMO650_PWR_GET_BATT_ID, NULL, 0, pBattId, sizeof(BATT_ID),  dwByteReturn, NULL))
}

// once BATT_ID has been filled it can be formatted as follows
wsprintf(strInfo, TEXT("%02X:%02X:%02X:%02X:%02X:%02X"), BattID.nBattID[6], BattID.nBattID[5], BattID.nBattID[4], BattID.nBattID[3], BattID.nBattID[2], BattID.nBattID[1]);

代码连接到Windows Mobile设备的电源驱动程序并尝试检索电池ID 这是针对SoMo650的最新ROM版本,Socket只能用C语言提供示例代码。

除了调用DeviceIoControl之外,我可以成功完成所有事情(尽我所知),因为我不知道如何将BATT_ID结构转换为C#。

我猜这是因为它是一个结构,而DeviceIoControl需要一个指针,我应该看看Marshal.PtrToStructure(),但我的C经验非常少,感觉非常深刻。

任何协助都将不胜感激。

2 个答案:

答案 0 :(得分:5)

您可能最好使用具有电池控制功能的Smart Device Framework。请点击此处查看社区版的下载链接。

修改:如果你仍然想要结构的pinvoke相当于这里:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BATT_ID
{
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I8)]
      public int[] nBattId;
};

然后在p /调用之前,您需要签名为“DeviceIoControl”,如下所示:

[DllImport("coredll.dll", EntryPoint="DeviceIoControl", SetLastError=true)]
        internal static extern int DeviceIoControlCE(
            int hDevice, 
            int dwIoControlCode, 
            byte[] lpInBuffer, 
            int nInBufferSize, 
            byte[] lpOutBuffer, 
            int nOutBufferSize, 
            ref int lpBytesReturned, 
            IntPtr lpOverlapped);

电话会是这样的:

IntPtr ptr = IntPtr.Zero;
BATT_ID battId;
int sz = Marshal.SizeOf(battId.GetType());
ptr = Marshal.AllocHGlobal(sz);
Marshal.StructureToPtr((BATT_ID)battId, ptr, false);
byte[] pBattId = ptr.ToPointer();
out int bytesReturned = 0;
DeviceIoControl(handle, IOCONTROL_ID, null, 0, pBattId, sz, ref bytesReturned, IntPtr.Zero);
battId = Marshal.PtrToStructure(ptr, battId.GetType());
Marshal.FreeHGlobal(ptr);

我希望我有这个权利......

编辑#2:正如 ctacke (谢谢!)指出我的代码示例错误...

unsigned byte[8] battId;
DeviceIoControl(g_hDevice, SOMO650_PWR_GET_BATT_ID, null, 0, battId, Marshal.SizeOf(battId), ref bytesReturned, IntPtr.Zero);

答案 1 :(得分:3)

基本上你有一个8字节的结构。只需将8字节长的byte []传入DeviceIoControl调用即可。没有必要打电话给AllocHGlobal,或做任何其他古怪的编组。