如何整理结构数组

本文关键字:数组 结构 何整理 | 更新日期: 2023-09-27 17:59:20

using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
    class Program
    {
        const int SystemPowerInformation = 11;
        const uint STATUS_SUCCESS = 0;
        [StructLayout(LayoutKind.Sequential)]
        struct PROCESSOR_POWER_INFORMATION
        {
            public uint  Number;
            public uint MaxMhz;
            public uint CurrentMhz;
            public uint MhzLimit;
            public uint MaxIdleState;
            public uint CurrentIdleState;
        }
        [DllImport("powrprof.dll")]
        static extern uint CallNtPowerInformation(
            int InformationLevel,
            IntPtr lpInputBuffer,
            int nInputBufferSize,
            [MarshalAs(UnmanagedType.LPArray)]
            out byte[]  lpOutputBuffer,
            int nOutputBufferSize
        );
        static void Main(string[] args)
        {

            byte[] buffer = new byte[4 * Marshal.SizeOf(typeof(PROCESSOR_POWER_INFORMATION))];
            uint retval = CallNtPowerInformation(
                SystemPowerInformation,
                IntPtr.Zero,
                0,
                out  buffer,
                4 * Marshal.SizeOf(typeof(PROCESSOR_POWER_INFORMATION))
            );
            if (retval == STATUS_SUCCESS)
                Console.WriteLine(buffer);
       }
    }
}

我正试图从CallNtPowerInformation中获取一些数据。我试图创建一个结构,调用CallNtPowerInformation并封送其中的数据,但没有成功。因此,我试图看看是否可以将数据放入字节数组,但我得到了以下结果:

对象引用未设置为对象的实例。

我相信我正在将内存分配给缓冲区。

我不知道为什么。任何指示都会有所帮助。

如何整理结构数组

名为SystemPowerInformation、值为11的常量名称错误。它应该命名为ProcessorInformation

您应该这样声明p/invoke:

[DllImport("powrprof.dll")]
static extern uint CallNtPowerInformation(
    int InformationLevel,
    IntPtr lpInputBuffer,
    int nInputBufferSize,
    [Out] PROCESSOR_POWER_INFORMATION[] processorPowerInformation,
    int nOutputBufferSize
);

为了调用函数,您需要分配一个大小合适的PROCESSOR_POWER_INFORMATION结构数组。像这样:

PROCESSOR_POWER_INFORMATION[] powerInfo = 
    new PROCESSOR_POWER_INFORMATION[procCount];

CallNtPowerInformation的文档告诉您使用GetSystemInfo来计算您有多少处理器。您可以使用Environment.ProcessorCount

然后你调用这样的函数:

uint retval = CallNtPowerInformation(
    ProcessorInformation,
    IntPtr.Zero,
    0,
    powerInfo,
    powerInfo.Length*Marshal.SizeOf(typeof(PROCESSOR_POWER_INFORMATION))
);

这里有一个完整的程序:

using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
    class Program
    {
        const int ProcessorInformation = 11;
        const uint STATUS_SUCCESS = 0;
        [StructLayout(LayoutKind.Sequential)]
        struct PROCESSOR_POWER_INFORMATION
        {
            public uint Number;
            public uint MaxMhz;
            public uint CurrentMhz;
            public uint MhzLimit;
            public uint MaxIdleState;
            public uint CurrentIdleState;
        }
        [DllImport("powrprof.dll")]
        static extern uint CallNtPowerInformation(
            int InformationLevel,
            IntPtr lpInputBuffer,
            int nInputBufferSize,
            [Out] PROCESSOR_POWER_INFORMATION[] lpOutputBuffer,
            int nOutputBufferSize
        );
        static void Main(string[] args)
        {
            int procCount = Environment.ProcessorCount;
            PROCESSOR_POWER_INFORMATION[] procInfo =
                new PROCESSOR_POWER_INFORMATION[procCount]; 
            uint retval = CallNtPowerInformation(
                ProcessorInformation,
                IntPtr.Zero,
                0,
                procInfo,
                procInfo.Length * Marshal.SizeOf(typeof(PROCESSOR_POWER_INFORMATION))
            );
            if (retval == STATUS_SUCCESS)
            {
                foreach (var item in procInfo)
                {
                    Console.WriteLine(item.CurrentMhz);
                }
            }
        }
    }
}

将您的ummanaged调用的参数类型更改为IntPtr:

[DllImport("powrprof.dll")]
    static extern uint CallNtPowerInformation(
        int InformationLevel,
        IntPtr lpInputBuffer,
        int nInputBufferSize,
        IntPtr lpOutputBuffer,
        int nOutputBufferSize
    );

在调用它之前使用这个:

GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();

然后调用它,将该IntPtr作为参数进行传递。

使用后不要忘记释放!