none
Приложение для контроля/наблюдения за состоянием аккумулятора ноутбука(VS2013+C#) RRS feed

  • Вопрос

  • Здравствуйте. У меня основной системой стоит Windows 8.1, второй Ubuntu 14.04.2... стояла какое-то время, но не в этом суть... Суть в том, что в Ubuntu мне понравилось приложение для контроля за батареей ноутбука - вывод графика разрядки/зарядки, текущая емкость, максимальная емкость, текущее напряжение батареи и тд. Хочу написать подобное приложение для Windows, используя Visual Studio 2013 и C#, но не знаю пока куда копать... класс PowerStatus не имеет в свойствах емкость батареи...

Ответы

  • Первый вариант правильный, второй нет. Не должно быть там никаких ref, конечно будет крашится.

    Как вариант можно попробовать так:

    		[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    		static extern bool DeviceIoControl(
    			SafeFileHandle hDevice, 
    			uint dwIoControlCode,
    			[MarshalAs(UnmanagedType.LPArray), In] byte[] InBuffer, 
    			uint nInBufferSize,
    			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5), Out, In] byte[] OutBuffer, 
    			uint nOutBufferSize,
    			out uint pBytesReturned, 
    			IntPtr lpOverlapped);
    

    После чего можно запинить массив используя GCHandle и получить на него указатель передать его Marshal.PtrToStructure() (и обратно).

    Можно и структуры вместо массивов задекларировать, вот их уже надо с ref и UnmanagedType.LPStruct.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Помучился я с Вашим вариантом... ничего у меня не вышло - просто знаний не хватило на реализацию, но нашел в сети рабочий вариант исходного кода который отлично работает...(лежит здесь - https://gist.github.com/ahawker/9715872)

    ПС.: В принципе у меня все равно не было шансов самому написать что-то подобное... хотя бы потому, что нужно знать кучу флагов/констант, о которых я не имею ни малейшего понятия...)

Все ответы

  • IOCTL_BATTERY_QUERY_INFORMATION с BatteryInformation вернет что надо:

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa372659%28v=vs.85%29.aspx

    Сигнатуры P/Invoke скорее всего можно найти на pinvoke.net.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Я вообще-то не программист, так... любитель.) Вобщем все что надо нашел, но работать у меня процедура DeviceIoControl отказывается... точнее выдает в ответ нули... PInvoke предлагает вот такой вариант: 

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode,
            IntPtr InBuffer, uint nInBufferSize,
            IntPtr OutBuffer, uint nOutBufferSize,
            out uint pBytesReturned, IntPtr lpOverlapped);

    Я нашел как бы рабочий вариант:

    [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            public static extern bool DeviceIoControl(SafeFileHandle hDevice,
              uint IoControlCode, 
              ref ulong InBuffer,
              uint nInBufferSize,
              ref ulong OutBuffer,
              uint nOutBufferSize,
              ref ulong pBytesReturned,
              object lpOverlapped)

    Но с использованием ref вылезает ошибка:

    "Контроль_зараяда_батареи_ноутбука.Class1::DeviceIoControl" разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой. Убедитесь, что соглашение о вызовах и параметры сигнатуры PInvoke совпадают с неуправляемой целевой сигнатурой."

    Вобщем убил целый день, а так и не разобрался... может кто посоветует какую-нибудь литературу почитать?) Или выдаст алгоритм "самообучения программированию на дому"...))


  • Вот найденное мной готовое решение, помогите починить.)

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Контроль_зараяда_батареи_ноутбука
    {
        class Class1
        {
            #region Variables Declaration
            private const int DIGCF_DEFAULT = 0x00000001;  // only valid with DIGCF_DEVICEINTERFACE
            private const int DIGCF_PRESENT = 0x00000002;
            private const int DIGCF_ALLCLASSES = 0x00000004;
            private const int DIGCF_PROFILE = 0x00000008;
            private const int DIGCF_DEVICEINTERFACE = 0x00000010;
            const int GENERIC_READ = 80000000;
            const uint GENERIC_WRITE = 0x40000000;
            internal static uint OPEN_EXISTING = 3;
            internal static uint FILE_ATTRIBUTE_NORMAL = 0x80;
            internal static uint FILE_SHARE_READ = 1;
            internal static uint FILE_SHARE_WRITE = 2;
            public const uint METHOD_BUFFERED = 0;
            public const uint FILE_ANY_ACCESS = 0x0001;
            public const uint FILE_DEVICE_BATTERY = 0x294044; //0x294040; //0x00000029;
            public static readonly Guid GUID_DEVCLASS_BATTERY = new Guid(0x72631e54, 0x78a4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a);
            #endregion
            #region Windows APIs
            [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
            static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator,
                                                           IntPtr hwndParent, uint Flags);
            [DllImport("setupapi.dll")]
            internal static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref  SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
            [DllImport("setupapi.dll", SetLastError = true)]
            protected static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA oInterfaceData, IntPtr lpDeviceInterfaceDetailData, uint nDeviceInterfaceDetailDataSize, out uint nRequiredSize, IntPtr lpDeviceInfoData);
            [DllImport("setupapi.dll", SetLastError = true)]
            protected static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA oInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA oDetailData, uint nDeviceInterfaceDetailDataSize, out uint nRequiredSize, IntPtr lpDeviceInfoData);
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)] string lpFileName, uint dwDesiredAccess,
                uint dwShareMode, IntPtr SecurityAttributes,
                uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern SafeFileHandle CreateFile(string fileName, [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
                 [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes,
                 [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] EFileAttributes flags,
                  IntPtr template);
            [DllImport("wimgapi.dll", EntryPoint = "WIMCloseHandle", SetLastError = true)]
            public static extern int WIMCloseHandle(IntPtr hObject);
            [DllImport(@"hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern void HidD_GetHidGuid(out Guid gHid);
            [DllImport("setupapi.dll")]
            internal static extern Int32 SetupDiClassNameFromGuid(ref Guid ClassGuid, StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize);
            [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInvo,
                ref Guid interfaceClassGuid, Int32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
            [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern UInt16 SetupDiDestroyDeviceInfoList(IntPtr hDevInfo);
            //[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
            //public static extern bool DeviceIoControl(SafeHandle hDevice, uint dwIoControlCode,
            //    IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out int lpBytesReturned,
            //    IntPtr lpOverlapped);
            //[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            //public static extern bool DeviceIoControl(SafeFileHandle hDevice, uint IoControlCode,
            //    [MarshalAs(UnmanagedType.AsAny)][In] BATTERY_QUERY_INFORMATION InBuffer, uint nInBufferSize,
            //[MarshalAs(UnmanagedType.AsAny)][Out] BATTERY_INFORMATION OutBuffer, out uint nOutBufferSize, ref uint pBytesReturned,
            //[In] IntPtr lpOverlapped);
            /*[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode,
            IntPtr InBuffer, uint nInBufferSize,
            IntPtr OutBuffer, uint nOutBufferSize,
            out uint pBytesReturned, IntPtr lpOverlapped);*/
    
            [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            public static extern bool DeviceIoControl(SafeFileHandle hDevice, uint IoControlCode,
                ref BATTERY_QUERY_INFORMATION InBuffer, uint nInBufferSize,
            ref BATTERY_INFORMATION OutBuffer, uint nOutBufferSize, ref uint pBytesReturned,
            IntPtr lpOverlapped);
            [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            public static extern bool DeviceIoControl(SafeFileHandle hDevice,
              uint IoControlCode,
              ref ulong InBuffer,
              uint nInBufferSize,
              ref ulong OutBuffer,
              uint nOutBufferSize,
              ref ulong pBytesReturned,
              object lpOverlapped);
            #endregion
            #region Structures and Enums
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct SP_DEVICE_INTERFACE_DATA
            {
                public UInt32 cbSize;
                public Guid InterfaceClassGuid;
                public UInt32 Flags;
                public UIntPtr Reserved;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct SP_DEVICE_INTERFACE_DETAIL_DATA
            {
                public UInt32 cbSize;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string DevicePath;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BATTERY_QUERY_INFORMATION
            {
                public ulong BatteryTag;
                public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel;
                public long AtRate;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BATTERY_QUERY_INFORMATION_LEVEL
            {
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string BatteryDeviceName;
                public ulong BatteryEstimatedTime;
                public BATTERY_REPORTING_SCALE BatteryGranularityInformation;
                public BATTERY_INFORMATION BatteryInformation;
                public BATTERY_MANUFACTURE_DATE BatteryManufactureDate;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string BatteryManufactureName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string BatterySerialNumber;
                public ulong BatteryTemperature;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string BatteryUniqueID;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BATTERY_REPORTING_SCALE
            {
                public ulong Granularity;
                public ulong Capacity;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BATTERY_MANUFACTURE_DATE
            {
                public char Day;
                public char Month;
                public ushort Year;
            }
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BATTERY_INFORMATION
            {
                public ulong Capabilities;
                public char Technology;
                public char[] Reserved;
                public char[] Chemistry;
                public ulong DesignCapacity;
                public ulong FullChargeCapacity;
                public ulong DefaultAlert1;
                public ulong DefaultAlert2;
                public ulong CriticalBias;
                public ulong CycleCount;
            }
            [Flags]
            public enum EFileAttributes : uint
            {
                Readonly = 0x00000001,
                Hidden = 0x00000002,
                System = 0x00000004,
                Directory = 0x00000010,
                Archive = 0x00000020,
                Device = 0x00000040,
                Normal = 0x00000080,
                Temporary = 0x00000100,
                SparseFile = 0x00000200,
                ReparsePoint = 0x00000400,
                Compressed = 0x00000800,
                Offline = 0x00001000,
                NotContentIndexed = 0x00002000,
                Encrypted = 0x00004000,
                Write_Through = 0x80000000,
                Overlapped = 0x40000000,
                NoBuffering = 0x20000000,
                RandomAccess = 0x10000000,
                SequentialScan = 0x08000000,
                DeleteOnClose = 0x04000000,
                BackupSemantics = 0x02000000,
                PosixSemantics = 0x01000000,
                OpenReparsePoint = 0x00200000,
                OpenNoRecall = 0x00100000,
                FirstPipeInstance = 0x00080000
            }
            #endregion
            #region Methods
            public static void ConnectWithDevice()
            {
                int index = 0;
                Guid guid = GUID_DEVCLASS_BATTERY;
                // get the GUID of the HID class
                //HidD_GetHidGuid(out guid);
                // get a handle to all devices that are part of the HID class
                // Fun fact:  DIGCF_PRESENT worked on my machine just fine.  I reinstalled Vista, and now it no longer finds the Wiimote with that parameter enabled...
                IntPtr hDevInfo = SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, DIGCF_DEVICEINTERFACE);// | HIDImports.DIGCF_PRESENT);
                // create a new interface data struct and initialize its size
                SP_DEVICE_INTERFACE_DATA diData = new SP_DEVICE_INTERFACE_DATA();
                diData.cbSize = (uint)Marshal.SizeOf(diData);
                // get a device interface to a single device (enumerate all devices)
                while (SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guid, index, ref diData))
                {
                    UInt32 size;
                    // Get Device Name
                    //string deviceName = GetClassNameFromGuid(diData.InterfaceClassGuid);
                    // get the buffer size for this device detail instance (returned in the size parameter)
                    SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, IntPtr.Zero, 0, out size, IntPtr.Zero);
                    // create a detail struct and set its size
                    SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                    diDetail.cbSize = (uint)(IntPtr.Size == 8 ? 8 : 5);
                    // actually get the detail struct
                    if (SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, ref diDetail, size, out size, IntPtr.Zero))
                    {
                        MessageBox.Show("Battery " + (index + 1) + " Device Path: " + diDetail.DevicePath);
                        // open a read/write handle to our device using the DevicePath returned
                        SafeFileHandle mHandle = CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, EFileAttributes.Overlapped, IntPtr.Zero);
                        if (!mHandle.IsInvalid)
                        {
                            bool result = false;
                            try
                            {
                                ulong time = 0, tag = 0, bytes = 0;
                                result = DeviceIoControl(mHandle,
                                    CTL_CODE(FILE_DEVICE_BATTERY, 0x10, METHOD_BUFFERED, FILE_ANY_ACCESS),
                                    ref time,
                                    (uint)Marshal.SizeOf(time),
                                    ref tag,
                                    (uint)Marshal.SizeOf(tag),
                                    ref bytes,
                                    null);
    
                                if (result)
                                {
                                    BATTERY_QUERY_INFORMATION bqi = new BATTERY_QUERY_INFORMATION();
                                    bqi.AtRate = 0;
                                    bqi.BatteryTag = (ulong)tag;
                                    //bqi.InformationLevel = 
                                    MessageBox.Show("Tag: " + tag.ToString() + " and bytes: " + bytes);
                                    uint len = 0;
                                    uint nInBufferSize = (uint)Marshal.SizeOf(bqi);
                                    BATTERY_INFORMATION bi = new BATTERY_INFORMATION();
                                    uint nOutBufferSize = (uint)Marshal.SizeOf(bqi);
                                    result = false;
                                    result = DeviceIoControl(mHandle, CTL_CODE(FILE_DEVICE_BATTERY, 0x11, METHOD_BUFFERED, FILE_ANY_ACCESS),
                                       ref bqi, nInBufferSize, ref bi, nOutBufferSize, ref len, IntPtr.Zero);
                                    if (result)
                                    {
                                        MessageBox.Show("Bytes Return: " + len.ToString());
                                        MessageBox.Show("Design Capacity: " + bi.DesignCapacity);
                                        MessageBox.Show("Full Charge Capacity: " + bi.FullChargeCapacity);
                                    }
                                    else
                                    {
                                        MessageBox.Show("No Result");
                                    }
                                }
                                else
                                {
                                    MessageBox.Show("Battery Query Information Not processed");
                                }
                            }
    
                            finally
                            {
                                //Marshal.FreeHGlobal(pInBuffer);
                                //Marshal.FreeHGlobal(pOutBuffer);
                            }
                        }
                        else
                        {
                            MessageBox.Show("In-valid File Handle");
                        }
                        mHandle.Close();
                        int errCode = Marshal.GetLastWin32Error();
                        MessageBox.Show("Win32 Error: " + errCode.ToString());
                    }
                    else
                    {
                        // failed to get the detail struct
                        throw new Exception("SetupDiGetDeviceInterfaceDetail failed on index " + index);
                    }
                    // move to the next device
                    index++;
                }
                // clean up our list
                SetupDiDestroyDeviceInfoList(hDevInfo);
                // if we didn't find a Wiimote, throw an exception
                //if (!found)
                //    throw new Exception("Wiimote not found in HID device list.");
            }
            private static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access)
            {
                return (uint)(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method));
            }
            #endregion
        }
    }
    

  • Первый вариант правильный, второй нет. Не должно быть там никаких ref, конечно будет крашится.

    Как вариант можно попробовать так:

    		[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    		static extern bool DeviceIoControl(
    			SafeFileHandle hDevice, 
    			uint dwIoControlCode,
    			[MarshalAs(UnmanagedType.LPArray), In] byte[] InBuffer, 
    			uint nInBufferSize,
    			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5), Out, In] byte[] OutBuffer, 
    			uint nOutBufferSize,
    			out uint pBytesReturned, 
    			IntPtr lpOverlapped);
    

    После чего можно запинить массив используя GCHandle и получить на него указатель передать его Marshal.PtrToStructure() (и обратно).

    Можно и структуры вместо массивов задекларировать, вот их уже надо с ref и UnmanagedType.LPStruct.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Помучился я с Вашим вариантом... ничего у меня не вышло - просто знаний не хватило на реализацию, но нашел в сети рабочий вариант исходного кода который отлично работает...(лежит здесь - https://gist.github.com/ahawker/9715872)

    ПС.: В принципе у меня все равно не было шансов самому написать что-то подобное... хотя бы потому, что нужно знать кучу флагов/констант, о которых я не имею ни малейшего понятия...)