first commit

This commit is contained in:
2025-07-06 00:23:46 +02:00
commit 38f50c8819
1788 changed files with 112878 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
/// <summary>
/// See:
/// <a href="https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image">MSDN</a>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct CoffFileHeader
{
/// <summary>
/// Machine type that is targeted by this image.
/// </summary>
public MachineType Machine;
public ushort NumberOfSections;
public uint TimeDateStamp;
public uint PointerToSymbolTable;
public uint NumberOfSymbols;
public ushort SizeOfOptionalHeader;
public ushort Characteristics;
}
}

View File

@@ -0,0 +1,78 @@
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential)]
public struct ImageDosHeader
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] e_magic_byte; // Magic number
/// <summary>
/// Bytes on last page of file
/// </summary>
public ushort e_cblp;
/// <summary>
/// Pages in file
/// </summary>
public ushort e_cp;
public ushort e_crlc;
/// <summary>
/// Size of header in paragraphs
/// </summary>
public ushort e_cparhdr;
public ushort e_minalloc;
public ushort e_maxalloc;
public ushort e_ss;
public ushort e_sp;
/// <summary>
/// Checksum
/// </summary>
public ushort e_csum;
/// <summary>
/// Initial IP value
/// </summary>
public ushort e_ip; //
/// <summary>
/// Initial (relative) CS value
/// </summary>
public ushort e_cs;
/// <summary>
/// File address of relocation table
/// </summary>
public ushort e_lfarlc;
/// <summary>
/// Overlay number
/// </summary>
public ushort e_ovno;
/// <summary>
/// Reserved words
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] e_res1;
public ushort e_oemid;
public ushort e_oeminfo;
/// <summary>
/// Reserved words
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public ushort[] e_res2;
/// <summary>
/// Image base offset to address of PE header.
/// </summary>
public int e_lfanew;
}
}

View File

@@ -0,0 +1,31 @@
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential)]
public struct ImageExportDirectory
{
public uint Characteristics;
public uint TimeDateStamp;
public ushort MajorVersion;
public ushort MinorVersion;
/// <summary>
/// RVA of image name.
/// </summary>
public uint Name;
public uint Base;
public uint NumberOfFunctions;
public uint NumberOfNames;
public uint AddressOfFunctions;
public uint AddressOfNames;
public uint AddressOfNameOrdinals;
public override string ToString()
{
return
$"{nameof(Characteristics)}: {Characteristics}, {nameof(TimeDateStamp)}: {TimeDateStamp}, {nameof(MajorVersion)}: {MajorVersion}, {nameof(MinorVersion)}: {MinorVersion}, {nameof(Name)}: {Name}, {nameof(Base)}: {Base}, {nameof(NumberOfFunctions)}: {NumberOfFunctions}, {nameof(NumberOfNames)}: {NumberOfNames}, {nameof(AddressOfFunctions)}: {AddressOfFunctions:X}, {nameof(AddressOfNames)}: {AddressOfNames:X}, {nameof(AddressOfNameOrdinals)}: {AddressOfNameOrdinals:X}";
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
/// <summary>
/// See: https://www.vergiliusproject.com/kernels/x64/Windows%2010%20|%202016/2009%2020H2%20(October%202020%20Update)/_IMAGE_NT_HEADERS64
/// And MSDN:
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct ImageNtHeader64
{
/// <summary>
/// Expected to be "PE" string for NT systems.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
[FieldOffset(0x0)]
public char[] Magic;
[FieldOffset(0x18)]
public OptionalHeader64 OptionalHeader;
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Explicit)]
public struct LdrData
{
[FieldOffset(0x0)]
public int Length;
[FieldOffset(0x4)]
public int Initialized;
[FieldOffset(0x8)]
public short SsHandle;
[FieldOffset(0x10)]
public IntPtr InLoadOrderModuleList;
[FieldOffset(0x20)]
public IntPtr InMemoryOrderModuleList;
[FieldOffset(0x30)]
public IntPtr InInitializationOrderModuleList;
}
}

View File

@@ -0,0 +1,21 @@
namespace NitroxModel.Platforms.OS.Windows.Internal
{
/// <summary>
/// See: <a href="https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types">MSDN</a>
/// </summary>
public enum MachineType : ushort
{
UNKNOWN = 0,
AM33 = 0x1d3,
AMD64 = 0x8664,
ARM = 0x1c0,
ARM64 = 0xaa64,
ARMNT = 0xc4,
EBC = 0xebc, // EFI byte code
I386 = 0x14c,
IA64 = 0x200,
M32R = 0x9041,
MIPS16 = 0x266,
POWER_PC = 0x1f1
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct ModuleEntry32
{
public int dwSize;
public uint th32ModuleID;
public uint th32ProcessID;
public uint GlblcntUsage;
public uint ProccntUsage;
public IntPtr modBaseAddr;
public uint modBaseSize;
public IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szExePath;
}
}

View File

@@ -0,0 +1,343 @@
namespace NitroxModel.Platforms.OS.Windows.Internal
{
public enum NtStatus : uint
{
// Success
SUCCESS = 0x00000000,
WAIT0 = 0x00000000,
WAIT1 = 0x00000001,
WAIT2 = 0x00000002,
WAIT3 = 0x00000003,
WAIT63 = 0x0000003f,
ABANDONED = 0x00000080,
ABANDONED_WAIT0 = 0x00000080,
ABANDONED_WAIT1 = 0x00000081,
ABANDONED_WAIT2 = 0x00000082,
ABANDONED_WAIT3 = 0x00000083,
ABANDONED_WAIT63 = 0x000000bf,
USER_APC = 0x000000c0,
KERNEL_APC = 0x00000100,
ALERTED = 0x00000101,
TIMEOUT = 0x00000102,
PENDING = 0x00000103,
REPARSE = 0x00000104,
MORE_ENTRIES = 0x00000105,
NOT_ALL_ASSIGNED = 0x00000106,
SOME_NOT_MAPPED = 0x00000107,
OP_LOCK_BREAK_IN_PROGRESS = 0x00000108,
VOLUME_MOUNTED = 0x00000109,
RX_ACT_COMMITTED = 0x0000010a,
NOTIFY_CLEANUP = 0x0000010b,
NOTIFY_ENUM_DIR = 0x0000010c,
NO_QUOTAS_FOR_ACCOUNT = 0x0000010d,
PRIMARY_TRANSPORT_CONNECT_FAILED = 0x0000010e,
PAGE_FAULT_TRANSITION = 0x00000110,
PAGE_FAULT_DEMAND_ZERO = 0x00000111,
PAGE_FAULT_COPY_ON_WRITE = 0x00000112,
PAGE_FAULT_GUARD_PAGE = 0x00000113,
PAGE_FAULT_PAGING_FILE = 0x00000114,
CRASH_DUMP = 0x00000116,
REPARSE_OBJECT = 0x00000118,
NOTHING_TO_TERMINATE = 0x00000122,
PROCESS_NOT_IN_JOB = 0x00000123,
PROCESS_IN_JOB = 0x00000124,
PROCESS_CLONED = 0x00000129,
FILE_LOCKED_WITH_ONLY_READERS = 0x0000012a,
FILE_LOCKED_WITH_WRITERS = 0x0000012b,
// Informational
INFORMATIONAL = 0x40000000,
OBJECT_NAME_EXISTS = 0x40000000,
THREAD_WAS_SUSPENDED = 0x40000001,
WORKING_SET_LIMIT_RANGE = 0x40000002,
IMAGE_NOT_AT_BASE = 0x40000003,
REGISTRY_RECOVERED = 0x40000009,
// Warning
WARNING = 0x80000000,
GUARD_PAGE_VIOLATION = 0x80000001,
DATATYPE_MISALIGNMENT = 0x80000002,
BREAKPOINT = 0x80000003,
SINGLE_STEP = 0x80000004,
BUFFER_OVERFLOW = 0x80000005,
NO_MORE_FILES = 0x80000006,
HANDLES_CLOSED = 0x8000000a,
PARTIAL_COPY = 0x8000000d,
DEVICE_BUSY = 0x80000011,
INVALID_EA_NAME = 0x80000013,
EA_LIST_INCONSISTENT = 0x80000014,
NO_MORE_ENTRIES = 0x8000001a,
LONG_JUMP = 0x80000026,
DLL_MIGHT_BE_INSECURE = 0x8000002b,
// Error
ERROR = 0xc0000000,
UNSUCCESSFUL = 0xc0000001,
NOT_IMPLEMENTED = 0xc0000002,
INVALID_INFO_CLASS = 0xc0000003,
INFO_LENGTH_MISMATCH = 0xc0000004,
ACCESS_VIOLATION = 0xc0000005,
IN_PAGE_ERROR = 0xc0000006,
PAGEFILE_QUOTA = 0xc0000007,
INVALID_HANDLE = 0xc0000008,
BAD_INITIAL_STACK = 0xc0000009,
BAD_INITIAL_PC = 0xc000000a,
INVALID_CID = 0xc000000b,
TIMER_NOT_CANCELED = 0xc000000c,
INVALID_PARAMETER = 0xc000000d,
NO_SUCH_DEVICE = 0xc000000e,
NO_SUCH_FILE = 0xc000000f,
INVALID_DEVICE_REQUEST = 0xc0000010,
END_OF_FILE = 0xc0000011,
WRONG_VOLUME = 0xc0000012,
NO_MEDIA_IN_DEVICE = 0xc0000013,
NO_MEMORY = 0xc0000017,
NOT_MAPPED_VIEW = 0xc0000019,
UNABLE_TO_FREE_VM = 0xc000001a,
UNABLE_TO_DELETE_SECTION = 0xc000001b,
ILLEGAL_INSTRUCTION = 0xc000001d,
ALREADY_COMMITTED = 0xc0000021,
ACCESS_DENIED = 0xc0000022,
BUFFER_TOO_SMALL = 0xc0000023,
OBJECT_TYPE_MISMATCH = 0xc0000024,
NON_CONTINUABLE_EXCEPTION = 0xc0000025,
BAD_STACK = 0xc0000028,
NOT_LOCKED = 0xc000002a,
NOT_COMMITTED = 0xc000002d,
INVALID_PARAMETER_MIX = 0xc0000030,
OBJECT_NAME_INVALID = 0xc0000033,
OBJECT_NAME_NOT_FOUND = 0xc0000034,
OBJECT_NAME_COLLISION = 0xc0000035,
OBJECT_PATH_INVALID = 0xc0000039,
OBJECT_PATH_NOT_FOUND = 0xc000003a,
OBJECT_PATH_SYNTAX_BAD = 0xc000003b,
DATA_OVERRUN = 0xc000003c,
DATA_LATE = 0xc000003d,
DATA_ERROR = 0xc000003e,
CRC_ERROR = 0xc000003f,
SECTION_TOO_BIG = 0xc0000040,
PORT_CONNECTION_REFUSED = 0xc0000041,
INVALID_PORT_HANDLE = 0xc0000042,
SHARING_VIOLATION = 0xc0000043,
QUOTA_EXCEEDED = 0xc0000044,
INVALID_PAGE_PROTECTION = 0xc0000045,
MUTANT_NOT_OWNED = 0xc0000046,
SEMAPHORE_LIMIT_EXCEEDED = 0xc0000047,
PORT_ALREADY_SET = 0xc0000048,
SECTION_NOT_IMAGE = 0xc0000049,
SUSPEND_COUNT_EXCEEDED = 0xc000004a,
THREAD_IS_TERMINATING = 0xc000004b,
BAD_WORKING_SET_LIMIT = 0xc000004c,
INCOMPATIBLE_FILE_MAP = 0xc000004d,
SECTION_PROTECTION = 0xc000004e,
EAS_NOT_SUPPORTED = 0xc000004f,
EA_TOO_LARGE = 0xc0000050,
NON_EXISTENT_EA_ENTRY = 0xc0000051,
NO_EAS_ON_FILE = 0xc0000052,
EA_CORRUPT_ERROR = 0xc0000053,
FILE_LOCK_CONFLICT = 0xc0000054,
LOCK_NOT_GRANTED = 0xc0000055,
DELETE_PENDING = 0xc0000056,
CTL_FILE_NOT_SUPPORTED = 0xc0000057,
UNKNOWN_REVISION = 0xc0000058,
REVISION_MISMATCH = 0xc0000059,
INVALID_OWNER = 0xc000005a,
INVALID_PRIMARY_GROUP = 0xc000005b,
NO_IMPERSONATION_TOKEN = 0xc000005c,
CANT_DISABLE_MANDATORY = 0xc000005d,
NO_LOGON_SERVERS = 0xc000005e,
NO_SUCH_LOGON_SESSION = 0xc000005f,
NO_SUCH_PRIVILEGE = 0xc0000060,
PRIVILEGE_NOT_HELD = 0xc0000061,
INVALID_ACCOUNT_NAME = 0xc0000062,
USER_EXISTS = 0xc0000063,
NO_SUCH_USER = 0xc0000064,
GROUP_EXISTS = 0xc0000065,
NO_SUCH_GROUP = 0xc0000066,
MEMBER_IN_GROUP = 0xc0000067,
MEMBER_NOT_IN_GROUP = 0xc0000068,
LAST_ADMIN = 0xc0000069,
WRONG_PASSWORD = 0xc000006a,
ILL_FORMED_PASSWORD = 0xc000006b,
PASSWORD_RESTRICTION = 0xc000006c,
LOGON_FAILURE = 0xc000006d,
ACCOUNT_RESTRICTION = 0xc000006e,
INVALID_LOGON_HOURS = 0xc000006f,
INVALID_WORKSTATION = 0xc0000070,
PASSWORD_EXPIRED = 0xc0000071,
ACCOUNT_DISABLED = 0xc0000072,
NONE_MAPPED = 0xc0000073,
TOO_MANY_LUIDS_REQUESTED = 0xc0000074,
LUIDS_EXHAUSTED = 0xc0000075,
INVALID_SUB_AUTHORITY = 0xc0000076,
INVALID_ACL = 0xc0000077,
INVALID_SID = 0xc0000078,
INVALID_SECURITY_DESCR = 0xc0000079,
PROCEDURE_NOT_FOUND = 0xc000007a,
INVALID_IMAGE_FORMAT = 0xc000007b,
NO_TOKEN = 0xc000007c,
BAD_INHERITANCE_ACL = 0xc000007d,
RANGE_NOT_LOCKED = 0xc000007e,
DISK_FULL = 0xc000007f,
SERVER_DISABLED = 0xc0000080,
SERVER_NOT_DISABLED = 0xc0000081,
TOO_MANY_GUIDS_REQUESTED = 0xc0000082,
GUIDS_EXHAUSTED = 0xc0000083,
INVALID_ID_AUTHORITY = 0xc0000084,
AGENTS_EXHAUSTED = 0xc0000085,
INVALID_VOLUME_LABEL = 0xc0000086,
SECTION_NOT_EXTENDED = 0xc0000087,
NOT_MAPPED_DATA = 0xc0000088,
RESOURCE_DATA_NOT_FOUND = 0xc0000089,
RESOURCE_TYPE_NOT_FOUND = 0xc000008a,
RESOURCE_NAME_NOT_FOUND = 0xc000008b,
ARRAY_BOUNDS_EXCEEDED = 0xc000008c,
FLOAT_DENORMAL_OPERAND = 0xc000008d,
FLOAT_DIVIDE_BY_ZERO = 0xc000008e,
FLOAT_INEXACT_RESULT = 0xc000008f,
FLOAT_INVALID_OPERATION = 0xc0000090,
FLOAT_OVERFLOW = 0xc0000091,
FLOAT_STACK_CHECK = 0xc0000092,
FLOAT_UNDERFLOW = 0xc0000093,
INTEGER_DIVIDE_BY_ZERO = 0xc0000094,
INTEGER_OVERFLOW = 0xc0000095,
PRIVILEGED_INSTRUCTION = 0xc0000096,
TOO_MANY_PAGING_FILES = 0xc0000097,
FILE_INVALID = 0xc0000098,
INSTANCE_NOT_AVAILABLE = 0xc00000ab,
PIPE_NOT_AVAILABLE = 0xc00000ac,
INVALID_PIPE_STATE = 0xc00000ad,
PIPE_BUSY = 0xc00000ae,
ILLEGAL_FUNCTION = 0xc00000af,
PIPE_DISCONNECTED = 0xc00000b0,
PIPE_CLOSING = 0xc00000b1,
PIPE_CONNECTED = 0xc00000b2,
PIPE_LISTENING = 0xc00000b3,
INVALID_READ_MODE = 0xc00000b4,
IO_TIMEOUT = 0xc00000b5,
FILE_FORCED_CLOSED = 0xc00000b6,
PROFILING_NOT_STARTED = 0xc00000b7,
PROFILING_NOT_STOPPED = 0xc00000b8,
NOT_SAME_DEVICE = 0xc00000d4,
FILE_RENAMED = 0xc00000d5,
CANT_WAIT = 0xc00000d8,
PIPE_EMPTY = 0xc00000d9,
CANT_TERMINATE_SELF = 0xc00000db,
INTERNAL_ERROR = 0xc00000e5,
INVALID_PARAMETER1 = 0xc00000ef,
INVALID_PARAMETER2 = 0xc00000f0,
INVALID_PARAMETER3 = 0xc00000f1,
INVALID_PARAMETER4 = 0xc00000f2,
INVALID_PARAMETER5 = 0xc00000f3,
INVALID_PARAMETER6 = 0xc00000f4,
INVALID_PARAMETER7 = 0xc00000f5,
INVALID_PARAMETER8 = 0xc00000f6,
INVALID_PARAMETER9 = 0xc00000f7,
INVALID_PARAMETER10 = 0xc00000f8,
INVALID_PARAMETER11 = 0xc00000f9,
INVALID_PARAMETER12 = 0xc00000fa,
MAPPED_FILE_SIZE_ZERO = 0xc000011e,
TOO_MANY_OPENED_FILES = 0xc000011f,
CANCELLED = 0xc0000120,
CANNOT_DELETE = 0xc0000121,
INVALID_COMPUTER_NAME = 0xc0000122,
FILE_DELETED = 0xc0000123,
SPECIAL_ACCOUNT = 0xc0000124,
SPECIAL_GROUP = 0xc0000125,
SPECIAL_USER = 0xc0000126,
MEMBERS_PRIMARY_GROUP = 0xc0000127,
FILE_CLOSED = 0xc0000128,
TOO_MANY_THREADS = 0xc0000129,
THREAD_NOT_IN_PROCESS = 0xc000012a,
TOKEN_ALREADY_IN_USE = 0xc000012b,
PAGEFILE_QUOTA_EXCEEDED = 0xc000012c,
COMMITMENT_LIMIT = 0xc000012d,
INVALID_IMAGE_LE_FORMAT = 0xc000012e,
INVALID_IMAGE_NOT_MZ = 0xc000012f,
INVALID_IMAGE_PROTECT = 0xc0000130,
INVALID_IMAGE_WIN16 = 0xc0000131,
LOGON_SERVER = 0xc0000132,
DIFFERENCE_AT_DC = 0xc0000133,
SYNCHRONIZATION_REQUIRED = 0xc0000134,
DLL_NOT_FOUND = 0xc0000135,
IO_PRIVILEGE_FAILED = 0xc0000137,
ORDINAL_NOT_FOUND = 0xc0000138,
ENTRY_POINT_NOT_FOUND = 0xc0000139,
CONTROL_C_EXIT = 0xc000013a,
PORT_NOT_SET = 0xc0000353,
DEBUGGER_INACTIVE = 0xc0000354,
CALLBACK_BYPASS = 0xc0000503,
PORT_CLOSED = 0xc0000700,
MESSAGE_LOST = 0xc0000701,
INVALID_MESSAGE = 0xc0000702,
REQUEST_CANCELED = 0xc0000703,
RECURSIVE_DISPATCH = 0xc0000704,
LPC_RECEIVE_BUFFER_EXPECTED = 0xc0000705,
LPC_INVALID_CONNECTION_USAGE = 0xc0000706,
LPC_REQUESTS_NOT_ALLOWED = 0xc0000707,
RESOURCE_IN_USE = 0xc0000708,
PROCESS_IS_PROTECTED = 0xc0000712,
VOLUME_DIRTY = 0xc0000806,
FILE_CHECKED_OUT = 0xc0000901,
CHECK_OUT_REQUIRED = 0xc0000902,
BAD_FILE_TYPE = 0xc0000903,
FILE_TOO_LARGE = 0xc0000904,
FORMS_AUTH_REQUIRED = 0xc0000905,
VIRUS_INFECTED = 0xc0000906,
VIRUS_DELETED = 0xc0000907,
TRANSACTIONAL_CONFLICT = 0xc0190001,
INVALID_TRANSACTION = 0xc0190002,
TRANSACTION_NOT_ACTIVE = 0xc0190003,
TM_INITIALIZATION_FAILED = 0xc0190004,
RM_NOT_ACTIVE = 0xc0190005,
RM_METADATA_CORRUPT = 0xc0190006,
TRANSACTION_NOT_JOINED = 0xc0190007,
DIRECTORY_NOT_RM = 0xc0190008,
COULD_NOT_RESIZE_LOG = 0xc0190009,
TRANSACTIONS_UNSUPPORTED_REMOTE = 0xc019000a,
LOG_RESIZE_INVALID_SIZE = 0xc019000b,
REMOTE_FILE_VERSION_MISMATCH = 0xc019000c,
CRM_PROTOCOL_ALREADY_EXISTS = 0xc019000f,
TRANSACTION_PROPAGATION_FAILED = 0xc0190010,
CRM_PROTOCOL_NOT_FOUND = 0xc0190011,
TRANSACTION_SUPERIOR_EXISTS = 0xc0190012,
TRANSACTION_REQUEST_NOT_VALID = 0xc0190013,
TRANSACTION_NOT_REQUESTED = 0xc0190014,
TRANSACTION_ALREADY_ABORTED = 0xc0190015,
TRANSACTION_ALREADY_COMMITTED = 0xc0190016,
TRANSACTION_INVALID_MARSHALL_BUFFER = 0xc0190017,
CURRENT_TRANSACTION_NOT_VALID = 0xc0190018,
LOG_GROWTH_FAILED = 0xc0190019,
OBJECT_NO_LONGER_EXISTS = 0xc0190021,
STREAM_MINIVERSION_NOT_FOUND = 0xc0190022,
STREAM_MINIVERSION_NOT_VALID = 0xc0190023,
MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xc0190024,
CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xc0190025,
CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xc0190026,
HANDLE_NO_LONGER_VALID = 0xc0190028,
NO_TXF_METADATA = 0xc0190029,
LOG_CORRUPTION_DETECTED = 0xc0190030,
CANT_RECOVER_WITH_HANDLE_OPEN = 0xc0190031,
RM_DISCONNECTED = 0xc0190032,
ENLISTMENT_NOT_SUPERIOR = 0xc0190033,
RECOVERY_NOT_NEEDED = 0xc0190034,
RM_ALREADY_STARTED = 0xc0190035,
FILE_IDENTITY_NOT_PERSISTENT = 0xc0190036,
CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xc0190037,
CANT_CROSS_RM_BOUNDARY = 0xc0190038,
TXF_DIR_NOT_EMPTY = 0xc0190039,
INDOUBT_TRANSACTIONS_EXIST = 0xc019003a,
TM_VOLATILE = 0xc019003b,
ROLLBACK_TIMER_EXPIRED = 0xc019003c,
TXF_ATTRIBUTE_CORRUPT = 0xc019003d,
EFS_NOT_ALLOWED_IN_TRANSACTION = 0xc019003e,
TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xc019003f,
TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xc0190040,
TXF_METADATA_ALREADY_PRESENT = 0xc0190041,
TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 0xc0190042,
TRANSACTION_REQUIRED_PROMOTION = 0xc0190043,
CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xc0190044,
TRANSACTIONS_NOT_FROZEN = 0xc0190045,
MAXIMUM_NT_STATUS = 0xffffffff
}
}

View File

@@ -0,0 +1,85 @@
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
/// <summary>
/// Structs from (copy paste url in browser to visit):
/// <a
/// href="https://www.vergiliusproject.com/kernels/x64/Windows 10 |%202016%2F2104 21H1 (May 2021 Update)/_IMAGE_OPTIONAL_HEADER64">
/// _IMAGE_OPTIONAL_HEADER64
/// </a>
/// Also see:
/// <a href="https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-image-only">MSDN: PE Header</a>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct OptionalHeader64
{
/// <summary>
/// Expected to be "PE" string for NT systems.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] Magic;
public byte MajorLinkerVersion;
public byte MinorLinkerVersion;
public uint SizeOfCode;
public uint SizeOfInitializedData;
public uint SizeOfUninitializedData;
public uint AddressOfEntryPoint;
public uint BaseOfCode;
public ulong ImageBase;
public uint SectionAlignment;
public uint FileAlignment;
public ushort MajorOperatingSystemVersion;
public ushort MinorOperatingSystemVersion;
public ushort MajorImageVersion;
public ushort MinorImageVersion;
public ushort MajorSubsystemVersion;
public ushort MinorSubsystemVersion;
public uint Win32VersionValue;
public uint SizeOfImage;
public uint SizeOfHeaders;
public uint CheckSum;
public ushort Subsystem;
public ushort DllCharacteristics;
public ulong SizeOfStackReserve;
public ulong SizeOfStackCommit;
public ulong SizeOfHeapReserve;
public ulong SizeOfHeapCommit;
public uint LoaderFlags;
public uint NumberOfRvaAndSizes;
public ImageDataDirectory ExportTable;
public ImageDataDirectory ImportTable;
public ImageDataDirectory ResourceTable;
public ImageDataDirectory ExceptionTable;
public ImageDataDirectory CertificateTable;
public ImageDataDirectory BaseRelocationTable;
public ImageDataDirectory Debug;
public ImageDataDirectory Architecture;
public ImageDataDirectory GlobalPtr;
public ImageDataDirectory TLSTable;
public ImageDataDirectory LoadConfigTable;
public ImageDataDirectory BoundImport;
public ImageDataDirectory IAT;
public ImageDataDirectory DelayImportDescriptor;
public ImageDataDirectory CLRRuntimeHeader;
public ImageDataDirectory Reserved;
public override string ToString()
{
return
$"{nameof(Magic)}: {new string(Magic)}, {nameof(MajorLinkerVersion)}: {MajorLinkerVersion}, {nameof(MinorLinkerVersion)}: {MinorLinkerVersion}, {nameof(SizeOfCode)}: {SizeOfCode}, {nameof(SizeOfInitializedData)}: {SizeOfInitializedData}, {nameof(SizeOfUninitializedData)}: {SizeOfUninitializedData}, {nameof(AddressOfEntryPoint)}: {AddressOfEntryPoint}, {nameof(BaseOfCode)}: {BaseOfCode}, {nameof(ImageBase)}: {ImageBase}, {nameof(SectionAlignment)}: {SectionAlignment}, {nameof(FileAlignment)}: {FileAlignment}, {nameof(MajorOperatingSystemVersion)}: {MajorOperatingSystemVersion}, {nameof(MinorOperatingSystemVersion)}: {MinorOperatingSystemVersion}, {nameof(MajorImageVersion)}: {MajorImageVersion}, {nameof(MinorImageVersion)}: {MinorImageVersion}, {nameof(MajorSubsystemVersion)}: {MajorSubsystemVersion}, {nameof(MinorSubsystemVersion)}: {MinorSubsystemVersion}, {nameof(Win32VersionValue)}: {Win32VersionValue}, {nameof(SizeOfImage)}: {SizeOfImage}, {nameof(SizeOfHeaders)}: {SizeOfHeaders}, {nameof(CheckSum)}: {CheckSum}, {nameof(Subsystem)}: {Subsystem}, {nameof(DllCharacteristics)}: {DllCharacteristics}, {nameof(SizeOfStackReserve)}: {SizeOfStackReserve}, {nameof(SizeOfStackCommit)}: {SizeOfStackCommit}, {nameof(SizeOfHeapReserve)}: {SizeOfHeapReserve}, {nameof(SizeOfHeapCommit)}: {SizeOfHeapCommit}, {nameof(LoaderFlags)}: {LoaderFlags}, {nameof(NumberOfRvaAndSizes)}: {NumberOfRvaAndSizes}";
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ImageDataDirectory
{
/// <summary>
/// Location of the data in this directory. Add this value to the base address of the image to get the real address.
/// </summary>
public uint VirtualAddress;
public uint Size;
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[Flags]
public enum ProcessAccessFlags : uint
{
ALL = 0x001F0FFF,
TERMINATE = 0x00000001,
CREATE_THREAD = 0x00000002,
VIRTUAL_MEMORY_OPERATION = 0x00000008,
VIRTUAL_MEMORY_READ = 0x00000010,
VIRTUAL_MEMORY_WRITE = 0x00000020,
DUPLICATE_HANDLE = 0x00000040,
CREATE_PROCESS = 0x000000080,
SET_QUOTA = 0x00000100,
SET_INFORMATION = 0x00000200,
QUERY_INFORMATION = 0x00000400,
QUERY_LIMITED_INFORMATION = 0x00001000,
SYNCHRONIZE = 0x00100000
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct ProcessBasicInformation
{
public NtStatus ExitStatus;
public IntPtr PebBaseAddress;
public UIntPtr AffinityMask;
public int BasePriority;
public UIntPtr UniqueProcessId;
public UIntPtr InheritedFromUniqueProcessId;
}
}

View File

@@ -0,0 +1,26 @@
using System;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[Flags]
public enum ProcessCreationFlags : uint
{
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NO_WINDOW = 0x08000000,
CREATE_PROTECTED_PROCESS = 0x00040000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_SECURE_PROCESS = 0x00400000,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_SUSPENDED = 0x00000004,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
DEBUG_PROCESS = 0x00000001,
DETACHED_PROCESS = 0x00000008,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
INHERIT_PARENT_AFFINITY = 0x00010000
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
/// <summary>
/// PEB structure in a used by Windows in 64-bit processes.
/// See full structure here:
/// https://ntopcode.wordpress.com/2018/02/26/anatomy-of-the-process-environment-block-peb-windows-internals/
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct ProcessEnvironmentBlock64
{
[FieldOffset(0x0)]
public byte Reserved1;
[FieldOffset(0x1)]
public byte Reserved2;
[FieldOffset(0x2)]
public byte BeingDebugged;
[FieldOffset(0x3)]
public byte Reserved3;
[FieldOffset(0x10)]
public IntPtr ImageBaseAddress;
/// <summary>
/// Ptr to structure <see cref="Windows.Internal.LdrData" />.
/// </summary>
[FieldOffset(0x18)]
public IntPtr LdrData;
[FieldOffset(0x20)]
public IntPtr ProcessParameters;
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct ProcessInfo
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 ProcessId;
public Int32 ThreadId;
}
}

View File

@@ -0,0 +1,14 @@
using System;
public enum PtraceRequest : int
{
PTRACE_ATTACH = 16,
PTRACE_DETACH = 17,
PTRACE_POKEDATA = 5
}
[Flags]
public enum ThreadAccess : int
{
SUSPEND_RESUME = 0x0002
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SecurityAttributes
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[Flags]
public enum SnapshotFlags : uint
{
HEAP_LIST = 0x00000001,
PROCESS = 0x00000002,
THREAD = 0x00000004,
MODULE = 0x00000008,
MODULE32 = 0x00000010,
INHERIT = 0x80000000,
ALL = 0x0000001F,
NO_HEAPS = 0x40000000
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Runtime.InteropServices;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct StartupInfo
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
}

View File

@@ -0,0 +1,18 @@
using System;
namespace NitroxModel.Platforms.OS.Windows.Internal
{
[Flags]
public enum ThreadAccess
{
TERMINATE = 0x0001,
SUSPEND_RESUME = 0x0002,
GET_CONTEXT = 0x0008,
SET_CONTEXT = 0x0010,
SET_INFORMATION = 0x0020,
QUERY_INFORMATION = 0x0040,
SET_THREAD_TOKEN = 0x0080,
IMPERSONATE = 0x0100,
DIRECT_IMPERSONATION = 0x0200
}
}

View File

@@ -0,0 +1,494 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace NitroxModel.Platforms.OS.Windows.Internal;
internal static class Win32Native
{
[Flags]
public enum AssocF : uint
{
None = 0,
Init_NoRemapCLSID = 0x1,
Init_ByExeName = 0x2,
Open_ByExeName = 0x2,
Init_DefaultToStar = 0x4,
Init_DefaultToFolder = 0x8,
NoUserSettings = 0x10,
NoTruncate = 0x20,
Verify = 0x40,
RemapRunDll = 0x80,
NoFixUps = 0x100,
IgnoreBaseClass = 0x200,
Init_IgnoreUnknown = 0x400,
Init_FixedProgId = 0x800,
IsProtocol = 0x1000,
InitForFile = 0x2000
}
public enum AssocStr
{
Command = 1,
Executable,
FriendlyDocName,
FriendlyAppName,
NoOpen,
ShellNewValue,
DDECommand,
DDEIfExec,
DDEApplication,
DDETopic,
InfoTip,
QuickTip,
TileInfo,
ContentType,
DefaultIcon,
ShellExtension,
DropTarget,
DelegateExecute,
SupportedUriProtocols,
// The values below ('Max' excluded) have been introduced in W10 1511
ProgID,
AppID,
AppPublisher,
AppIconReference,
Max
}
/// <summary>
/// Gets the associated program for the file extension.
/// </summary>
/// <param name="str"></param>
/// <param name="extension"></param>
/// <returns></returns>
public static string AssocQueryString(AssocStr str, string extension)
{
const int S_OK = 0;
const int S_FALSE = 1;
uint length = 0;
uint ret = AssocQueryString(AssocF.None, str, extension, null, null, ref length);
if (ret != S_FALSE)
{
return null;
}
StringBuilder sb = new((int)length);
ret = AssocQueryString(AssocF.None, str, extension, null, sb, ref length);
if (ret != S_OK)
{
return null;
}
return sb.ToString();
}
[DllImport("kernel32.dll", SetLastError = true)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
/// <summary>
/// If true, kills the debugged process when debugger detaches.
/// </summary>
/// <param name="killOnExit"></param>
[DllImport("kernel32.dll")]
public static extern void DebugSetProcessKillOnExit(bool killOnExit);
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWow64Process(
[In] SafeHandle hProcess,
[Out] [MarshalAs(UnmanagedType.Bool)] out bool wow64Process
);
public static string QueryFullProcessImageName(SafeHandle process, uint flags = 0)
{
try
{
StringBuilder fileNameBuilder = new(1024);
int size = fileNameBuilder.Capacity;
return QueryFullProcessImageName(process, flags, fileNameBuilder, ref size) ? fileNameBuilder.ToString() : null;
}
catch (Exception)
{
return null;
}
}
[DllImport("kernel32.dll")]
public static extern bool TerminateProcess(SafeHandle hProcess, int exitCode);
[DllImport("kernel32.dll")]
public static extern uint SuspendThread(SafeHandle hThread);
[DllImport("kernel32.dll")]
public static extern uint ResumeThread(SafeHandle hThread);
[DllImport("ntdll.dll", PreserveSig = false)]
public static extern void NtSuspendProcess(SafeHandle processHandle);
[DllImport("ntdll.dll", PreserveSig = false, SetLastError = true)]
public static extern void NtResumeProcess(SafeHandle processHandle);
[DllImport("kernel32.dll")]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
ProcessCreationFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref StartupInfo lpStartupInfo,
out ProcessInfo lpProcessInformation
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeProcessHandle OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(
SafeHandle hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(SafeHandle hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten);
[DllImport("ntdll.dll")]
public static extern NtStatus NtQueryInformationProcess(SafeHandle processHandle, int processInformationClass, ref ProcessBasicInformation processInformation, int processInformationLength, IntPtr returnLength);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateRemoteThread(
SafeHandle hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId);
[DllImport("kernel32.dll")]
internal static extern bool FlushInstructionCache(SafeHandle hProcess, IntPtr lpBaseAddress, uint dwSize);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern SafeAccessTokenHandle OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern uint AssocQueryString(AssocF flags, AssocStr str, string extension, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut);
[DllImport("kernel32.dll")]
private static extern bool QueryFullProcessImageName([In] SafeHandle hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In] [Out] ref int lpdwSize);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool QueryFullProcessImageName([In] SafeHandle hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
[DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)]
private static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData);
public static bool IsTrusted(string fileName)
{
return WinVerifyTrust(fileName) == 0;
}
private static uint WinVerifyTrust(string fileName)
{
Guid wintrust_action_generic_verify_v2 = new("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
uint result = 0;
using (WINTRUST_FILE_INFO fileInfo = new(fileName,
Guid.Empty))
using (UnmanagedPointer guidPtr = new(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))),
AllocMethod.HGlobal))
using (UnmanagedPointer wvtDataPtr = new(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))),
AllocMethod.HGlobal))
{
WINTRUST_DATA data = new(fileInfo);
IntPtr pGuid = guidPtr;
IntPtr pData = wvtDataPtr;
Marshal.StructureToPtr(wintrust_action_generic_verify_v2,
pGuid,
true);
Marshal.StructureToPtr(data,
pData,
true);
result = WinVerifyTrust(IntPtr.Zero,
pGuid,
pData);
}
return result;
}
internal struct WINTRUST_FILE_INFO : IDisposable
{
public WINTRUST_FILE_INFO(string fileName, Guid subject)
{
cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));
pcwszFilePath = fileName;
if (subject != Guid.Empty)
{
pgKnownSubject = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
Marshal.StructureToPtr(subject, pgKnownSubject, true);
}
else
{
pgKnownSubject = IntPtr.Zero;
}
hFile = IntPtr.Zero;
}
public uint cbStruct;
[MarshalAs(UnmanagedType.LPTStr)] public string pcwszFilePath;
public IntPtr hFile;
public IntPtr pgKnownSubject;
public void Dispose() => Dispose(true);
private void Dispose(bool disposing)
{
if (pgKnownSubject != IntPtr.Zero)
{
Marshal.DestroyStructure(pgKnownSubject, typeof(Guid));
Marshal.FreeHGlobal(pgKnownSubject);
}
}
}
private enum AllocMethod
{
HGlobal,
CoTaskMem
}
private enum UnionChoice
{
File = 1,
Catalog,
Blob,
Signer,
Cert
}
private enum UiChoice
{
All = 1,
NoUI,
NoBad,
NoGood
}
private enum RevocationCheckFlags
{
None = 0,
WholeChain
}
private enum StateAction
{
Ignore = 0,
Verify,
Close,
AutoCache,
AutoCacheFlush
}
private enum TrustProviderFlags
{
UseIE4Trust = 1,
NoIE4Chain = 2,
NoPolicyUsage = 4,
RevocationCheckNone = 16,
RevocationCheckEndCert = 32,
RevocationCheckChain = 64,
RecovationCheckChainExcludeRoot = 128,
Safer = 256,
HashOnly = 512,
UseDefaultOSVerCheck = 1024,
LifetimeSigning = 2048
}
private enum UIContext
{
Execute = 0,
Install
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
internal static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
internal static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, long dwNewLong);
[Flags]
public enum WS : long
{
WS_BORDER = 0x00800000L,
WS_CAPTION = 0x00C00000L,
WS_CHILD = 0x40000000L,
WS_CHILDWINDOW = 0x40000000L,
WS_CLIPCHILDREN = 0x02000000L,
WS_CLIPSIBLINGS = 0x04000000L,
WS_DISABLED = 0x08000000L,
WS_DLGFRAME = 0x00400000L,
WS_GROUP = 0x00020000L,
WS_HSCROLL = 0x00100000L,
WS_ICONIC = 0x20000000L,
WS_MAXIMIZE = 0x01000000L,
WS_MAXIMIZEBOX = 0x00010000L,
WS_MINIMIZE = 0x20000000L,
WS_MINIMIZEBOX = 0x00020000L,
WS_OVERLAPPED = 0x00000000L,
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
WS_POPUP = 0x80000000L,
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
WS_SIZEBOX = 0x00040000L,
WS_SYSMENU = 0x00080000L,
WS_TABSTOP = 0x00010000L,
WS_THICKFRAME = 0x00040000L,
WS_TILED = 0x00000000L,
WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
WS_VISIBLE = 0x10000000L,
WS_VSCROLL = 0x00200000L
}
[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_DATA : IDisposable
{
public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo)
{
cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA));
pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)));
Marshal.StructureToPtr(fileInfo, pInfoStruct, false);
dwUnionChoice = UnionChoice.File;
pPolicyCallbackData = IntPtr.Zero;
pSIPCallbackData = IntPtr.Zero;
dwUIChoice = UiChoice.NoUI;
fdwRevocationChecks = RevocationCheckFlags.None;
dwStateAction = StateAction.Ignore;
hWVTStateData = IntPtr.Zero;
pwszURLReference = IntPtr.Zero;
dwProvFlags = TrustProviderFlags.Safer;
dwUIContext = UIContext.Execute;
}
public uint cbStruct;
public IntPtr pPolicyCallbackData;
public IntPtr pSIPCallbackData;
public UiChoice dwUIChoice;
public RevocationCheckFlags fdwRevocationChecks;
public UnionChoice dwUnionChoice;
public IntPtr pInfoStruct;
public StateAction dwStateAction;
public IntPtr hWVTStateData;
private readonly IntPtr pwszURLReference;
public TrustProviderFlags dwProvFlags;
public UIContext dwUIContext;
public void Dispose() => Dispose(true);
private void Dispose(bool disposing)
{
if (dwUnionChoice == UnionChoice.File)
{
WINTRUST_FILE_INFO info = new();
Marshal.PtrToStructure(pInfoStruct, info);
info.Dispose();
Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO));
}
Marshal.FreeHGlobal(pInfoStruct);
}
}
private sealed class UnmanagedPointer : IDisposable
{
private readonly AllocMethod m_meth;
private IntPtr m_ptr;
public UnmanagedPointer(IntPtr ptr, AllocMethod method)
{
m_meth = method;
m_ptr = ptr;
}
public static implicit operator IntPtr(UnmanagedPointer ptr) => ptr.m_ptr;
~UnmanagedPointer()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
if (m_ptr != IntPtr.Zero)
{
if (m_meth == AllocMethod.HGlobal)
{
Marshal.FreeHGlobal(m_ptr);
}
else if (m_meth == AllocMethod.CoTaskMem)
{
Marshal.FreeCoTaskMem(m_ptr);
}
m_ptr = IntPtr.Zero;
}
if (disposing)
{
GC.SuppressFinalize(this);
}
}
public void Dispose() => Dispose(true);
}
}

View File

@@ -0,0 +1,268 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace NitroxModel.Platforms.OS.Windows;
#if NET5_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public static class RegistryEx
{
/// <summary>
/// Reads the value of the registry key or returns the default value of <see cref="T" />.
/// </summary>
/// <param name="pathWithValue">
/// Full path to the registry key. If the registry hive is omitted then "current user" is used.
/// </param>
/// <param name="defaultValue">The default value if the registry key is not found or failed to convert to <see cref="T" />.</param>
/// <typeparam name="T">Type of value to read. If the value in the registry key does not match it will try to convert.</typeparam>
/// <returns>Value as read from registry or null if not found.</returns>
public static T Read<T>(string pathWithValue, T defaultValue = default)
{
(RegistryKey baseKey, string valueKey) = GetKey(pathWithValue, false);
if (baseKey == null)
{
return defaultValue;
}
try
{
object value = baseKey.GetValue(valueKey);
if (value == null)
{
return defaultValue;
}
Type typeOfT = typeof(T);
return value.GetType() == typeOfT ? (T)value : (T)TypeDescriptor.GetConverter(typeOfT).ConvertFrom(value);
}
catch (Exception)
{
return defaultValue;
}
finally
{
baseKey.Dispose();
}
}
/// <summary>
/// Deletes the whole subtree or value, whichever exists.
/// </summary>
/// <param name="pathWithOptionalValue">If no value name is given it will delete the key instead.</param>
/// <returns>True if something was deleted.</returns>
public static bool Delete(string pathWithOptionalValue)
{
(RegistryKey key, string valueKey) = GetKey(pathWithOptionalValue);
if (key == null)
{
return false;
}
// Try to delete the key.
RegistryKey prev = key;
key = key.OpenSubKey(valueKey);
if (key != null)
{
key.DeleteSubKeyTree(valueKey);
key.Dispose();
prev.Dispose();
return true;
}
key = prev; // Restore state for next step
// Not a key, delete the value if it exists.
if (key.GetValue(valueKey) != null)
{
key.DeleteValue(valueKey);
key.Dispose();
return true;
}
// Nothing to delete.
return false;
}
public static void Write<T>(string pathWithKey, T value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
(RegistryKey baseKey, string valueKey) = GetKey(pathWithKey, true, true);
if (baseKey == null)
{
return;
}
// Figure out what kind of value to store.
RegistryValueKind? kind = value switch
{
int => RegistryValueKind.DWord,
long => RegistryValueKind.QWord,
byte[] => RegistryValueKind.Binary,
string => RegistryValueKind.String,
_ => null
};
// If regKey already exists, and we don't know how to parse the value, use existing kind.
if (!kind.HasValue)
{
try
{
kind = baseKey.GetValueKind(valueKey);
}
catch (Exception)
{
// ignored - thrown when key does not exist.
}
}
try
{
baseKey.SetValue(valueKey, value, kind.GetValueOrDefault(RegistryValueKind.String));
}
finally
{
baseKey.Dispose();
}
}
/// <summary>
/// Checks if a key exists.
/// </summary>
public static bool Exists(string pathWithValue)
{
(RegistryKey baseKey, string valueKey) = GetKey(pathWithValue, false);
if (baseKey == null)
{
return false;
}
try
{
return baseKey.GetValue(valueKey) != null;
}
finally
{
baseKey.Dispose();
}
}
/// <summary>
/// Waits for a registry value to have the given value.
/// </summary>
public static async Task CompareWaitAsync<T>(string pathWithKey, Func<T, bool> predicate, CancellationToken token)
{
CancellationTokenSource innerCts = null;
if (token == default)
{
innerCts = new(TimeSpan.FromSeconds(10));
token = innerCts.Token;
}
RegistryKey baseKey = null;
try
{
// Test once before in-case it is already successful.
(baseKey, string valueKey) = GetKey(pathWithKey, false);
if (Test(baseKey, valueKey, predicate))
{
return;
}
// Wait for predicate to be successful.
while (true)
{
token.ThrowIfCancellationRequested();
// If regkey didn't exist yet it might later.
if (baseKey == null)
{
(baseKey, valueKey) = GetKey(pathWithKey, false);
}
if (Test(baseKey, valueKey, predicate))
{
break;
}
await Task.Delay(100, token);
}
}
finally
{
baseKey?.Dispose();
innerCts?.Dispose();
}
static bool Test(RegistryKey regKey, string regKeyName, Func<T, bool> testPredicate)
{
T preTestVal = regKey?.GetValue(regKeyName) is T typedValue ? typedValue : default;
return testPredicate(preTestVal);
}
}
public static Task CompareWaitAsync<T>(string pathWithKey, Func<T, bool> predicate, TimeSpan timeout = default)
{
CancellationTokenSource source = new(timeout == default ? TimeSpan.FromSeconds(10) : timeout);
return CompareWaitAsync(pathWithKey, predicate, source.Token);
}
private static (RegistryKey baseKey, string valueKey) GetKey(string path, bool needsWriteAccess = true, bool createIfNotExists = false)
{
if (string.IsNullOrWhiteSpace(path))
{
return (null, null);
}
path = path.Trim();
// Parse path to get the registry key instance.
Span<string> parts = path.Split(Path.DirectorySeparatorChar);
Span<string> partsWithoutHive;
RegistryHive hive = RegistryHive.CurrentUser;
string regPathWithoutHiveOrKey;
if (!parts[0].Equals("Computer", StringComparison.OrdinalIgnoreCase))
{
partsWithoutHive = parts[..^1];
regPathWithoutHiveOrKey = string.Join(Path.DirectorySeparatorChar.ToString(), partsWithoutHive.ToArray());
}
else
{
partsWithoutHive = parts[2..^1];
regPathWithoutHiveOrKey = string.Join(Path.DirectorySeparatorChar.ToString(), partsWithoutHive.ToArray());
hive = parts[1].ToLower() switch
{
"hkey_classes_root" => RegistryHive.ClassesRoot,
"hkey_local_machine" => RegistryHive.LocalMachine,
"hkey_current_user" => RegistryHive.CurrentUser,
"hkey_users" => RegistryHive.Users,
"hkey_current_config" => RegistryHive.CurrentConfig,
_ => throw new ArgumentException($"Path must contain a valid registry hive but was given '{parts[1]}'", nameof(path))
};
}
RegistryKey hiveRef = RegistryKey.OpenBaseKey(hive, RegistryView.Registry64);
RegistryKey key = hiveRef.OpenSubKey(regPathWithoutHiveOrKey, needsWriteAccess);
// Should the key (and its path leading to it) be created?
if (key == null && createIfNotExists)
{
key = hiveRef;
foreach (string part in partsWithoutHive)
{
RegistryKey prev = key;
try
{
key = key?.OpenSubKey(part, needsWriteAccess) ?? key?.CreateSubKey(part, needsWriteAccess);
}
finally
{
// Cleanup old/parent key reference
prev?.Dispose();
}
}
}
return (key, parts[^1]);
}
}

View File

@@ -0,0 +1,31 @@
using System;
using NitroxModel.Helper;
namespace NitroxModel.Platforms.OS.Windows;
#if NET5_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public class RegistryKeyValueStore : IKeyValueStore
{
public static string KeyToRegistryPath(string key) => @$"SOFTWARE\Nitrox\{key}";
public T GetValue<T>(string key, T defaultValue) => RegistryEx.Read(KeyToRegistryPath(key), defaultValue);
public bool SetValue<T>(string key, T value)
{
try
{
RegistryEx.Write(KeyToRegistryPath(key), value);
return true;
}
catch (Exception)
{
return false;
}
}
public bool DeleteKey(string key) => RegistryEx.Delete(KeyToRegistryPath(key));
public bool KeyExists(string key) => RegistryEx.Exists(KeyToRegistryPath(key));
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.Win32;
using NitroxModel.Platforms.OS.Shared;
using NitroxModel.Platforms.OS.Windows.Internal;
namespace NitroxModel.Platforms.OS.Windows;
#if NET5_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
internal class WinFileSystem : FileSystem
{
public override IEnumerable<string> ExecutableFileExtensions { get; } = ["exe", "cmd", "bat"];
public override string TextEditor => GetFullPath("notepad.exe");
public override IEnumerable<string> GetDefaultPrograms(string file)
{
string SearchExecutableInSameDirectory(string path)
{
if (Path.GetExtension(path) != "")
{
return path;
}
foreach (string ext in ExecutableFileExtensions)
{
string newPath = Path.ChangeExtension(path, ext);
if (File.Exists(newPath))
{
return newPath;
}
}
return path;
}
string extension = Path.GetExtension(file);
if (string.IsNullOrWhiteSpace(extension))
{
yield break;
}
string defaultProgramOnDblClick = Win32Native.AssocQueryString(Win32Native.AssocStr.Executable, extension);
if (!string.IsNullOrWhiteSpace(defaultProgramOnDblClick) && File.Exists(defaultProgramOnDblClick))
{
yield return Path.GetFullPath(defaultProgramOnDblClick);
}
string baseKey = $@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{extension}";
using RegistryKey rk = Registry.CurrentUser.OpenSubKey($@"{baseKey}\OpenWithList");
if (rk?.GetValue("MRUList") is not string mruList)
{
yield break;
}
foreach (char c in mruList)
{
string fullPath = SearchExecutableInSameDirectory(GetFullPath(rk.GetValue(c.ToString()).ToString()));
if (fullPath == null)
{
continue;
}
yield return fullPath;
}
}
/// <summary>
/// Adds full access flag to the directory (and sub files/directories) for the current user.
/// </summary>
/// <param name="directory"></param>
/// <returns>True if set, false if program is not allowed to change permissions.</returns>
public override bool SetFullAccessToCurrentUser(string directory)
{
try
{
string identity = WindowsIdentity.GetCurrent().Name;
DirectoryInfo dir = new(directory);
DirectorySecurity flags = dir.GetAccessControl();
flags.AddAccessRule(new(identity, FileSystemRights.FullControl, InheritanceFlags.None, PropagationFlags.InheritOnly, AccessControlType.Allow));
flags.AddAccessRule(new (identity, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
flags.AddAccessRule(new (identity, FileSystemRights.FullControl, InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
dir.SetAccessControl(flags);
return true;
}
catch (UnauthorizedAccessException)
{
return false;
}
}
public override bool IsTrustedFile(string file) => Win32Native.IsTrusted(file);
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Runtime.InteropServices;
using static NitroxModel.Platforms.OS.Windows.Internal.Win32Native;
namespace NitroxModel.Platforms.OS.Windows;
public class WindowsApi
{
/// <summary>
/// Applies default OS animations to the window handle.
/// </summary>
/// <remarks>
/// Note on Windows OS: it will force enable resizing of a Window if <see cref="canResize"/> is true. Make sure to set it correctly.
/// </remarks>
public static void EnableDefaultWindowAnimations(nint windowHandle, bool canResize)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
WS dwNewLong = WS.WS_CAPTION | WS.WS_CLIPCHILDREN | WS.WS_MINIMIZEBOX | WS.WS_MAXIMIZEBOX | WS.WS_SYSMENU;
if (canResize)
{
dwNewLong |= WS.WS_SIZEBOX;
}
HandleRef handle = new(null, windowHandle);
switch (IntPtr.Size)
{
case 8:
SetWindowLongPtr64(handle, -16, (long)dwNewLong);
break;
default:
SetWindowLong32(handle, -16, (int)dwNewLong);
break;
}
}
public static void BringProcessToFront(IntPtr windowHandle)
{
if (windowHandle == IntPtr.Zero)
{
return;
}
const int SW_RESTORE = 9;
if (IsIconic(windowHandle))
{
ShowWindow(windowHandle, SW_RESTORE);
}
SetForegroundWindow(windowHandle);
}
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
[DllImport("User32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}