diff --git a/src/Task.Monitor.Interop.Win32/ConsoleApi.cs b/src/Task.Monitor.Interop.Win32/ConsoleApi.cs index 417b33e..1bd3ae7 100644 --- a/src/Task.Monitor.Interop.Win32/ConsoleApi.cs +++ b/src/Task.Monitor.Interop.Win32/ConsoleApi.cs @@ -9,8 +9,8 @@ public static class ConsoleApi public const uint DISABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0008; [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); + public static extern bool GetConsoleMode(nint hConsoleHandle, out uint lpMode); [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); + public static extern bool SetConsoleMode(nint hConsoleHandle, uint dwMode); } \ No newline at end of file diff --git a/src/Task.Monitor.Interop.Win32/Kernel32.cs b/src/Task.Monitor.Interop.Win32/Kernel32.cs index 31c3a54..79db4b9 100644 --- a/src/Task.Monitor.Interop.Win32/Kernel32.cs +++ b/src/Task.Monitor.Interop.Win32/Kernel32.cs @@ -12,54 +12,53 @@ public static class Kernel32 public const uint PROCESS_NAME_WIN32 = 0; public const uint PROCESS_NAME_NATIVE = 1; - public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + public static readonly nint INVALID_HANDLE_VALUE = -1; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct PROCESSENTRY32W + public unsafe struct PROCESSENTRY32W { - public uint dwSize; - public uint cntUsage; - public uint th32ProcessID; - public UIntPtr th32DefaultHeapID; - public uint th32ModuleID; - public uint cntThreads; - public uint th32ParentProcessID; - public int pcPriClassBase; - public uint dwFlags; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] - public string szExeFile; + public uint dwSize; + public uint cntUsage; + public uint th32ProcessID; + public nuint th32DefaultHeapID; + public uint th32ModuleID; + public uint cntThreads; + public uint th32ParentProcessID; + public int pcPriClassBase; + public uint dwFlags; + public fixed char szExeFile[MAX_PATH]; } [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); + public static extern bool CloseHandle(nint hObject); [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID); + public static extern nint CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID); [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern bool GetProcessTimes( - IntPtr hProcess, - out MinWinBase.FILETIME lpCreationTime, - out MinWinBase.FILETIME lpExitTime, - out MinWinBase.FILETIME lpKernelTime, - out MinWinBase.FILETIME lpUserTime); + public static extern unsafe bool GetProcessTimes( + nint hProcess, + MinWinBase.FILETIME* lpCreationTime, + MinWinBase.FILETIME* lpExitTime, + MinWinBase.FILETIME* lpKernelTime, + MinWinBase.FILETIME* lpUserTime); [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern IntPtr OpenProcess( + public static extern nint OpenProcess( uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool Process32FirstW(IntPtr hSnapshot, ref PROCESSENTRY32W lppe); + public static extern unsafe bool Process32FirstW(nint hSnapshot, PROCESSENTRY32W* lppe); [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool Process32NextW(IntPtr hSnapshot, ref PROCESSENTRY32W lppe); + public static extern unsafe bool Process32NextW(nint hSnapshot, PROCESSENTRY32W* lppe); [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool QueryFullProcessImageNameW( - IntPtr hProcess, + public static extern unsafe bool QueryFullProcessImageNameW( + nint hProcess, uint dwFlags, - StringBuilder lpExeName, - ref uint lpdwSize); -} \ No newline at end of file + char* lpExeName, + uint* lpdwSize); +} diff --git a/src/Task.Monitor.Interop.Win32/Pdh.cs b/src/Task.Monitor.Interop.Win32/Pdh.cs index 26a1e95..3d3cee1 100644 --- a/src/Task.Monitor.Interop.Win32/Pdh.cs +++ b/src/Task.Monitor.Interop.Win32/Pdh.cs @@ -10,7 +10,7 @@ public static class Pdh [StructLayout(LayoutKind.Sequential)] public struct PDH_RAW_COUNTER { public uint CStatus; - public System.Runtime.InteropServices.ComTypes.FILETIME TimeStamp; + public MinWinBase.FILETIME TimeStamp; public long FirstValue; public long SecondValue; public uint MultiCount; @@ -18,33 +18,35 @@ public struct PDH_RAW_COUNTER { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct PDH_RAW_COUNTER_ITEM { - [MarshalAs(UnmanagedType.LPWStr)] public string szName; + [MarshalAs(UnmanagedType.LPWStr)] + public string szName; public PDH_RAW_COUNTER RawValue; } [DllImport(Libraries.Pdh, CharSet = CharSet.Unicode)] - public static extern uint PdhOpenQuery( + public static extern unsafe uint PdhOpenQuery( + [MarshalAs(UnmanagedType.LPWStr)] string? szDataSource, - IntPtr dwUserData, - out IntPtr phQuery); + nint dwUserData, + nint* phQuery); [DllImport(Libraries.Pdh, CharSet = CharSet.Unicode)] - public static extern uint PdhAddEnglishCounter( - IntPtr hQuery, + public static extern unsafe uint PdhAddEnglishCounter( + nint hQuery, string szFullCounterPath, - IntPtr dwUserData, - out IntPtr phCounter); + nint dwUserData, + nint* phCounter); [DllImport(Libraries.Pdh)] - public static extern uint PdhCollectQueryData(IntPtr hQuery); + public static extern uint PdhCollectQueryData(nint hQuery); [DllImport(Libraries.Pdh, CharSet = CharSet.Unicode)] - public static extern uint PdhGetRawCounterArray( - IntPtr hCounter, - ref uint lpdwBufferSize, - ref uint lpdwItemCount, - IntPtr ItemBuffer); + public static extern unsafe uint PdhGetRawCounterArray( + nint hCounter, + uint* lpdwBufferSize, + uint* lpdwItemCount, + nint ItemBuffer); [DllImport("pdh.dll")] - public static extern uint PdhCloseQuery(IntPtr hQuery); + public static extern uint PdhCloseQuery(nint hQuery); } \ No newline at end of file diff --git a/src/Task.Monitor.Interop.Win32/ProcessEnv.cs b/src/Task.Monitor.Interop.Win32/ProcessEnv.cs index d49ec03..cb234b7 100644 --- a/src/Task.Monitor.Interop.Win32/ProcessEnv.cs +++ b/src/Task.Monitor.Interop.Win32/ProcessEnv.cs @@ -8,5 +8,5 @@ public static class ProcessEnv public const int STD_INPUT_HANDLE = -10; [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern IntPtr GetStdHandle(int nStdHandle); + public static extern nint GetStdHandle(int nStdHandle); } diff --git a/src/Task.Monitor.Interop.Win32/PsApi.cs b/src/Task.Monitor.Interop.Win32/PsApi.cs index fa945e5..4bcb6c8 100644 --- a/src/Task.Monitor.Interop.Win32/PsApi.cs +++ b/src/Task.Monitor.Interop.Win32/PsApi.cs @@ -22,8 +22,8 @@ public struct PROCESS_MEMORY_COUNTERS } [DllImport(Libraries.PsApi, SetLastError = true)] - public static extern bool GetProcessMemoryInfo( - IntPtr hProcess, - ref PROCESS_MEMORY_COUNTERS psmemCounters, + public static extern unsafe bool GetProcessMemoryInfo( + nint hProcess, + PROCESS_MEMORY_COUNTERS* psmemCounters, uint cb); -} \ No newline at end of file +} diff --git a/src/Task.Monitor.Interop.Win32/SysInfoApi.cs b/src/Task.Monitor.Interop.Win32/SysInfoApi.cs index 53be82c..dce8c5f 100644 --- a/src/Task.Monitor.Interop.Win32/SysInfoApi.cs +++ b/src/Task.Monitor.Interop.Win32/SysInfoApi.cs @@ -7,8 +7,8 @@ public static unsafe class SysInfoApi [StructLayout(LayoutKind.Sequential)] public struct MEMORYSTATUSEX { - public uint dwLength; - public uint dwMemoryLoad; + public uint dwLength; + public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; @@ -27,13 +27,13 @@ public struct SYSTEM_INFO { public ushort wProcessorArchitecture; public ushort wReserved; - public uint dwPageSize; - public uint* lpMinimumApplicationAddress; - public uint* lpMaximumApplicationAddress; - public uint* dwActiveProcessorMask; - public uint dwNumberOfProcessors; - public uint dwProcessorType; - public uint dwAllocationGranularity; + public uint dwPageSize; + public uint* lpMinimumApplicationAddress; + public uint* lpMaximumApplicationAddress; + public uint* dwActiveProcessorMask; + public uint dwNumberOfProcessors; + public uint dwProcessorType; + public uint dwAllocationGranularity; public ushort wProcessorLevel; public ushort wProcessorRevision; } diff --git a/src/Task.Monitor.Interop.Win32/WinNt.cs b/src/Task.Monitor.Interop.Win32/WinNt.cs index f3ee189..7e14f3c 100644 --- a/src/Task.Monitor.Interop.Win32/WinNt.cs +++ b/src/Task.Monitor.Interop.Win32/WinNt.cs @@ -19,7 +19,7 @@ public struct IO_COUNTERS public unsafe struct SID_AND_ATTRIBUTES { public uint* Sid; - public uint Attributes; + public uint Attributes; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -29,5 +29,5 @@ public struct TOKEN_USER } [DllImport(Libraries.Kernel32, SetLastError = true)] - public static extern bool GetProcessIoCounters(IntPtr hProcess, out IO_COUNTERS counters); + public static extern unsafe bool GetProcessIoCounters(nint hProcess, IO_COUNTERS* counters); } diff --git a/src/Task.Monitor.Interop.Win32/WinService.cs b/src/Task.Monitor.Interop.Win32/WinService.cs index b016ce5..6a2d663 100644 --- a/src/Task.Monitor.Interop.Win32/WinService.cs +++ b/src/Task.Monitor.Interop.Win32/WinService.cs @@ -40,15 +40,15 @@ public struct ENUM_SERVICE_STATUS_PROCESS { public string lpServiceName; public string lpDisplayName; - public int dwServiceType; - public int dwCurrentState; - public int dwControlsAccepted; - public int dwWin32ExitCode; - public int dwServiceSpecificExitCode; - public int dwCheckPoint; - public int dwWaitHint; - public int dwProcessId; - public int dwServiceFlags; + public int dwServiceType; + public int dwCurrentState; + public int dwControlsAccepted; + public int dwWin32ExitCode; + public int dwServiceSpecificExitCode; + public int dwCheckPoint; + public int dwWaitHint; + public int dwProcessId; + public int dwServiceFlags; } [StructLayout(LayoutKind.Sequential)] @@ -67,60 +67,40 @@ public struct SERVICE_STATUS_PROCESS [DllImport(Libraries.Advapi32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseServiceHandle(IntPtr hSCObject); - - [DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Auto)] - public static extern IntPtr CreateService( - IntPtr hSCManager, - string lpServiceName, - string lpDisplayName, - uint dwDesiredAccess, - uint dwServiceType, - uint dwStartType, - uint dwErrorControl, - string lpBinaryPathName, - string lpLoadOrderGroup, - string lpdwTagId, - string lpDependencies, - string lpServiceStartName, - string lpPassword); - - [DllImport(Libraries.Advapi32, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteService(IntPtr hService); + public static extern bool CloseServiceHandle(nint hSCObject); [DllImport(Libraries.Advapi32, EntryPoint = "EnumServicesStatusExW", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool EnumServicesStatusEx( - IntPtr hSCManager, + public static extern unsafe bool EnumServicesStatusEx( + nint hSCManager, uint InfoLevel, uint dwServiceType, uint dwServiceState, - IntPtr lpServices, + nint lpServices, uint cbBufSize, - out uint pcbBytesNeeded, - out uint lpServicesReturned, - ref uint lpResumeHandle, + uint* pcbBytesNeeded, + uint* lpServicesReturned, + uint* lpResumeHandle, string pszGroupName); [DllImport(Libraries.Advapi32, SetLastError = true)] - public static extern IntPtr OpenSCManager( + public static extern nint OpenSCManager( string lpMachineName, string lpDatabaseName, int dwDesiredAccess); [DllImport(Libraries.Advapi32, SetLastError = true)] - public static extern IntPtr OpenService( - IntPtr hSCManager, + public static extern nint OpenService( + nint hSCManager, string lpServiceName, - int dwDesiredAccess); + int dwDesiredAccess); [DllImport(Libraries.Advapi32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryServiceStatusEx( - IntPtr hService, - int InfoLevel, - IntPtr lpBuffer, - uint cbBufSize, - out uint pcbBytesNeeded); -} \ No newline at end of file + public static extern unsafe bool QueryServiceStatusEx( + nint hService, + int InfoLevel, + nint lpBuffer, + uint cbBufSize, + uint* pcbBytesNeeded); +} diff --git a/src/Task.Monitor.Interop.Win32/WinUser.cs b/src/Task.Monitor.Interop.Win32/WinUser.cs index a6a9e3c..8e476e1 100644 --- a/src/Task.Monitor.Interop.Win32/WinUser.cs +++ b/src/Task.Monitor.Interop.Win32/WinUser.cs @@ -8,5 +8,5 @@ public static class WinUser public const uint GR_USEROBJECTS = 1; [DllImport(Libraries.User32)] - public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); + public static extern uint GetGuiResources(nint hProcess, uint uiFlags); } \ No newline at end of file diff --git a/src/Task.Monitor.System/Process/GpuService.Windows.cs b/src/Task.Monitor.System/Process/GpuService.Windows.cs index 8b49a98..4a7f6a5 100644 --- a/src/Task.Monitor.System/Process/GpuService.Windows.cs +++ b/src/Task.Monitor.System/Process/GpuService.Windows.cs @@ -15,14 +15,16 @@ public static partial class GpuService private static readonly Dictionary prevEngineValues = new(); private static readonly Dictionary cumulativeEngineValues = new(); - private static Dictionary GetProcessStatsInternal() + private static unsafe Dictionary GetProcessStatsInternal() { uint pdhResult = 0; + nint hQuery = 0; + nint hCounter = 0; if ((pdhResult = Pdh.PdhOpenQuery( - null, - IntPtr.Zero, - out IntPtr hQuery)) != Pdh.ERROR_SUCCESS) { + null, + nint.Zero, + &hQuery)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( nameof(Pdh.PdhOpenQuery), @@ -33,10 +35,10 @@ private static Dictionary GetProcessStatsInternal() } if ((pdhResult = Pdh.PdhAddEnglishCounter( - hQuery, - GpuEngineCounterPath, - IntPtr.Zero, - out IntPtr hCounter)) != Pdh.ERROR_SUCCESS) { + hQuery, + GpuEngineCounterPath, + nint.Zero, + &hCounter)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( GpuEngineCounterPath, @@ -62,9 +64,9 @@ private static Dictionary GetProcessStatsInternal() _ = Pdh.PdhGetRawCounterArray( hCounter, - ref bufferSize, - ref itemCount, - IntPtr.Zero); + &bufferSize, + &itemCount, + nint.Zero); if (bufferSize <= 0) { TraceEx.WriteLineOnce( @@ -75,19 +77,19 @@ private static Dictionary GetProcessStatsInternal() return new Dictionary(cumulativeEngineValues); } - IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize); + nint buffer = Marshal.AllocHGlobal((int)bufferSize); if (Pdh.PdhGetRawCounterArray( hCounter, - ref bufferSize, - ref itemCount, + &bufferSize, + &itemCount, buffer) == Pdh.ERROR_SUCCESS) { int structSize = Marshal.SizeOf(); Dictionary maxDeltas = new(); for (int i = 0; i < itemCount; i++) { - IntPtr currentItemPtr = new IntPtr(buffer.ToInt64() + (i * structSize)); + nint currentItemPtr = new nint(buffer.ToInt64() + (i * structSize)); Pdh.PDH_RAW_COUNTER_ITEM item = Marshal.PtrToStructure(currentItemPtr); if (item.RawValue.CStatus != Pdh.PDH_CSTATUS_VALID_DATA || @@ -145,21 +147,27 @@ private static int ParsePidFromInstance(string instanceName) const string pidPrefix = "pid_"; int pidIndex = instanceName.IndexOf(pidPrefix, StringComparison.OrdinalIgnoreCase); - if (pidIndex == -1) + if (pidIndex == -1) { return -1; + } int startIndex = pidIndex + pidPrefix.Length; - if (startIndex >= instanceName.Length) + + if (startIndex >= instanceName.Length) { return -1; + } int endIndex = instanceName.IndexOf('_', startIndex); - if (endIndex == -1) + + if (endIndex == -1) { endIndex = instanceName.Length; + } ReadOnlySpan pidSpan = instanceName.AsSpan(startIndex, endIndex - startIndex); - if (int.TryParse(pidSpan, out int pid)) + if (int.TryParse(pidSpan, out int pid)) { return pid; + } return -1; } diff --git a/src/Task.Monitor.System/Process/IProcessService.cs b/src/Task.Monitor.System/Process/IProcessService.cs index 62a7610..a978c7f 100644 --- a/src/Task.Monitor.System/Process/IProcessService.cs +++ b/src/Task.Monitor.System/Process/IProcessService.cs @@ -2,6 +2,6 @@ public interface IProcessService { - IEnumerable GetProcesses(); + List GetProcesses(); ProcessInfo? GetProcessById(int pid); } diff --git a/src/Task.Monitor.System/Process/ProcessService.MacOS.cs b/src/Task.Monitor.System/Process/ProcessService.MacOS.cs index 07e8bdb..5cee73c 100644 --- a/src/Task.Monitor.System/Process/ProcessService.MacOS.cs +++ b/src/Task.Monitor.System/Process/ProcessService.MacOS.cs @@ -103,8 +103,9 @@ private unsafe int[] GetPids() return pinfo; } - private IEnumerable GetProcessInfosInternal() + private List GetProcessInfosInternal() { + List processInfos = new(); int[] pids = GetPids(); Dictionary gpuStats = GpuService.GetProcessStats(); @@ -113,9 +114,11 @@ private IEnumerable GetProcessInfosInternal() ProcessInfo? pinfo = CreateProcessInfo(pids[i], gpuTime); if (pinfo != null) { - yield return pinfo; + processInfos.Add(pinfo); } } + + return processInfos; } private static unsafe string GetProcessUserName(ref ProcInfo.proc_taskallinfo procTaskInfo) diff --git a/src/Task.Monitor.System/Process/ProcessService.Windows.cs b/src/Task.Monitor.System/Process/ProcessService.Windows.cs index 94e4252..e978624 100644 --- a/src/Task.Monitor.System/Process/ProcessService.Windows.cs +++ b/src/Task.Monitor.System/Process/ProcessService.Windows.cs @@ -1,7 +1,6 @@ -using System.ComponentModel; +using System.ComponentModel.Design; using System.Runtime.InteropServices; using System.Security.Principal; -using System.ServiceProcess; using System.Text; using Microsoft.Win32.SafeHandles; using Task.Monitor.Cli.Utils; @@ -17,17 +16,17 @@ public sealed partial class ProcessService #if __WIN32__ private static Dictionary userMap = new(); - private ProcessInfo? CreateProcessInfo(ref Kernel32.PROCESSENTRY32W entry, long gpuTime) + private unsafe ProcessInfo? CreateProcessInfo(Kernel32.PROCESSENTRY32W* entry, long gpuTime) { - IntPtr hProcess = Kernel32.OpenProcess( + nint hProcess = Kernel32.OpenProcess( Kernel32.PROCESS_QUERY_LIMITED_INFORMATION, bInheritHandle: false, - entry.th32ProcessID); + entry->th32ProcessID); - if (hProcess == IntPtr.Zero) { + if (hProcess == nint.Zero) { PInvokeErrorHelpers.TraceOnceOnLastError( - $"{nameof(Kernel32.OpenProcess)}_{entry.th32ProcessID}", - $"Failed to open process for pid {entry.th32ProcessID}"); + $"{nameof(Kernel32.OpenProcess)}_{entry->th32ProcessID}", + $"Failed to open process for pid {entry->th32ProcessID}"); return null; } @@ -35,31 +34,33 @@ public sealed partial class ProcessService SafeProcessHandle processHandle = new(hProcess, ownsHandle: false); ProcessInfo processInfo = new() { - Pid = (int)entry.th32ProcessID + Pid = (int)entry->th32ProcessID }; - processInfo.ProcessName = entry.szExeFile.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) - ? entry.szExeFile.Substring(0, entry.szExeFile.Length - 4) - : entry.szExeFile; + string exeFile = new string(entry->szExeFile); + + processInfo.ProcessName = exeFile.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) + ? exeFile.Substring(0, exeFile.Length - 4) + : exeFile; processInfo.FileName = GetProcessPath(hProcess); processInfo.FileDescription = GetProcessProductName( - entry.th32ProcessID, + entry->th32ProcessID, processInfo.FileName, processInfo.ProcessName); - processInfo.ModuleName = Path.GetFileName(entry.szExeFile); - processInfo.IsDaemon = ServiceUtils.GetService((int)entry.th32ProcessID, out ServiceInfo? _); - processInfo.IsLowPriority = entry.pcPriClassBase < 8; + processInfo.ModuleName = Path.GetFileName(exeFile); + processInfo.IsDaemon = ServiceUtils.GetService((int)entry->th32ProcessID, out ServiceInfo? _); + processInfo.IsLowPriority = entry->pcPriClassBase < 8; processInfo.UserName = GetProcessUserName(processHandle); - processInfo.CmdLine = GetProcessCommandLine((int)entry.th32ProcessID, processInfo.FileName); - processInfo.ThreadCount = (int)entry.cntThreads; + processInfo.CmdLine = GetProcessCommandLine((int)entry->th32ProcessID, processInfo.FileName); + processInfo.ThreadCount = (int)entry->cntThreads; processInfo.HandleCount = 0; - processInfo.BasePriority = entry.pcPriClassBase; + processInfo.BasePriority = entry->pcPriClassBase; PsApi.PROCESS_MEMORY_COUNTERS memCounters = new(); - GetProcessMemCounters(hProcess, ref memCounters); + GetProcessMemCounters(hProcess, &memCounters); processInfo.UsedMemory = (long)memCounters.WorkingSetSize; GetProcessorTimes( @@ -101,12 +102,12 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) } } - private ProcessInfo? GetProcessInfoInternal(int pid) + private unsafe ProcessInfo? GetProcessInfoInternal(int pid) { ProcessInfo? processInfo = null; - IntPtr hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); + nint hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); - if (hSnapshot == IntPtr.Zero) { + if (hSnapshot == nint.Zero) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.CreateToolhelp32Snapshot)); return null; } @@ -115,7 +116,7 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) dwSize = (uint)Marshal.SizeOf() }; - if (!Kernel32.Process32FirstW(hSnapshot, ref entry)) { + if (!Kernel32.Process32FirstW(hSnapshot, &entry)) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.Process32FirstW)); return null; } @@ -127,7 +128,7 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) Dictionary gpuStats = GpuService.GetProcessStats(); long gpuTime = gpuStats.GetValueOrDefault((int)entry.th32ProcessID, 0); - processInfo = CreateProcessInfo(ref entry, gpuTime); + processInfo = CreateProcessInfo(&entry, gpuTime); if (processInfo != null) { break; @@ -135,55 +136,60 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) entry.dwSize = (uint)Marshal.SizeOf(); - } while (Kernel32.Process32NextW(hSnapshot, ref entry)); + } while (Kernel32.Process32NextW(hSnapshot, &entry)); Kernel32.CloseHandle(hSnapshot); return processInfo; } - private IEnumerable GetProcessInfosInternal() + private unsafe List GetProcessInfosInternal() { + List processInfos = new(); Dictionary gpuStats = GpuService.GetProcessStats(); - IntPtr hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); + nint hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); - if (hSnapshot == IntPtr.Zero) { + if (hSnapshot == nint.Zero) { PInvokeErrorHelpers.TraceOnLastError(nameof(Kernel32.CreateToolhelp32Snapshot)); - yield break; + return processInfos; } Kernel32.PROCESSENTRY32W entry = new() { dwSize = (uint)Marshal.SizeOf() }; - if (!Kernel32.Process32FirstW(hSnapshot, ref entry)) { + if (!Kernel32.Process32FirstW(hSnapshot, &entry)) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.Process32FirstW)); - yield break; + Kernel32.CloseHandle(hSnapshot); + return processInfos; } do { long gpuTime = gpuStats.GetValueOrDefault((int)entry.th32ProcessID, 0); - ProcessInfo? processInfo = CreateProcessInfo(ref entry, gpuTime); + ProcessInfo? processInfo = CreateProcessInfo(&entry, gpuTime); if (processInfo != null) { - yield return processInfo; + processInfos.Add(processInfo); } entry.dwSize = (uint)Marshal.SizeOf(); - } while (Kernel32.Process32NextW(hSnapshot, ref entry)); + } while (Kernel32.Process32NextW(hSnapshot, &entry)); Kernel32.CloseHandle(hSnapshot); + return processInfos; } - private static void GetProcessIoOperations( - IntPtr hProcess, + private static unsafe void GetProcessIoOperations( + nint hProcess, out ulong readBytes, out ulong writeBytes) { readBytes = 0; writeBytes = 0; - if (!WinNt.GetProcessIoCounters(hProcess, out WinNt.IO_COUNTERS counters)) { + WinNt.IO_COUNTERS counters = new(); + + if (!WinNt.GetProcessIoCounters(hProcess, &counters)) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(WinNt.GetProcessIoCounters)); return; } @@ -192,57 +198,64 @@ private static void GetProcessIoOperations( writeBytes = counters.WriteTransferCount; } - private void GetProcessMemCounters(IntPtr hProcess, ref PsApi.PROCESS_MEMORY_COUNTERS counters) + private unsafe void GetProcessMemCounters(nint hProcess, PsApi.PROCESS_MEMORY_COUNTERS* counters) { - counters.cb = (uint)Marshal.SizeOf(); + counters->cb = (uint)Marshal.SizeOf(); if (!PsApi.GetProcessMemoryInfo( hProcess, - ref counters, - counters.cb)) { + counters, + counters->cb)) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(PsApi.GetProcessMemoryInfo)); } } - private void GetProcessorTimes( - IntPtr hProcess, + private unsafe void GetProcessorTimes( + nint hProcess, out long kernelTime, out long userTime) { + MinWinBase.FILETIME creationFileTime = new(); + MinWinBase.FILETIME exitFileTime = new(); + MinWinBase.FILETIME kernelFileTime = new(); + MinWinBase.FILETIME userFileTime = new(); + kernelTime = 0; userTime = 0; if (!Kernel32.GetProcessTimes(hProcess, - out MinWinBase.FILETIME creation, - out MinWinBase.FILETIME exit, - out MinWinBase.FILETIME kernel, - out MinWinBase.FILETIME user)) { + &creationFileTime, + &exitFileTime, + &kernelFileTime, + &userFileTime)) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.GetProcessTimes)); return; } - - kernelTime = kernel.ToLong(); - userTime = user.ToLong(); + + kernelTime = kernelFileTime.ToLong(); + userTime = userFileTime.ToLong(); } - private string GetProcessPath(IntPtr hProcess, uint flags = Kernel32.PROCESS_NAME_WIN32) + private unsafe string GetProcessPath(nint hProcess, uint flags = Kernel32.PROCESS_NAME_WIN32) { uint size = 1024; - var sb = new StringBuilder((int)size); + Span buffer = stackalloc char[(int)size]; + + fixed (char* pBuffer = &MemoryMarshal.GetReference(buffer)) { + if (!Kernel32.QueryFullProcessImageNameW( + hProcess, + flags, + pBuffer, + &size)) { + + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.QueryFullProcessImageNameW)); + return string.Empty; + } - if (!Kernel32.QueryFullProcessImageNameW( - hProcess, - flags, - sb, - ref size)) { - - PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.QueryFullProcessImageNameW)); - return string.Empty; + return buffer.Slice(0, (int)size).ToString(); } - - return sb.ToString(0, (int)size); } private static string GetProcessProductName( @@ -338,7 +351,7 @@ private static unsafe bool GetProcessTokenSid(SafeProcessHandle processHandle, o if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { uint* sidPtr = tokenUser->sidAndAttributes.Sid; - sid = new SecurityIdentifier(new IntPtr(sidPtr)); + sid = new SecurityIdentifier(new nint(sidPtr)); } } else { diff --git a/src/Task.Monitor.System/Process/ProcessService.cs b/src/Task.Monitor.System/Process/ProcessService.cs index c93b664..1ab08f1 100644 --- a/src/Task.Monitor.System/Process/ProcessService.cs +++ b/src/Task.Monitor.System/Process/ProcessService.cs @@ -2,12 +2,7 @@ public sealed partial class ProcessService : IProcessService { - public IEnumerable GetProcesses() - { - foreach (ProcessInfo processInfo in GetProcessInfosInternal()) { - yield return processInfo; - } - } + public List GetProcesses() => GetProcessInfosInternal(); public ProcessInfo? GetProcessById(int pid) => GetProcessInfoInternal(pid); } diff --git a/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs b/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs index 735e839..6c31347 100644 --- a/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs +++ b/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs @@ -20,9 +20,9 @@ private static void BuildServiceMap() { serviceMap.Clear(); - IntPtr hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_CONNECT); + nint hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_CONNECT); - if (hSCM == IntPtr.Zero) { + if (hSCM == nint.Zero) { PInvokeErrorHelpers.TraceOnceOnLastError(nameof(WinService.SC_MANAGER_CONNECT)); return; } @@ -32,12 +32,12 @@ private static void BuildServiceMap() for (int i = 0; i < services.Length; i++) { ServiceInfo service = services[i]; - IntPtr hService = WinService.OpenService( + nint hService = WinService.OpenService( hSCM, service.ServiceName, WinService.SERVICE_QUERY_STATUS); - if (hService == IntPtr.Zero) { + if (hService == nint.Zero) { PInvokeErrorHelpers.TraceOnceOnLastError($"{nameof(WinService.OpenService)} {service.ServiceName}"); continue; } @@ -82,17 +82,18 @@ public static bool GetService(int pid, out ServiceInfo? service) return key?.GetValue("ImagePath")?.ToString() ?? null; } - private static int GetServiceProcessId(IntPtr hService) + private static unsafe int GetServiceProcessId(nint hService) { int pid = 0; - IntPtr pss = Marshal.AllocHGlobal(Marshal.SizeOf()); - + nint pss = Marshal.AllocHGlobal(Marshal.SizeOf()); + uint bytesNeeded = 0; + if (!WinService.QueryServiceStatusEx( hService, WinService.SC_ENUM_PROCESS_INFO, pss, (uint)Marshal.SizeOf(), - out _)) { + &bytesNeeded)) { PInvokeErrorHelpers.TraceOnceOnLastError($"{nameof(WinService.QueryServiceStatusEx)} {hService}"); return 0; @@ -113,12 +114,12 @@ private static int GetServiceProcessId(IntPtr hService) return pid; } - internal static ServiceInfo[] GetServices() + internal static unsafe ServiceInfo[] GetServices() { ServiceInfo[] services = []; - IntPtr hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_ENUMERATE_SERVICE); + nint hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_ENUMERATE_SERVICE); - if (hSCM == IntPtr.Zero) { + if (hSCM == nint.Zero) { PInvokeErrorHelpers.TraceOnceOnLastError( nameof(WinService.OpenSCManager), $"Failed GetServices {nameof(WinService.SC_MANAGER_ENUMERATE_SERVICE)}"); @@ -126,7 +127,7 @@ internal static ServiceInfo[] GetServices() return services; } - IntPtr buffer = IntPtr.Zero; + nint buffer = nint.Zero; uint bytesNeeded = 0; uint servicesReturned = 0; @@ -137,11 +138,11 @@ internal static ServiceInfo[] GetServices() WinService.INFO_LEVEL_STANDARD, WinService.SERVICE_TYPE_ALL, WinService.SERVICE_STATE_ALL, - IntPtr.Zero, + nint.Zero, 0, - out bytesNeeded, - out servicesReturned, - ref resumeHandle, + &bytesNeeded, + &servicesReturned, + &resumeHandle, null!); if (bytesNeeded == 0) { @@ -153,7 +154,7 @@ internal static ServiceInfo[] GetServices() return services; } - buffer = Marshal.AllocHGlobal((IntPtr)bytesNeeded); + buffer = Marshal.AllocHGlobal((nint)bytesNeeded); resumeHandle = 0; bool result = WinService.EnumServicesStatusEx( @@ -163,9 +164,9 @@ internal static ServiceInfo[] GetServices() WinService.SERVICE_STATE_ALL, buffer, bytesNeeded, - out bytesNeeded, - out servicesReturned, - ref resumeHandle, + &bytesNeeded, + &servicesReturned, + &resumeHandle, null!); if (!result) { @@ -173,7 +174,7 @@ internal static ServiceInfo[] GetServices() nameof(WinService.EnumServicesStatusEx), $"{nameof(WinService.EnumServicesStatusEx)} failed to allocate {nameof(buffer)}"); - if (buffer != IntPtr.Zero) { + if (buffer != nint.Zero) { Marshal.FreeHGlobal(buffer); } @@ -181,7 +182,7 @@ internal static ServiceInfo[] GetServices() return services; } - IntPtr currentPtr = buffer; + nint currentPtr = buffer; int structSize = Marshal.SizeOf(); services = new ServiceInfo[servicesReturned]; @@ -193,10 +194,10 @@ internal static ServiceInfo[] GetServices() DisplayName = status.lpDisplayName }; - currentPtr = IntPtr.Add(currentPtr, structSize); + currentPtr = nint.Add(currentPtr, structSize); } - if (buffer != IntPtr.Zero) { + if (buffer != nint.Zero) { Marshal.FreeHGlobal(buffer); } diff --git a/src/Task.Monitor.System/Process/ThreadInfo.cs b/src/Task.Monitor.System/Process/ThreadInfo.cs index 1296fd8..2323c04 100644 --- a/src/Task.Monitor.System/Process/ThreadInfo.cs +++ b/src/Task.Monitor.System/Process/ThreadInfo.cs @@ -6,7 +6,7 @@ public class ThreadInfo public string ThreadState { get; set; } = string.Empty; public string Reason { get; set; } = string.Empty; public int Priority { get; set; } = 0; - public long StartAddress { get; set; } = IntPtr.Zero; + public long StartAddress { get; set; } = nint.Zero; public TimeSpan CpuKernelTime { get; set; } = TimeSpan.Zero; public TimeSpan CpuUserTime { get; set; } = TimeSpan.Zero; public TimeSpan CpuTotalTime { get; set; } = TimeSpan.Zero; diff --git a/src/Task.Monitor.System/SystemInfo.Windows.cs b/src/Task.Monitor.System/SystemInfo.Windows.cs index 4c31e1d..31ffd6d 100644 --- a/src/Task.Monitor.System/SystemInfo.Windows.cs +++ b/src/Task.Monitor.System/SystemInfo.Windows.cs @@ -161,18 +161,18 @@ private static bool GetGpuMemoryInternalTotal(ref SystemStatistics systemStatist return true; } - private static bool GetGpuMemoryInternalUsed(ref SystemStatistics systemStatistics) + private static unsafe bool GetGpuMemoryInternalUsed(ref SystemStatistics systemStatistics) { const string AdapterMemoryCounterPath = @"\GPU Adapter Memory(*)\Dedicated Usage"; - IntPtr hQuery; - IntPtr hCounter; + nint hQuery = 0; + nint hCounter = 0; uint pdhResult = 0; if ((pdhResult = Pdh.PdhOpenQuery( null, - IntPtr.Zero, - out hQuery)) != Pdh.ERROR_SUCCESS) { + nint.Zero, + &hQuery)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( nameof(Pdh.PdhOpenQuery), @@ -186,8 +186,8 @@ private static bool GetGpuMemoryInternalUsed(ref SystemStatistics systemStatisti if ((pdhResult = Pdh.PdhAddEnglishCounter( hQuery, AdapterMemoryCounterPath, - IntPtr.Zero, - out hCounter)) != Pdh.ERROR_SUCCESS) { + nint.Zero, + &hCounter)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( AdapterMemoryCounterPath, @@ -215,7 +215,7 @@ private static bool GetGpuMemoryInternalUsed(ref SystemStatistics systemStatisti return true; } - private static bool GetNetworkStatsInternal(ref NetworkStatistics networkStatistics) + private static unsafe bool GetNetworkStatsInternal(ref NetworkStatistics networkStatistics) { networkStatistics.NetworkBytesSent = 0; networkStatistics.NetworkBytesReceived = 0; @@ -225,15 +225,15 @@ private static bool GetNetworkStatsInternal(ref NetworkStatistics networkStatist const string BytesReceivedPath = @"\Network Interface(*)\Bytes Received/sec"; const string BytesSentPath = @"\Network Interface(*)\Bytes Sent/sec"; - IntPtr hQuery; - IntPtr hCounterReceived; - IntPtr hCounterSent; + nint hQuery = 0; + nint hCounterReceived = 0; + nint hCounterSent = 0; uint pdhResult = 0; if ((pdhResult = Pdh.PdhOpenQuery( null, - IntPtr.Zero, - out hQuery)) != Pdh.ERROR_SUCCESS) { + nint.Zero, + &hQuery)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( nameof(Pdh.PdhOpenQuery), @@ -246,8 +246,8 @@ private static bool GetNetworkStatsInternal(ref NetworkStatistics networkStatist if ((pdhResult = Pdh.PdhAddEnglishCounter( hQuery, BytesReceivedPath, - IntPtr.Zero, - out hCounterReceived)) != Pdh.ERROR_SUCCESS) { + nint.Zero, + &hCounterReceived)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( BytesReceivedPath, @@ -261,8 +261,8 @@ private static bool GetNetworkStatsInternal(ref NetworkStatistics networkStatist if ((pdhResult = Pdh.PdhAddEnglishCounter( hQuery, BytesSentPath, - IntPtr.Zero, - out hCounterSent)) != Pdh.ERROR_SUCCESS) { + nint.Zero, + &hCounterSent)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnPInvokeError(nameof(Pdh.PdhAddEnglishCounter), pdhResult); Pdh.PdhCloseQuery(hQuery); @@ -359,7 +359,7 @@ private static bool IsRunningAsRootInternal() return principal.IsInRole(WindowsBuiltInRole.Administrator); } - private static long SumRawCounterArray(IntPtr hCounter) + private static unsafe long SumRawCounterArray(nint hCounter) { uint bufferSize = 0; uint itemCount = 0; @@ -367,9 +367,9 @@ private static long SumRawCounterArray(IntPtr hCounter) _ = Pdh.PdhGetRawCounterArray( hCounter, - ref bufferSize, - ref itemCount, - IntPtr.Zero); + &bufferSize, + &itemCount, + nint.Zero); if (bufferSize <= 0) { TraceEx.WriteLineOnce( @@ -379,12 +379,12 @@ private static long SumRawCounterArray(IntPtr hCounter) return -1; } - IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize); + nint buffer = Marshal.AllocHGlobal((int)bufferSize); if ((pdhResult = Pdh.PdhGetRawCounterArray( hCounter, - ref bufferSize, - ref itemCount, + &bufferSize, + &itemCount, buffer)) != Pdh.ERROR_SUCCESS) { PInvokeErrorHelpers.TraceOnceOnPInvokeError( @@ -401,7 +401,7 @@ private static long SumRawCounterArray(IntPtr hCounter) for (int i = 0; i < itemCount; i++) { - IntPtr ptr = new IntPtr(buffer.ToInt64() + (i * structSize)); + nint ptr = new nint(buffer.ToInt64() + (i * structSize)); Pdh.PDH_RAW_COUNTER_ITEM item = Marshal.PtrToStructure(ptr); if (item.RawValue.CStatus == Pdh.PDH_CSTATUS_VALID_DATA) { diff --git a/src/Task.Monitor.System/SystemTerminal.Windows.cs b/src/Task.Monitor.System/SystemTerminal.Windows.cs index 7a71957..3e4cac9 100644 --- a/src/Task.Monitor.System/SystemTerminal.Windows.cs +++ b/src/Task.Monitor.System/SystemTerminal.Windows.cs @@ -28,9 +28,9 @@ private void EnableAnsiTerminalCodesInternal() { // Not all terminals on Windows platforms (conhost.exe as an example) support VT/ANSI escape codes. // We attempt to enable here to support older terminals. - IntPtr consoleHandle = ProcessEnv.GetStdHandle(ProcessEnv.STD_OUTPUT_HANDLE); + nint consoleHandle = ProcessEnv.GetStdHandle(ProcessEnv.STD_OUTPUT_HANDLE); - if (consoleHandle == IntPtr.Zero || consoleHandle == new IntPtr(-1)) { + if (consoleHandle == 0 || consoleHandle == -1) { PInvokeErrorHelpers.AssertOnLastError(nameof(ProcessEnv.GetStdHandle)); PInvokeErrorHelpers.TraceOnLastError(nameof(ProcessEnv.GetStdHandle)); return; diff --git a/tests/Task.Monitor.Tests/Process/ProcessServiceFake.cs b/tests/Task.Monitor.Tests/Process/ProcessServiceFake.cs index 7ca1d4f..bc3756c 100644 --- a/tests/Task.Monitor.Tests/Process/ProcessServiceFake.cs +++ b/tests/Task.Monitor.Tests/Process/ProcessServiceFake.cs @@ -9,7 +9,7 @@ public sealed class ProcessServiceFake : IProcessService public void AddProcessInfo(ProcessInfo processInfo) => processInfos.Add(processInfo); - public IEnumerable GetProcesses() => processInfos; + public List GetProcesses() => processInfos; public ProcessInfo? GetProcessById(int pid) => processInfos.SingleOrDefault(p => p.Pid == pid);