【问题标题】:PInvoke for GetLogicalProcessorInformation Function调用 GetLogicalProcessorInformation 函数
【发布时间】:2011-08-07 11:16:52
【问题描述】:

我想通过 c#/PInvoke 调用 GetLogicalProcessorInformation 函数,但我坚持使用 SYSTEM_LOGICAL_PROCESSOR_INFORMATION 结构和 CACHE_DESCRIPTOR 结构。

我应该如何定义这些结构以正确使用?

主要问题:
1. SYSTEM_LOGICAL_PROCESSOR_INFORMATION 的定义中有联合
2. SYSTEM_LOGICAL_PROCESSOR_INFORMATION 的定义中有 ULONGLONG
3. CACHE_DESCRIPTOR 的定义中有WORDDWORD

你能帮我解决这些结构吗?

【问题讨论】:

  • 投反对票的理由有哪些?

标签: c# windows pinvoke cpu


【解决方案1】:

更新:修复了必须手动完成的结构编组。

这是一个相当混乱的 P/invoke。即使定义了结构和联合,调用函数也很重要,因为您必须手动编组结构。

[StructLayout(LayoutKind.Sequential)]
public struct PROCESSORCORE
{
    public byte Flags;
};

[StructLayout(LayoutKind.Sequential)]
public struct NUMANODE
{
    public uint NodeNumber;
}

public enum PROCESSOR_CACHE_TYPE
{
    CacheUnified,
    CacheInstruction,
    CacheData,
    CacheTrace
}

[StructLayout(LayoutKind.Sequential)]
public struct CACHE_DESCRIPTOR
{
    public byte Level;
    public byte Associativity;
    public ushort LineSize;
    public uint Size;
    public PROCESSOR_CACHE_TYPE Type;
}

[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
    [FieldOffset(0)]
    public PROCESSORCORE ProcessorCore;
    [FieldOffset(0)]
    public NUMANODE NumaNode;
    [FieldOffset(0)]
    public CACHE_DESCRIPTOR Cache;
    [FieldOffset(0)]
    private UInt64 Reserved1;
    [FieldOffset(8)]
    private UInt64 Reserved2;
}

public enum LOGICAL_PROCESSOR_RELATIONSHIP
{
    RelationProcessorCore,
    RelationNumaNode,
    RelationCache,
    RelationProcessorPackage,
    RelationGroup,
    RelationAll = 0xffff
}

public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
    public UIntPtr ProcessorMask;
    public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
    public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
}

[DllImport(@"kernel32.dll", SetLastError=true)]
public static extern bool GetLogicalProcessorInformation(
    IntPtr Buffer,
    ref uint ReturnLength
);

private const int ERROR_INSUFFICIENT_BUFFER = 122;

public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] MyGetLogicalProcessorInformation()
{
    uint ReturnLength = 0;
    GetLogicalProcessorInformation(IntPtr.Zero, ref ReturnLength);
    if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
    {
        IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength);
        try
        {
            if (GetLogicalProcessorInformation(Ptr, ref ReturnLength))
            {
                int size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
                int len = (int)ReturnLength / size;
                SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] Buffer = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[len];
                IntPtr Item = Ptr;
                for (int i = 0; i < len; i++)
                {
                    Buffer[i] = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(Item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
                    Item += size;
                }
                return Buffer;
            }
        }
        finally
        {
            Marshal.FreeHGlobal(Ptr);
        }
    }
    return null;
}

static void Main(string[] args)
{
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] Buffer = MyGetLogicalProcessorInformation();
    for (int i=0; i<Buffer.Length; i++)
    {
        Console.WriteLine(Buffer[i].ProcessorMask);
    }
}

【讨论】:

  • 我遇到以下编译错误(在 .NET 1.1 上)Operator '+=' cannot be applied to operands of type 'System.IntPtr' and 'int'。我可以使用int* 代替 IntPtr 吗?
  • 我尝试使用以下内容:Item = new IntPtr(Item.ToInt32() + size); 并且成功了。我会告诉你,如果我可以使用int*
  • 哦,.net 1.1。对那个遗迹不熟悉!你的解决方法很好。当然,它会在 64 位目标上失败,但这在 .net 1.1 上不是问题。
【解决方案2】:

DWORDuintWORDushort

[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
   public byte Level;
   public byte Associativity;
   public ushort LineSize;
   public uint Size;
   public PROCESSOR_CACHE_TYPE Type;
}

enum PROCESSOR_CACHE_TYPE
{
    Unified = 0,
    Instruction = 1,
    Data = 2,
    Trace = 3,
}

union 是具有Explicit 布局和FieldOffset 的结构。

[StructLayout(LayoutKind.Sequential)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
    public UIntPtr ProcessorMask;
    public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
    public ProcessorRelationUnion RelationUnion;
}

[StructLayout(LayoutKind.Explicit)]
struct ProcessorRelationUnion
{
    [FieldOffset(0)] public CACHE_DESCRIPTOR Cache;
    [FieldOffset(0)] public uint NumaNodeNumber;
    [FieldOffset(0)] public byte ProcessorCoreFlags;
    [FieldOffset(0)] private UInt64 Reserved1;
    [FieldOffset(8)] private UInt64 Reserved2;
}

[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
    public byte Level;
    public byte Associativity;
    public ushort LineSize;
    public uint Size;
    public PROCESSOR_CACHE_TYPE Type;
}

enum LOGICAL_PROCESSOR_RELATIONSHIP : uint
{
    ProcessorCore = 0,
    NumaNode = 1,
    RelationCache = 2,
}

ULONGLONGUInt64。它将结构与 8 字节边界(24 字节)对齐。正如 David 在 cmets 中指出的那样,它是必需的,并且由于某种原因,Microsoft Interop 库中缺少它。

更新:添加了缺失的结构和指向 Microsoft Research 的 Windows 互操作库的链接。

来源:WindowsInteropLib/Kernel32.cs

【讨论】:

  • 虽然这个答案吸引了所有的赞成票,但在我看来,它在两个重要方面严重不足。忽略 ULONGLONG[2] Reserved 成员意味着该结构的大小不正确,为 20 字节而不是正确的 24 字节。更重要的是,没有提及实际调用该函数,这是相当棘手的。
  • 感谢您指出大卫 - 我刚刚阅读您的答案并意识到同样的事情。
猜你喜欢
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 2021-03-30
  • 2018-03-28
  • 1970-01-01
  • 2017-01-23
  • 2018-05-30
相关资源
最近更新 更多