I want to call via c#/PInvoke the GetLogicalProcessorInformation
function, but I'm stuck with SYSTEM_LOGICAL_PROCESSOR_INFORMATION
struct and CACHE_DESCRIPTOR
struct.
How should I define these structs for correct usage?
Main problems:
1. SYSTEM_LOGICAL_PROCESSOR_INFORMATION
has union in its definition
2. SYSTEM_LOGICAL_PROCESSOR_INFORMATION
has ULONGLONG
in its definition
3. CACHE_DESCRIPTOR
has WORD
and DWORD
in its definition.
Can you help me with these structures?
Updated: fixed the structure marshalling which has to be done manually.
This is quite a messy P/invoke. Even when you have the structs and the union defined, it's non-trivial to call the function because you have to marshal the structures manually.
[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);
}
}
A DWORD
is a uint
and WORD
is a ushort
.
[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,
}
A union
is a structure with a Explicit
layout and 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,
}
A ULONGLONG
is a UInt64
. It is being to align the structure to 8 byte boundary (24 bytes). As David pointed out in the comments, it is required and for some reason it was missing from the Microsoft Interop library.
Update: Added missing structures and link to the Windows Interop Library from Microsoft Research.
Source: WindowsInteropLib/Kernel32.cs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With