Как передать указатель на структуру через Pinvoke? - PullRequest
2 голосов
/ 12 февраля 2010

Я пытаюсь написать 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 и пытается извлечь идентификатор батареи.
Это для последней версии ПЗУ, SoMo650 и Socket могут предоставить только пример кода на языке C.

Я могу успешно сделать все (как можно лучше), кроме вызова DeviceIoControl, поскольку я не знаю, как перевести структуру BATT_ID в C #.

Я предполагаю, что, поскольку это структура, а DeviceIoControl ожидает указатель, я бы посмотрел на Marshal.PtrToStructure (), но у меня очень мало опыта в C и я чувствую себя не в своей тарелке.

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

5 голосов
/ 12 февраля 2010

Возможно, вам лучше использовать 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);
3 голосов
/ 12 февраля 2010

В основном у вас есть структура, которая составляет 8 байтов. Просто передайте байт [] длиной 8 байт в вызов DeviceIoControl. Нет необходимости вызывать AllocHGlobal или делать какие-либо другие дурацкие действия.

...