代码之家  ›  专栏  ›  技术社区  ›  Matt Lacey

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

  •  2
  • Matt Lacey  · 技术社区  · 16 年前

    我试图将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和Socket的最新ROM版本,只能提供C语言的示例代码。

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

    我猜,因为它是一个结构,DeviceIoControl需要一个指针,所以我应该看看Marshal.PtrToStructure(),但我对C语言的经验很少,感觉很不熟悉。

    2 回复  |  直到 16 年前
        1
  •  5
  •   t0mm13b    12 年前

    您最好使用 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;
    };
    

    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: 作为 (谢谢!)指出我的代码示例是错误的。。。

    unsigned byte[8] battId;
    DeviceIoControl(g_hDevice, SOMO650_PWR_GET_BATT_ID, null, 0, battId, Marshal.SizeOf(battId), ref bytesReturned, IntPtr.Zero);
    
        2
  •  3
  •   ctacke    16 年前

    基本上你有一个8字节的结构。只需向DeviceIoControl调用传入一个8字节长的字节[]。不需要调用AllocHGlobal,也不需要执行任何其他古怪的封送处理。