diff --git a/PInvoke/Kernel32/SysInfoApi.cs b/PInvoke/Kernel32/SysInfoApi.cs
index be0239fc..278c861f 100644
--- a/PInvoke/Kernel32/SysInfoApi.cs
+++ b/PInvoke/Kernel32/SysInfoApi.cs
@@ -1226,9 +1226,9 @@ namespace Vanara.PInvoke
///
///
///
- /// The memory allocated for the results in .
///
- /// An array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pointers. If the function fails, the contents of this buffer are undefined.
+ /// A safe handle that holds an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pointers. If the function fails, the
+ /// contents of this buffer are undefined.
///
///
///
@@ -1237,26 +1237,17 @@ namespace Vanara.PInvoke
///
/// If the function fails, the return value has error information.
///
- public static unsafe Win32Error GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, out SafeCoTaskMemHandle mem, out RefEnumerator info)
+ public static unsafe Win32Error GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, out SafeSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_List info)
{
info = default;
- mem = default;
uint sz = 0;
var err = BoolToLastErr(GetLogicalProcessorInformationEx(RelationshipType, IntPtr.Zero, ref sz) || sz > 0);
if (err.Failed && err != Win32Error.ERROR_INSUFFICIENT_BUFFER) return err;
- mem = new SafeCoTaskMemHandle(sz);
- err = BoolToLastErr(GetLogicalProcessorInformationEx(RelationshipType, mem, ref sz));
- if (err.Succeeded)
- {
- var ret = new List();
- for (IntPtr pCurrent = mem, pEnd = pCurrent.Offset(sz); pCurrent.ToInt64() < pEnd.ToInt64() && pCurrent != IntPtr.Zero;)
- {
- ret.Add(pCurrent);
- pCurrent = pCurrent.Offset(pCurrent.ToStructure().Size);
- }
- mem.Write(ret, true, (int)sz);
- info = new RefEnumerator((SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)mem.DangerousGetHandle().Offset(sz), ret.Count);
- }
+ var iinfo = new SafeSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_List(sz);
+ if ((err = BoolToLastErr(GetLogicalProcessorInformationEx(RelationshipType, iinfo, ref sz))).Succeeded)
+ info = iinfo;
+ else
+ iinfo.Dispose();
return err;
}
@@ -2798,12 +2789,10 @@ namespace Vanara.PInvoke
public PROCESSOR_CACHE_TYPE Type;
}
- ///
- /// Describes cache attributes. This structure is used with the GetLogicalProcessorInformationEx function.
- ///
+ /// Describes cache attributes. This structure is used with the GetLogicalProcessorInformationEx function.
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_cache_relationship typedef struct _CACHE_RELATIONSHIP { BYTE
- // Level; BYTE Associativity; WORD LineSize; DWORD CacheSize; PROCESSOR_CACHE_TYPE Type; BYTE Reserved[20]; GROUP_AFFINITY GroupMask;
- // } CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
+ // Level; BYTE Associativity; WORD LineSize; DWORD CacheSize; PROCESSOR_CACHE_TYPE Type; BYTE Reserved[20]; GROUP_AFFINITY
+ // GroupMask; } CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
[PInvokeData("winnt.h", MSDNShortId = "f8fe521b-02d6-4c58-8ef8-653280add111")]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct CACHE_RELATIONSHIP
@@ -2831,85 +2820,61 @@ namespace Vanara.PInvoke
///
public byte Level;
- ///
- /// The cache associativity. If this member is CACHE_FULLY_ASSOCIATIVE (0xFF), the cache is fully associative.
- ///
+ /// The cache associativity. If this member is CACHE_FULLY_ASSOCIATIVE (0xFF), the cache is fully associative.
public byte Associativity;
- ///
- /// The cache line size, in bytes.
- ///
+ /// The cache line size, in bytes.
public ushort LineSize;
- ///
- /// The cache size, in bytes.
- ///
+ /// The cache size, in bytes.
public uint CacheSize;
- ///
- /// The cache type. This member is a PROCESSOR_CACHE_TYPE value.
- ///
+ /// The cache type. This member is a PROCESSOR_CACHE_TYPE value.
public PROCESSOR_CACHE_TYPE Type;
- ///
- /// This member is reserved.
- ///
+ /// This member is reserved.
private readonly uint Reserved1;
-
private readonly uint Reserved2;
private readonly uint Reserved3;
private readonly uint Reserved4;
private readonly uint Reserved5;
- ///
- /// A GROUP_AFFINITY structure that specifies a group number and processor affinity within the group.
- ///
+ /// A GROUP_AFFINITY structure that specifies a group number and processor affinity within the group.
public GROUP_AFFINITY GroupMask;
}
///
- /// Represents information about processor groups. This structure is used with the GetLogicalProcessorInformationEx function.
+ /// Represents information about processor groups. This structure is used with the GetLogicalProcessorInformationEx function.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_group_relationship typedef struct _GROUP_RELATIONSHIP { WORD
// MaximumGroupCount; WORD ActiveGroupCount; BYTE Reserved[20]; PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY]; } GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
[PInvokeData("winnt.h", MSDNShortId = "3529ddef-04c5-4573-877d-c225da684e38")]
+ [VanaraMarshaler(typeof(SafeAnysizeStructMarshaler), nameof(ActiveGroupCount))]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct GROUP_RELATIONSHIP
{
- ///
- /// The maximum number of processor groups on the system.
- ///
+ /// The maximum number of processor groups on the system.
public ushort MaximumGroupCount;
///
- ///
/// The number of active groups on the system. This member indicates the number of PROCESSOR_GROUP_INFO structures in the
/// GroupInfo array.
- ///
///
public ushort ActiveGroupCount;
- ///
- /// This member is reserved.
- ///
+ /// This member is reserved.
private readonly uint Reserved1;
-
private readonly uint Reserved2;
private readonly uint Reserved3;
private readonly uint Reserved4;
private readonly uint Reserved5;
- private PROCESSOR_GROUP_INFO _GroupInfo;
///
- ///
/// An array of PROCESSOR_GROUP_INFO structures. Each structure represents the number and affinity of processors in an active
/// group on the system.
- ///
///
- public PROCESSOR_GROUP_INFO[] GroupInfo
- {
- get { unsafe { fixed (void* p = &_GroupInfo) { return ((IntPtr)p).ToArray(ActiveGroupCount); } } }
- }
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ public PROCESSOR_GROUP_INFO[] GroupInfo;
}
///
@@ -3038,34 +3003,25 @@ namespace Vanara.PInvoke
}
///
- ///
/// Represents information about a NUMA node in a processor group. This structure is used with the GetLogicalProcessorInformationEx function.
- ///
///
- // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_numa_node_relationship typedef struct _NUMA_NODE_RELATIONSHIP
- // { DWORD NodeNumber; BYTE Reserved[20]; GROUP_AFFINITY GroupMask; } NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
+ // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_numa_node_relationship typedef struct
+ // _NUMA_NODE_RELATIONSHIP { DWORD NodeNumber; BYTE Reserved[20]; GROUP_AFFINITY GroupMask; } NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
[PInvokeData("winnt.h", MSDNShortId = "a4e4c994-c4af-4b4f-8684-6037bcba35a9")]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct NUMA_NODE_RELATIONSHIP
{
- ///
- /// The number of the NUMA node.
- ///
+ /// The number of the NUMA node.
public uint NodeNumber;
- ///
- /// This member is reserved.
- ///
+ /// This member is reserved.
private readonly uint Reserved1;
-
private readonly uint Reserved2;
private readonly uint Reserved3;
private readonly uint Reserved4;
private readonly uint Reserved5;
- ///
- /// A GROUP_AFFINITY structure that specifies a group number and processor affinity within the group.
- ///
+ /// A GROUP_AFFINITY structure that specifies a group number and processor affinity within the group.
public GROUP_AFFINITY GroupMask;
}
@@ -3243,30 +3199,21 @@ namespace Vanara.PInvoke
public static readonly OSVERSIONINFOEX Default = new OSVERSIONINFOEX { dwOSVersionInfoSize = (uint)Marshal.SizeOf(typeof(OSVERSIONINFOEX)) };
}
- ///
- /// Represents the number and affinity of processors in a processor group.
- ///
+ /// Represents the number and affinity of processors in a processor group.
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_processor_group_info typedef struct _PROCESSOR_GROUP_INFO {
// BYTE MaximumProcessorCount; BYTE ActiveProcessorCount; BYTE Reserved[38]; KAFFINITY ActiveProcessorMask; } PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
[PInvokeData("winnt.h", MSDNShortId = "6ff9cc3c-34e7-4dc4-94cd-6ed278dfaa03")]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PROCESSOR_GROUP_INFO
{
- ///
- /// The maximum number of processors in the group.
- ///
+ /// The maximum number of processors in the group.
public byte MaximumProcessorCount;
- ///
- /// The number of active processors in the group.
- ///
+ /// The number of active processors in the group.
public byte ActiveProcessorCount;
- ///
- /// This member is reserved.
- ///
+ /// This member is reserved.
private readonly ushort Reserved1;
-
private readonly uint Reserved2;
private readonly uint Reserved3;
private readonly uint Reserved4;
@@ -3277,9 +3224,7 @@ namespace Vanara.PInvoke
private readonly uint Reserved9;
private readonly uint Reserved10;
- ///
- /// A bitmap that specifies the affinity for zero or more active processors within the group.
- ///
+ /// A bitmap that specifies the affinity for zero or more active processors within the group.
public UIntPtr ActiveProcessorMask;
}
@@ -3305,6 +3250,7 @@ namespace Vanara.PInvoke
// { BYTE Flags; BYTE EfficiencyClass; BYTE Reserved[20]; WORD GroupCount; GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; }
// PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
[PInvokeData("winnt.h", MSDNShortId = "1efda80d-cf5b-4312-801a-ea3585b152ac")]
+ [VanaraMarshaler(typeof(SafeAnysizeStructMarshaler), nameof(GroupCount))]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PROCESSOR_RELATIONSHIP
{
@@ -3335,32 +3281,23 @@ namespace Vanara.PInvoke
///
public byte EfficiencyClass;
- ///
- /// This member is reserved.
- ///
+ /// This member is reserved.
private readonly ushort Reserved1;
-
private readonly uint Reserved2;
private readonly uint Reserved3;
private readonly uint Reserved4;
private readonly uint Reserved5;
private readonly ushort Reserved6;
- ///
- /// This member specifies the number of entries in the GroupMask array. For more information, see Remarks.
- ///
+ /// This member specifies the number of entries in the GroupMask array. For more information, see Remarks.
public ushort GroupCount;
- private GROUP_AFFINITY _GroupMask;
-
///
/// An array of GROUP_AFFINITY structures. The GroupCount member specifies the number of structures in the array. Each
/// structure in the array specifies a group number and processor affinity within the group.
///
- public GROUP_AFFINITY[] GroupMask
- {
- get { unsafe { fixed (void* p = &_GroupMask) { return ((IntPtr)p).ToArray(GroupCount); } } }
- }
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ public GROUP_AFFINITY[] GroupMask;
}
///
@@ -3583,17 +3520,15 @@ namespace Vanara.PInvoke
}
///
- ///
/// Contains information about the relationships of logical processors and related hardware. The GetLogicalProcessorInformationEx
/// function uses this structure.
- ///
///
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_system_logical_processor_information_ex typedef struct
// _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { LOGICAL_PROCESSOR_RELATIONSHIP Relationship; DWORD Size; union { PROCESSOR_RELATIONSHIP
// Processor; NUMA_NODE_RELATIONSHIP NumaNode; CACHE_RELATIONSHIP Cache; GROUP_RELATIONSHIP Group; } DUMMYUNIONNAME; }
// SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
[PInvokeData("winnt.h", MSDNShortId = "6ff16cda-c1dc-4d5c-ac60-756653cd6b07")]
- [StructLayout(LayoutKind.Sequential), DebuggerDisplay("{DebugString}")]
+ [StructLayout(LayoutKind.Sequential, Size = 76)]
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
{
///
@@ -3630,57 +3565,44 @@ namespace Vanara.PInvoke
///
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
- ///
- /// The size of the structure.
- ///
+ /// The size of the structure.
public uint Size;
/// The relationship union.
- public ProcessorRelationUnion RelationUnion;
+ private readonly ulong dummy;
- /// Union tied to the relationship.
- [StructLayout(LayoutKind.Explicit)]
- public struct ProcessorRelationUnion
+ ///
+ /// A NUMA_NODE_RELATIONSHIP structure that describes a NUMA node. This structure contains valid data only if the
+ /// Relationship member is RelationNumaNode.
+ ///
+ public NUMA_NODE_RELATIONSHIP NumaNode => GetField(LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode);
+
+ ///
+ /// A CACHE_RELATIONSHIP structure that describes cache attributes. This structure contains valid data only if the
+ /// Relationship member is RelationCache.
+ ///
+ public CACHE_RELATIONSHIP Cache => GetField(LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache);
+
+ ///
+ /// A PROCESSOR_RELATIONSHIP structure that describes processor affinity. This structure contains valid data only if the
+ /// Relationship member is RelationProcessorCore or RelationProcessorPackage.
+ ///
+ public PROCESSOR_RELATIONSHIP Processor => GetField(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage);
+
+ ///
+ /// A GROUP_RELATIONSHIP structure that contains information about the processor groups. This structure contains valid data
+ /// only if the Relationship member is RelationGroup.
+ ///
+ public GROUP_RELATIONSHIP Group => GetField(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup);
+
+ private T GetField(params LOGICAL_PROCESSOR_RELATIONSHIP[] r)
{
- ///
- /// A PROCESSOR_RELATIONSHIP structure that describes processor affinity. This structure contains valid data only if the
- /// Relationship member is RelationProcessorCore or RelationProcessorPackage.
- ///
- [FieldOffset(0)] public PROCESSOR_RELATIONSHIP Processor;
-
- ///
- /// A NUMA_NODE_RELATIONSHIP structure that describes a NUMA node. This structure contains valid data only if the
- /// Relationship member is RelationNumaNode.
- ///
- [FieldOffset(0)] public NUMA_NODE_RELATIONSHIP NumaNode;
-
- ///
- /// A CACHE_RELATIONSHIP structure that describes cache attributes. This structure contains valid data only if the
- /// Relationship member is RelationCache.
- ///
- [FieldOffset(0)] public CACHE_RELATIONSHIP Cache;
-
- ///
- /// A GROUP_RELATIONSHIP structure that contains information about the processor groups. This structure contains valid data
- /// only if the Relationship member is RelationGroup.
- ///
- [FieldOffset(0)] public GROUP_RELATIONSHIP Group;
- }
-
- internal string DebugString
- {
- get
+ if (!r.Contains(Relationship))
+ return default;
+ unsafe
{
- uint c = Relationship switch
- {
- LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore => RelationUnion.Processor.GroupCount,
- LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode => RelationUnion.NumaNode.NodeNumber,
- LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache => RelationUnion.Cache.CacheSize,
- LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage => RelationUnion.Processor.GroupCount,
- LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup => RelationUnion.Group.ActiveGroupCount,
- _ => 0
- };
- return $"{Relationship}, Size={Size}, Count={c}";
+ fixed (void* p = &dummy)
+ return ((IntPtr)p).ToStructure();
}
}
}
@@ -3693,5 +3615,39 @@ namespace Vanara.PInvoke
/// The cycle time for a processor.
public ulong CycleTime;
}
+
+ /// Holds a list of structures retrived from .
+ public class SafeSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_List : SafeMemoryHandle
+ {
+ internal SafeSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_List(SizeT size) : base(size)
+ {
+ }
+
+ /// Gets the number of elements available.
+ /// The number of elements available.
+ public int Count => Items.Count;
+
+ /// Gets a reference to a at the specified index.
+ /// The index.
+ /// A reference to .
+ public unsafe SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* this[int index] => (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(void*)Items[index];
+
+ /// Move to next element.
+ private List Items
+ {
+ get
+ {
+ var ret = new List();
+ for (IntPtr pCurrent = handle, pEnd = pCurrent.Offset(sz); pCurrent != IntPtr.Zero && pCurrent.ToInt64() < pEnd.ToInt64();)
+ {
+ var cSz = pCurrent.ToStructure().Size;
+ if (cSz == 0) break;
+ ret.Add(pCurrent);
+ pCurrent = pCurrent.Offset(cSz);
+ }
+ return ret;
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/UnitTests/PInvoke/Kernel32/SysInfoTests.cs b/UnitTests/PInvoke/Kernel32/SysInfoTests.cs
index 155e6724..cba11a8d 100644
--- a/UnitTests/PInvoke/Kernel32/SysInfoTests.cs
+++ b/UnitTests/PInvoke/Kernel32/SysInfoTests.cs
@@ -57,26 +57,27 @@ namespace Vanara.PInvoke.Tests
{
unsafe
{
- Assert.That(GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, out var mem, out var info), ResultIs.Successful);
- using (mem)
+ Assert.That(GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, out var info), ResultIs.Successful);
+ using (info)
{
Assert.That(info.Count, Is.GreaterThan(0));
for (int i = 0; i < info.Count; i++)
{
- switch (info[i].Relationship)
+ var pr = info[i];
+ switch (pr->Relationship)
{
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode:
- info[i].RelationUnion.NumaNode.WriteValues();
+ pr->NumaNode.WriteValues();
break;
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache:
- info[i].RelationUnion.Cache.WriteValues();
+ pr->Cache.WriteValues();
break;
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore:
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage:
- info[i].RelationUnion.Processor.WriteValues();
+ pr->Processor.WriteValues();
break;
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup:
- info[i].RelationUnion.Group.WriteValues();
+ pr->Group.WriteValues();
break;
default:
break;