views:

194

answers:

2

I am trying to write the C# equivalent to the following:

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.
This is for the latest ROM version of the SoMo650 and Socket are only able to provide sample code in 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#.

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.

Any assitance would be greatly appreciated.

+3  A: 

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:

[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:

[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...

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

Hope this helps, Best regards, Tom.

tommieb75
The battery related functionality that the SDF provides is a wrapper on GetSystemPowerStatusEx2. The information I am trying to get is only available from the device driver.
Matt Lacey
@Matt: Ok, have a look at the edited answer I hope I have it the right way.... :)
tommieb75
Your stucture is incorrect - the original definition is 8 UINT8's, which is simply 8 bytes. There also no need to wrap this in a structure (even if it were 8 ints).
ctacke
@ctacke: oh...feel free to edit it...
tommieb75
thanks for al the help so far. I'm busy trying to get this working.
Matt Lacey
+2  A: 

Basically you have a structure that is 8 bytes. Just pass in a byte[] that is 8 bytes long to the DeviceIoControl call. There is no need to call AllocHGlobal, or do any other wacky marshaling.

ctacke