using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Threading; namespace PCL.Core.Utils.OS; public static partial class KernelInterop { // ReSharper disable InconsistentNaming, UnusedMember.Local [LibraryImport("kernel32.dll", EntryPoint = "GetCurrentThreadId", SetLastError = true)] private static partial uint _GetCurrentThreadId(); [LibraryImport("kernel32.dll", EntryPoint = "ExitProcess", SetLastError = false)] private static partial void _ExitProcess(uint statusCode); [LibraryImport("kernel32.dll", EntryPoint = "GetNamedPipeClientProcessId", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool _GetNamedPipeClientProcessId(IntPtr pipeHandle, out uint clientProcessId); [LibraryImport("kernel32.dll", EntryPoint = "GetLogicalProcessorInformationEx", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool _GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationshipType, IntPtr buffer, ref uint returnLength); private const int ERROR_INSUFFICIENT_BUFFER = 122; private enum LOGICAL_PROCESSOR_RELATIONSHIP : uint { RelationProcessorCore = 0, RelationNumaNode = 1, RelationCache = 2, RelationProcessorPackage = 3, RelationGroup = 4, RelationAll = 0xffff } private static MEMORYSTATUSEX CreateStatus() => new() { dwLength = (uint)Marshal.SizeOf() }; [LibraryImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; } private const int ERROR_ACCESS_DENIED = 5; [LibraryImport("kernel32.dll", EntryPoint = "AllocConsole")] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool _AllocConsole(); [LibraryImport("kernel32.dll", EntryPoint = "FreeConsole")] private static partial void _FreeConsole(); [LibraryImport("kernel32.dll", EntryPoint = "GetConsoleWindow")] private static partial nint _GetConsoleWindow(); // ReSharper restore InconsistentNaming, UnusedMember.Local private static void _ThrowLastWin32Error(int? errorCode = null) => throw new Win32Exception(errorCode ?? Marshal.GetLastWin32Error()); /// /// 获取当前线程的 Win32 Thread ID。若无特殊情况请用 而不是这个方法。 /// public static uint CurrentNativeThreadId => _GetCurrentThreadId(); /// /// 直接结束当前进程。若无特殊情况请使用 /// /// 退出状态码 (返回值) public static void ExitProcess(int statusCode = 0) => _ExitProcess((uint)statusCode); /// /// 获取指定命名管道当前连接的客户端进程 ID /// /// 命名管道句柄 /// 获取到的进程 ID public static uint GetNamedPipeClientProcessId(IntPtr pipeHandle) { if (!_GetNamedPipeClientProcessId(pipeHandle, out var clientProcessId)) _ThrowLastWin32Error(); return clientProcessId; } /// /// 获取仅包含性能核(P-core)的逻辑处理器数量。 /// 在不支持 EfficiencyClass(旧 OS 或非混合架构)时,会退回到 Environment.ProcessorCount。 /// public static int GetPerformanceLogicalProcessorCount() { var cores = QueryProcessorCoreRelationships(); if (cores.Count == 0) { // 不支持 EfficiencyClass return Environment.ProcessorCount; } // 原理:性能核的 EfficiencyClass 一定比能效核大 var maxEff = cores.Max(c => c.EfficiencyClass); // 统计所有效率等级为 maxEff 的核心的掩码位数 return cores .Where(c => c.EfficiencyClass == maxEff) .Sum(c => CountSetBits(c.Mask)); static int CountSetBits(ulong v) { var cnt = 0; while (v != 0) { cnt += (int)(v & 1); v >>= 1; } return cnt; } } /// /// 仅承载 EfficiencyClass 和 Mask 的简单 CPU 核心信息 /// public sealed record ProcessorCore(byte EfficiencyClass, ulong Mask); /// /// 枚举 RelationProcessorCore 返回的所有物理核心关系信息 /// // Partly generated by o4-mini-high (20250709) public static List QueryProcessorCoreRelationships() { uint returnedLength = 0; // 第一次调用仅为了获取所需缓冲区大小 if (!_GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, IntPtr.Zero, ref returnedLength) && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var list = new List(); var buffer = Marshal.AllocHGlobal((int)returnedLength); try { if (!_GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, buffer, ref returnedLength)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var ptr = buffer; var end = IntPtr.Add(buffer, (int)returnedLength); // SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX 头部:Relationship (4 字节) + Size (4 字节) const int headerSize = sizeof(uint) + sizeof(uint); // GROUP_AFFINITY 大小 = KAFFINITY (平台指针大小) + WORD Group + WORD[3] Reserved var groupAffinitySize = IntPtr.Size + 8; while (ptr.ToInt64() < end.ToInt64()) { var relationship = (uint)Marshal.ReadInt32(ptr); var size = (uint)Marshal.ReadInt32(ptr, sizeof(uint)); if (relationship == (uint)LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore) { // PROCESSOR_RELATIONSHIP 结构: // Flags BYTE @ offset 8 // EfficiencyClass BYTE @ offset 9 // Reserved[20] BYTE[20] // GroupCount WORD @ offset 30 // GroupMask[ANYSIZE] GROUP_AFFINITY 从 offset 32 开始 var efficiencyClass = Marshal.ReadByte(ptr, headerSize + 1); var groupCount = (ushort)Marshal.ReadInt16(ptr, headerSize + 2 + 20); var maskBase = IntPtr.Add(ptr, headerSize + 2 + 20 + sizeof(ushort)); for (var i = 0; i < groupCount; i++) { var affinityPtr = IntPtr.Add(maskBase, i * groupAffinitySize); // 只读取 Mask 部分,统计位数 var mask = (IntPtr.Size == 8 ? (ulong)Marshal.ReadInt64(affinityPtr) : (uint)Marshal.ReadInt32(affinityPtr)); list.Add(new ProcessorCore(efficiencyClass, mask)); } } // 移动到下一个记录 ptr = IntPtr.Add(ptr, (int)size); } } finally { Marshal.FreeHGlobal(buffer); } return list; } /// /// 获取系统可用物理内存 (ullAvailPhys) 的字节数 /// public static ulong GetAvailablePhysicalMemoryBytes() { var status = CreateStatus(); if (!GlobalMemoryStatusEx(ref status)) _ThrowLastWin32Error(); return status.ullAvailPhys; } /// /// 获取系统可用物理内存 (ullAvailPhys) 和总物理内存 (ullTotalPhys) 的字节数 /// public static (ulong Total, ulong Available) GetPhysicalMemoryBytes() { var status = CreateStatus(); if (!GlobalMemoryStatusEx(ref status)) _ThrowLastWin32Error(); return (status.ullTotalPhys, status.ullAvailPhys); } /// /// 获取以百分比表示的系统内存占用 (范围 0.0 ~ 100.0) /// public static double GetMemoryLoadPercent() { var status = CreateStatus(); if (!GlobalMemoryStatusEx(ref status)) _ThrowLastWin32Error(); return status.dwMemoryLoad; } /// /// 为当前进程新建终端窗口。
/// 若进程已拥有终端窗口,该方法将无任何作用。若有需要,可在调用前使用 /// 来确认进程是否存在关联的终端窗口。 ///
public static void AllocateConsole() { if (_AllocConsole()) return; var lastError = Marshal.GetLastWin32Error(); if (lastError != ERROR_ACCESS_DENIED) _ThrowLastWin32Error(lastError); } /// /// 释放当前进程的终端窗口。
/// 若进程不存在关联的终端窗口,该方法将无任何作用。 ///
public static void FreeConsole() => _FreeConsole(); /// /// 获取当前进程关联的终端窗口句柄。 /// /// 代表终端窗口的 HWND,若当前进程无关联的终端窗口,则该值为 public static nint GetConsoleWindow() => _GetConsoleWindow(); }