c#-结构数组的指针有问题

c#-结构数组的指针有问题,c#,.net-core,ntdll,C#,.net Core,Ntdll,我想通过使用ntdll中的NtQuerySystemInformation获得关于每个处理器性能的信息。现在我有一个问题,它只是在所有5次尝试中运行,然后返回 NtQuerySystemInformation返回一个NtStatus,它始终是InfoLengthMismatch,这通常意味着我必须使缓冲区变大。如果我只使用一个处理器(没有阵列)和0x10000的缓冲区大小来尝试,它的效果会很好,在第一次尝试时它会给我InfoLengthMismatch,但第二次尝试总是有效的 我尝试将缓冲区增加

我想通过使用ntdll中的NtQuerySystemInformation获得关于每个处理器性能的信息。现在我有一个问题,它只是在所有5次尝试中运行,然后返回

NtQuerySystemInformation返回一个NtStatus,它始终是InfoLengthMismatch,这通常意味着我必须使缓冲区变大。如果我只使用一个处理器(没有阵列)和0x10000的缓冲区大小来尝试,它的效果会很好,在第一次尝试时它会给我InfoLengthMismatch,但第二次尝试总是有效的

我尝试将缓冲区增加100倍,也增加了1000倍,但没有任何效果

private _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] GetPerformanceInfo()
    {
        try
        {
            //Getting count of processors
            SYSTEM_INFO sysInfo = new SYSTEM_INFO();
            GetSystemInfo(out sysInfo);
            int processors = (int)sysInfo.numberOfProcessors;

            int tries = 0;

            while (true)
            {

                //buffer size
                uint infoLength = (uint)(Marshal.SizeOf(typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) * processors);

                //buffer
                IntPtr infoPtr = Marshal.AllocHGlobal((int)infoLength);

                //Problem: result is always InfoLengthMismatch
                NtStatus result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, infoPtr, infoLength, out infoLength);

                //if success, get the array and return it
                if (result == NtStatus.Success)
                {
                    int szStruct = Marshal.SizeOf(typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
                    _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] localStructs = new _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[processors];

                    for (uint i = 0; i < processors; i++)
                        localStructs[i] = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)Marshal.PtrToStructure(new IntPtr(infoPtr.ToInt64() + (szStruct * processors)), typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));

                    return localStructs;
                }

                //free ptr when fail
                Marshal.FreeHGlobal(infoPtr);

                if (++tries > 5)
                    return null;

                //set ptr again, new try
                infoPtr = Marshal.AllocHGlobal((int)infoLength);

            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Source + ": " + e.Message.ToString());
            return null;
        }
    }

}

//struct of a large int
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct LARGE_INTEGER
{
    [FieldOffset(0)] public Int64 QuadPart;
    [FieldOffset(0)] public UInt32 LowPart;
    [FieldOffset(4)] public Int32 HighPart;
}

//struct
public struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
{
    public LARGE_INTEGER IdleTime;
    public LARGE_INTEGER KernelTime;
    public LARGE_INTEGER UserTime;
    public LARGE_INTEGER Reserved1;
    public ulong Reserved2;
}

通常情况下,如果大小错误,它将输出infoLength变量的正确大小,但在这种情况下,我每次都在循环开始时设置它。

我注意到了一些事情。首先,分配内存两次,只释放一次:

//buffer
IntPtr infoPtr = Marshal.AllocHGlobal((int)infoLength);

//...

//free ptr when fail
Marshal.FreeHGlobal(infoPtr);

//...

//set ptr again, new try
infoPtr = Marshal.AllocHGlobal((int)infoLength);
其次,当
NtQuerySystemInformation
返回错误时,它会将可选的out参数设置为所需的大小。与我看到的不同,您创建的缓冲区大小是
8*5*处理器
。或
40*处理器

您可以通过在调用前后输出
infoLength
来确认这一点以及适当的所需大小

// Should be 40 * processors
Console.WriteLine((int)infoLength);

//Problem: result is always InfoLengthMismatch
NtStatus result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, 
                      infoPtr, infoLength, out infoLength);

// Will be bigger than 40 * processors
Console.WriteLine((int)infoLength);

您是否知道分配内存两次,释放内存一次?我有4个处理器,但infoLength将设置为40,而不是40*4。@Tom我复制了您的代码,没有问题。我只添加了
NtStatus
SYSTEM\u INFORMATION\u类
enum,以及
ntquerysystem信息的dlliport
和我使用的
Environment.ProcessorCount
// Should be 40 * processors
Console.WriteLine((int)infoLength);

//Problem: result is always InfoLengthMismatch
NtStatus result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, 
                      infoPtr, infoLength, out infoLength);

// Will be bigger than 40 * processors
Console.WriteLine((int)infoLength);