Update WinApi
This commit is contained in:
parent
49abc808a4
commit
09af9d5091
@ -22,7 +22,7 @@ namespace WebmrAPI.Models
|
|||||||
}
|
}
|
||||||
public string? BaseAddress
|
public string? BaseAddress
|
||||||
{
|
{
|
||||||
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X12}" : null;
|
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X16}" : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
// File: Models/MemoryRegionInfo.cs
|
// File: Models/MemoryRegionInfo.cs
|
||||||
|
|
||||||
|
using WebmrAPI.Services;
|
||||||
|
|
||||||
namespace WebmrAPI.Models
|
namespace WebmrAPI.Models
|
||||||
{
|
{
|
||||||
public class MemoryRegionInfo : MemoryRegion
|
public class MemoryRegionInfo : MemoryRegion
|
||||||
{
|
{
|
||||||
private string _state = String.Empty;
|
private WinApi.MemoryState _state = 0;
|
||||||
private string _protect = String.Empty;
|
private WinApi.MemoryPageProtectionState _protect = 0;
|
||||||
private string _type = String.Empty;
|
private WinApi.MemoryType _type = 0;
|
||||||
|
|
||||||
public string State
|
public WinApi.MemoryState MemoryState
|
||||||
{
|
{
|
||||||
get => LockedGet(ref _state);
|
get => LockedGet(ref _state);
|
||||||
set => LockedSet(ref _state, value);
|
set => LockedSet(ref _state, value);
|
||||||
}
|
}
|
||||||
public string Protect
|
public WinApi.MemoryPageProtectionState MemoryPageProtection
|
||||||
{
|
{
|
||||||
get => LockedGet(ref _protect);
|
get => LockedGet(ref _protect);
|
||||||
set => LockedSet(ref _protect, value);
|
set => LockedSet(ref _protect, value);
|
||||||
}
|
}
|
||||||
public string Type
|
public WinApi.MemoryType MemoryType
|
||||||
{
|
{
|
||||||
get => LockedGet(ref _type);
|
get => LockedGet(ref _type);
|
||||||
set => LockedSet(ref _type, value);
|
set => LockedSet(ref _type, value);
|
||||||
|
@ -34,7 +34,7 @@ namespace WebmrAPI.Models
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public double ProcessorTime
|
public double ProcessorTime
|
||||||
{
|
{
|
||||||
get { lock (_lock) return (_lastPTime - _curPTime).TotalMilliseconds; }
|
get { lock (_lock) return (_curPTime - _lastPTime).TotalMilliseconds; }
|
||||||
}
|
}
|
||||||
public int PID
|
public int PID
|
||||||
{
|
{
|
||||||
|
@ -128,15 +128,15 @@ namespace WebmrAPI.Services
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mbi.State == WinApi.MEM_COMMIT || mbi.State == WinApi.MEM_RESERVE)
|
if (mbi.State == WinApi.MemoryState.Commit || mbi.State == WinApi.MemoryState.Reserve)
|
||||||
{
|
{
|
||||||
regions.Add(new MemoryRegionInfo
|
regions.Add(new MemoryRegionInfo
|
||||||
{
|
{
|
||||||
MemoryAddress = mbi.BaseAddress.ToInt64(),
|
MemoryAddress = mbi.BaseAddress.ToInt64(),
|
||||||
MemorySize = mbi.RegionSize.ToUInt64(),
|
MemorySize = mbi.RegionSize.ToUInt64(),
|
||||||
State = WinApi.GetStateString(mbi.State),
|
MemoryState = mbi.State,
|
||||||
Protect = WinApi.GetProtectString(mbi.Protect),
|
MemoryPageProtection = mbi.PageProtection,
|
||||||
Type = WinApi.GetTypeString(mbi.Type)
|
MemoryType = mbi.Type
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ namespace WebmrAPI.Services
|
|||||||
private void PopulateBaseProcessInfo(ProcessInfo dst, System.Diagnostics.Process process, Dictionary<int, (string? Name, string? CommandLine, int ParentPID)> wmiData)
|
private void PopulateBaseProcessInfo(ProcessInfo dst, System.Diagnostics.Process process, Dictionary<int, (string? Name, string? CommandLine, int ParentPID)> wmiData)
|
||||||
{
|
{
|
||||||
dst.PID = process.Id;
|
dst.PID = process.Id;
|
||||||
dst.MemorySize = (ulong)process.VirtualMemorySize64;
|
dst.MemorySize = (ulong)process.WorkingSet64;
|
||||||
dst.ThreadCount = process.Threads.Count;
|
dst.ThreadCount = process.Threads.Count;
|
||||||
dst.TotalProcessorTime = process.TotalProcessorTime;
|
dst.TotalProcessorTime = process.TotalProcessorTime;
|
||||||
dst.MemoryAddress = 0x000000000000;
|
dst.MemoryAddress = 0x000000000000;
|
||||||
|
@ -1,60 +1,58 @@
|
|||||||
// File: Services/WinApi.cs
|
// File: Services/WinApi.cs
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using WebmrAPI.Utils;
|
||||||
|
|
||||||
namespace WebmrAPI.Services
|
namespace WebmrAPI.Services
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
public static class WinApi
|
public static class WinApi
|
||||||
{
|
{
|
||||||
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
|
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
|
||||||
public const uint PROCESS_VM_READ = 0x00000010;
|
public const uint PROCESS_VM_READ = 0x00000010;
|
||||||
public const uint PROCESS_VM_OPERATION = 0x00000008;
|
public const uint PROCESS_VM_OPERATION = 0x00000008;
|
||||||
|
|
||||||
public const uint MEM_COMMIT = 0x00001000;
|
|
||||||
public const uint MEM_FREE = 0x00010000;
|
|
||||||
public const uint MEM_RESERVE = 0x00002000;
|
|
||||||
|
|
||||||
public const uint MEM_IMAGE = 0x01000000;
|
|
||||||
public const uint MEM_MAPPED = 0x00040000;
|
|
||||||
public const uint MEM_PRIVATE = 0x00020000;
|
|
||||||
|
|
||||||
public static int LastError { get => Marshal.GetLastWin32Error(); }
|
public static int LastError { get => Marshal.GetLastWin32Error(); }
|
||||||
public static uint MBISize { get => (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)); }
|
public static uint MBISize { get => (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)); }
|
||||||
|
|
||||||
private static string GetHexValue(uint data)
|
[JsonConverter(typeof(JsonEnumConverter<MemoryState>))]
|
||||||
|
public enum MemoryState : uint
|
||||||
{
|
{
|
||||||
return $"0x{data:X8}";
|
Undefined = 0,
|
||||||
|
Commit = 0x00001000,
|
||||||
|
Reserve = 0x00002000,
|
||||||
|
Free = 0x00010000,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetStateString(uint state)
|
[JsonConverter(typeof(JsonEnumConverter<MemoryType>))]
|
||||||
|
public enum MemoryType : uint
|
||||||
{
|
{
|
||||||
switch (state)
|
Undefined = 0,
|
||||||
{
|
Image = 0x01000000,
|
||||||
case MEM_COMMIT: return "MEM_COMMIT";
|
Mapped = 0x00040000,
|
||||||
case MEM_FREE: return "MEM_FREE";
|
Private = 0x00020000,
|
||||||
case MEM_RESERVE: return "MEM_RESERVE";
|
|
||||||
default: return GetHexValue(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetProtectString(uint protect)
|
[JsonConverter(typeof(JsonEnumConverter<MemoryPageProtectionState>))]
|
||||||
|
public enum MemoryPageProtectionState : uint
|
||||||
{
|
{
|
||||||
switch (protect)
|
Undefined = 0,
|
||||||
{
|
NoAccess = 0x0001,
|
||||||
default: return GetHexValue(protect);
|
ReadOnly = 0x0002,
|
||||||
}
|
ReadWrite = 0x0004,
|
||||||
|
WriteCopy = 0x0008,
|
||||||
|
Execute = 0x0010,
|
||||||
|
ExecuteRead = 0x0020,
|
||||||
|
ExecuteReadWrite = 0x0040,
|
||||||
|
ExecuteWriteCopy = 0x0080,
|
||||||
|
Guard = 0x0100,
|
||||||
|
NoCache = 0x0200,
|
||||||
|
WriteCombine = 0x0400,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetTypeString(uint type)
|
// --- P/Invoke Declarations ---
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case MEM_IMAGE: return "MEM_IMAGE";
|
|
||||||
case MEM_MAPPED: return "MEM_MAPPED";
|
|
||||||
case MEM_PRIVATE: return "MEM_PRIVATE";
|
|
||||||
default: return GetHexValue(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
|
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@ -65,9 +63,9 @@ namespace WebmrAPI.Services
|
|||||||
public uint AllocationProtect;
|
public uint AllocationProtect;
|
||||||
public ushort PartitionId;
|
public ushort PartitionId;
|
||||||
public UIntPtr RegionSize;
|
public UIntPtr RegionSize;
|
||||||
public uint State;
|
public MemoryState State;
|
||||||
public uint Protect;
|
public MemoryPageProtectionState PageProtection;
|
||||||
public uint Type;
|
public MemoryType Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,5 +90,162 @@ namespace WebmrAPI.Services
|
|||||||
out MEMORY_BASIC_INFORMATION lpBuffer,
|
out MEMORY_BASIC_INFORMATION lpBuffer,
|
||||||
uint dwLength
|
uint dwLength
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// --- Module-related P/Invokes (from psapi.dll and kernel32.dll) ---
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex
|
||||||
|
[DllImport("psapi.dll", SetLastError = true)]
|
||||||
|
public static extern bool EnumProcessModulesEx(
|
||||||
|
IntPtr hProcess,
|
||||||
|
[Out] IntPtr[] lphModule, // Array to receive module handles
|
||||||
|
uint cb, // Size of the lphModule array, in bytes
|
||||||
|
out uint lpcbNeeded, // Number of bytes required to store all module handles
|
||||||
|
uint dwFilterFlag // Filter for modules (e.g., LIST_MODULES_ALL)
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexw
|
||||||
|
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
public static extern uint GetModuleFileNameEx(
|
||||||
|
IntPtr hProcess,
|
||||||
|
IntPtr hModule,
|
||||||
|
[Out] System.Text.StringBuilder lpFilename,
|
||||||
|
uint nSize
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamew
|
||||||
|
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
public static extern uint GetModuleBaseName(
|
||||||
|
IntPtr hProcess,
|
||||||
|
IntPtr hModule,
|
||||||
|
[Out] System.Text.StringBuilder lpBaseName,
|
||||||
|
uint nSize
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-_moduleinfo
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct MODULEINFO
|
||||||
|
{
|
||||||
|
public IntPtr lpBaseOfDll;
|
||||||
|
public uint SizeOfImage;
|
||||||
|
public IntPtr EntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmoduleinformation
|
||||||
|
[DllImport("psapi.dll", SetLastError = true)]
|
||||||
|
public static extern bool GetModuleInformation(
|
||||||
|
IntPtr hProcess,
|
||||||
|
IntPtr hModule,
|
||||||
|
out MODULEINFO lpmodinfo,
|
||||||
|
uint cb
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- Thread-related P/Invokes (from kernel32.dll and ntdll.dll) ---
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
public static extern IntPtr OpenThread(
|
||||||
|
uint dwDesiredAccess,
|
||||||
|
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
|
||||||
|
uint dwThreadId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationthread
|
||||||
|
[DllImport("ntdll.dll", SetLastError = true)]
|
||||||
|
public static extern int NtQueryInformationThread(
|
||||||
|
IntPtr ThreadHandle,
|
||||||
|
THREAD_INFO_CLASS ThreadInformationClass,
|
||||||
|
IntPtr ThreadInformation, // Pointer to buffer
|
||||||
|
uint ThreadInformationLength,
|
||||||
|
out uint ReturnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enum for ThreadInformationClass in NtQueryInformationThread
|
||||||
|
// https://ntdoc.m417z.com/threadinfoclass
|
||||||
|
public enum THREAD_INFO_CLASS : int
|
||||||
|
{
|
||||||
|
ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION
|
||||||
|
ThreadTimes, // q: KERNEL_USER_TIMES
|
||||||
|
ThreadPriority, // s: KPRIORITY (requires SeIncreaseBasePriorityPrivilege)
|
||||||
|
ThreadBasePriority, // s: KPRIORITY
|
||||||
|
ThreadAffinityMask, // s: KAFFINITY
|
||||||
|
ThreadImpersonationToken, // s: HANDLE
|
||||||
|
ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY)
|
||||||
|
ThreadEnableAlignmentFaultFixup, // s: BOOLEAN
|
||||||
|
ThreadEventPair, // Obsolete
|
||||||
|
ThreadQuerySetWin32StartAddress, // qs: PVOID (requires THREAD_Set_LIMITED_INFORMATION)
|
||||||
|
ThreadZeroTlsCell, // s: ULONG // TlsIndex // 10
|
||||||
|
ThreadPerformanceCount, // q: LARGE_INTEGER
|
||||||
|
ThreadAmILastThread, // q: ULONG
|
||||||
|
ThreadIdealProcessor, // s: ULONG
|
||||||
|
ThreadPriorityBoost, // qs: ULONG
|
||||||
|
ThreadSetTlsArrayAddress, // s: ULONG_PTR
|
||||||
|
ThreadIsIoPending, // q: ULONG
|
||||||
|
ThreadHideFromDebugger, // q: BOOLEAN; s: void
|
||||||
|
ThreadBreakOnTermination, // qs: ULONG
|
||||||
|
ThreadSwitchLegacyState, // s: void // NtCurrentThread // NPX/FPU
|
||||||
|
ThreadIsTerminated, // q: ULONG // 20
|
||||||
|
ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION
|
||||||
|
ThreadIoPriority, // qs: IO_PRIORITY_HINT (requires SeIncreaseBasePriorityPrivilege)
|
||||||
|
ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION (requires THREAD_QUERY_LIMITED_INFORMATION)
|
||||||
|
ThreadPagePriority, // qs: PAGE_PRIORITY_INFORMATION
|
||||||
|
ThreadActualBasePriority, // s: LONG (requires SeIncreaseBasePriorityPrivilege)
|
||||||
|
ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT)
|
||||||
|
ThreadCSwitchMon, // Obsolete
|
||||||
|
ThreadCSwitchPmu, // Obsolete
|
||||||
|
ThreadWow64Context, // qs: WOW64_CONTEXT, ARM_NT_CONTEXT since 20H1
|
||||||
|
ThreadGroupInformation, // qs: GROUP_AFFINITY // 30
|
||||||
|
ThreadUmsInformation, // q: THREAD_UMS_INFORMATION // Obsolete
|
||||||
|
ThreadCounterProfiling, // q: BOOLEAN; s: THREAD_PROFILING_INFORMATION?
|
||||||
|
ThreadIdealProcessorEx, // qs: PROCESSOR_NUMBER; s: previous PROCESSOR_NUMBER on return
|
||||||
|
ThreadCpuAccountingInformation, // q: BOOLEAN; s: HANDLE (NtOpenSession) // NtCurrentThread // since WIN8
|
||||||
|
ThreadSuspendCount, // q: ULONG // since WINBLUE
|
||||||
|
ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD
|
||||||
|
ThreadContainerId, // q: GUID
|
||||||
|
ThreadNameInformation, // qs: THREAD_NAME_INFORMATION (requires THREAD_SET_LIMITED_INFORMATION)
|
||||||
|
ThreadSelectedCpuSets, // q: ULONG[]
|
||||||
|
ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40
|
||||||
|
ThreadActualGroupAffinity, // q: GROUP_AFFINITY // since THRESHOLD2
|
||||||
|
ThreadDynamicCodePolicyInfo, // q: ULONG; s: ULONG (NtCurrentThread)
|
||||||
|
ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables // (requires SeDebugPrivilege and PsProtectedSignerAntimalware)
|
||||||
|
ThreadWorkOnBehalfTicket, // ALPC_WORK_ON_BEHALF_TICKET // RTL_WORK_ON_BEHALF_TICKET_EX // NtCurrentThread
|
||||||
|
ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2
|
||||||
|
ThreadDbgkWerReportActive, // s: ULONG; s: 0 disables, otherwise enables
|
||||||
|
ThreadAttachContainer, // s: HANDLE (job object) // NtCurrentThread
|
||||||
|
ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3
|
||||||
|
ThreadPowerThrottlingState, // qs: POWER_THROTTLING_THREAD_STATE // since REDSTONE3 (set), WIN11 22H2 (query)
|
||||||
|
ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50
|
||||||
|
ThreadCreateStateChange, // since WIN11
|
||||||
|
ThreadApplyStateChange,
|
||||||
|
ThreadStrongerBadHandleChecks, // s: ULONG // NtCurrentThread // since 22H1
|
||||||
|
ThreadEffectiveIoPriority, // q: IO_PRIORITY_HINT
|
||||||
|
ThreadEffectivePagePriority, // q: ULONG
|
||||||
|
ThreadUpdateLockOwnership, // THREAD_LOCK_OWNERSHIP // since 24H2
|
||||||
|
ThreadSchedulerSharedDataSlot, // SCHEDULER_SHARED_DATA_SLOT_INFORMATION
|
||||||
|
ThreadTebInformationAtomic, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_QUERY_INFORMATION)
|
||||||
|
ThreadIndexInformation, // THREAD_INDEX_INFORMATION
|
||||||
|
MaxThreadInfoClass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structure for ThreadBasicInformation (if needed, though ThreadQuerySetWin32StartAddress directly gives address)
|
||||||
|
// https://ntdoc.m417z.com/thread_basic_information
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct THREAD_BASIC_INFORMATION
|
||||||
|
{
|
||||||
|
public int ExitStatus;
|
||||||
|
public IntPtr TebBaseAddress;
|
||||||
|
public CLIENT_ID ClientId;
|
||||||
|
public IntPtr AffinityMask;
|
||||||
|
public int Priority;
|
||||||
|
public int BasePriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://ntdoc.m417z.com/client_id
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CLIENT_ID
|
||||||
|
{
|
||||||
|
public IntPtr UniqueProcess;
|
||||||
|
public IntPtr UniqueThread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
Utils/JsonEnumConverter.cs
Normal file
54
Utils/JsonEnumConverter.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// File: Utils/JsonEnumConverter.cs
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WebmrAPI.Utils
|
||||||
|
{
|
||||||
|
public class JsonEnumConverter<T> : JsonConverter<T> where T : Enum
|
||||||
|
{
|
||||||
|
private T GetDefaultValue(Type type)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(type, "Undefined", true, out object? result) && result != null)
|
||||||
|
{
|
||||||
|
return (T)result;
|
||||||
|
}
|
||||||
|
return (T)Enum.ToObject(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.String)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(typeToConvert, reader.GetString(), true, out object? result) && result != null)
|
||||||
|
{
|
||||||
|
return (T)result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reader.TokenType == JsonTokenType.Number)
|
||||||
|
{
|
||||||
|
if (reader.TryGetInt32(out int intValue))
|
||||||
|
{
|
||||||
|
T status = (T)Enum.ToObject(typeToConvert, intValue);
|
||||||
|
if (Enum.IsDefined(typeof(T), status))
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GetDefaultValue(typeToConvert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (Enum.IsDefined(typeof(T), value))
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteStringValue("Undefined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user