简体   繁体   English

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

[英]How to pass a pointer to a struct via Pinvoke?

I am trying to write the C# equivalent to the following: 我正在尝试编写与以下内容等效的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]);

The code is connecting to the power driver of a Windows Mobile device and attempting to retrieve the battery Id. 代码连接到Windows Mobile设备的电源驱动程序并尝试检索电池ID。
This is for the latest ROM version of the SoMo650 and Socket are only able to provide sample code in C. 这是针对SoMo650和Socket的最新ROM版本,只能在C中提供示例代码。

I can successfully do everything (as best as I can tell) apart from calling DeviceIoControl as I don't know how to translate the BATT_ID structure into C#. 除了调用DeviceIoControl,我可以成功地完成所有事情(尽我所知),因为我不知道如何将BATT_ID结构转换为C#。

I'm guessing that as it's a structure and DeviceIoControl expects a pointer I shoould be looking at Marshal.PtrToStructure() but I have very little C experience and feel very out of my depth. 我猜这是因为它是一个结构,而DeviceIoControl期望一个指针我应该看着Marshal.PtrToStructure(),但我的C经验非常少,感觉非常深刻。

Any assitance would be greatly appreciated. 任何协助将不胜感激。

You might be better to use the Smart Device Framework which has a battery control in place..see here for the download link for the community edition. 您可能最好使用具有电池控制功能的智能设备框架 。请参阅社区版的下载链接。

Edit: If you still want the pinvoke equivalent of the structure look here: 编辑:如果您仍然希望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;
};

Then prior to p/invoking, you need the signature for the ' DeviceIoControl ' as shown: 然后在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);

The call would look like this: 电话会是这样的:

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);

I hope I have this right... 我希望我有这个权利......

Edit#2: As ctacke (thanks!) pointed out my code sample is wrong... 编辑#2:正如ctacke (谢谢!)指出我的代码示例是错误的...

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

Basically you have a structure that is 8 bytes. 基本上你有一个8字节的结构。 Just pass in a byte[] that is 8 bytes long to the DeviceIoControl call. 只需将8字节长的byte []传入DeviceIoControl调用即可。 There is no need to call AllocHGlobal, or do any other wacky marshaling. 没有必要打电话给AllocHGlobal,或做任何其他古怪的编组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM