diff --git a/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs b/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs
index 276bd7267..4e9bf04b9 100644
--- a/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs
+++ b/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs
@@ -1,6 +1,8 @@
-using System.Diagnostics;
+using STROOP.Win32;
+using System.Diagnostics;
using System.Runtime.InteropServices;
-using static STROOP.Core.Kernal32NativeMethods;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.ProcessStatus;
namespace STROOP.Core.GameMemoryAccess;
@@ -13,14 +15,13 @@ public DolphinProcessIO(Process process, Emulator emulator)
protected override void CalculateOffset()
{
- MemoryBasicInformation info;
- IntPtr infoSize = (IntPtr)Marshal.SizeOf(typeof(MemoryBasicInformation));
- uint setInfoSize = (uint)Marshal.SizeOf(typeof(PsapiWorkingSetExInformation));
+ VirtualQueryEx.MemoryBasicInformation info;
+ IntPtr infoSize = (IntPtr)Marshal.SizeOf(typeof(VirtualQueryEx.MemoryBasicInformation));
_baseOffset = (UIntPtr)0;
bool mem1Found = false;
for (IntPtr p = new IntPtr();
- VQueryEx(_processHandle, p, out info, infoSize) == infoSize;
+ VirtualQueryEx.Invoke(_processHandle, p, out info, infoSize) == infoSize;
p = (IntPtr)(p.ToInt64() + info.RegionSize.ToInt64()))
{
if (mem1Found)
@@ -37,17 +38,15 @@ protected override void CalculateOffset()
continue;
}
- if (info.RegionSize == (IntPtr)0x2000000 && info.Type == MemoryType.MEM_MAPPED)
+ if (info.RegionSize == (IntPtr)0x2000000 && info.Type == VirtualQueryEx.MemoryType.MEM_MAPPED)
{
// Here, it's likely the right page, but it can happen that multiple pages with these criteria
// exists and have nothing to do with the emulated memory. Only the right page has valid
// working set information so an additional check is required that it is backed by physical
// memory.
- PsapiWorkingSetExInformation wsInfo;
- wsInfo.VirtualAddress = (IntPtr)info.BaseAddress.ToUInt64();
- if (QWorkingSetEx(_processHandle, out wsInfo, setInfoSize))
+ if (NativeMethodWrappers.QueryWorkingSetEx((HANDLE)_processHandle, info.BaseAddress, out PSAPI_WORKING_SET_EX_INFORMATION wsInfo))
{
- if ((wsInfo.VirtualAttributes & 0x01) != 0)
+ if ((wsInfo.VirtualAttributes.Flags & 0x01) != 0)
{
_baseOffset = info.BaseAddress;
mem1Found = true;
diff --git a/STROOP.Core/GameMemoryAccess/SigScanSharp.cs b/STROOP.Core/GameMemoryAccess/SigScanSharp.cs
index 0db9d8aa0..7c8425176 100644
--- a/STROOP.Core/GameMemoryAccess/SigScanSharp.cs
+++ b/STROOP.Core/GameMemoryAccess/SigScanSharp.cs
@@ -25,7 +25,7 @@
*/
using System.Diagnostics;
-using System.Runtime.InteropServices;
+using STROOP.Win32;
namespace STROOP.Core.GameMemoryAccess;
@@ -52,7 +52,7 @@ public bool SelectModule(ProcessModule targetModule)
g_dictStringPatterns.Clear();
try
{
- return Win32.ReadProcessMemory(g_hProcess, g_lpModuleBase, g_arrModuleBuffer, (IntPtr)targetModule.ModuleMemorySize);
+ return NativeMethodWrappers.ReadProcessMemory(g_hProcess, (UIntPtr)g_lpModuleBase, g_arrModuleBuffer);
}
catch (AccessViolationException)
{
@@ -112,10 +112,4 @@ private byte[] ParsePatternString(string szPattern)
return patternbytes.ToArray();
}
-
- private static class Win32
- {
- [DllImport("kernel32.dll")]
- public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead = default(IntPtr));
- }
}
diff --git a/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs b/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs
index 914437a72..f0271e1c6 100644
--- a/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs
+++ b/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs
@@ -1,6 +1,10 @@
-using System.ComponentModel;
+using STROOP.Win32;
+using System.ComponentModel;
using System.Diagnostics;
-using static STROOP.Core.Kernal32NativeMethods;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.Threading;
+using static STROOP.Core.ProcessHelper;
namespace STROOP.Core.GameMemoryAccess;
@@ -29,16 +33,20 @@ public WindowsProcessRamIO(Process process, Emulator emulator) : base()
_process.EnableRaisingEvents = true;
- ProcessAccess accessFlags = ProcessAccess.PROCESS_QUERY_LIMITED_INFORMATION | ProcessAccess.SUSPEND_RESUME
- | ProcessAccess.VM_OPERATION | ProcessAccess.VM_READ | ProcessAccess.VM_WRITE;
- _processHandle = ProcessGetHandleFromId(accessFlags, false, _process.Id);
+ var accessFlags = PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION
+ | PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME
+ | PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION
+ | PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ
+ | PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE;
+
+ _processHandle = PInvoke.OpenProcess(accessFlags, false, (uint)_process.Id);
try
{
CalculateOffset();
}
catch (Exception e)
{
- CloseProcess(_processHandle);
+ PInvoke.CloseHandle((HANDLE)_processHandle);
throw;
}
@@ -52,16 +60,10 @@ private void _process_Exited(object sender, EventArgs e)
}
protected override bool ReadFunc(UIntPtr address, byte[] buffer)
- {
- int numOfBytes = 0;
- return ProcessReadMemory(_processHandle, address, buffer, (IntPtr)buffer.Length, ref numOfBytes);
- }
+ => NativeMethodWrappers.ReadProcessMemory(_processHandle, address, buffer);
protected override bool WriteFunc(UIntPtr address, byte[] buffer)
- {
- int numOfBytes = 0;
- return ProcessWriteMemory(_processHandle, address, buffer, (IntPtr)buffer.Length, ref numOfBytes);
- }
+ => NativeMethodWrappers.WriteProcessMemory(_processHandle, address, buffer);
public override byte[] ReadAllMemory()
{
@@ -71,8 +73,8 @@ public override byte[] ReadAllMemory()
for (uint address = 0; true; address++)
{
- bool success = ProcessReadMemory(_processHandle, (UIntPtr)address, buffer, (IntPtr)buffer.Length, ref numBytes);
- if (!success) break;
+ if (!NativeMethodWrappers.ReadProcessMemory(_processHandle, address, buffer))
+ break;
output.Add(buffer[0]);
}
@@ -91,30 +93,29 @@ private bool CompareBytes(byte[] a, byte[] b)
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx
public static bool Is64Bit(Process process)
=> Environment.Is64BitOperatingSystem
- && IsWow64Process(process.Handle, out bool isWow64)
+ && PInvoke.IsWow64Process(process.SafeHandle, out var isWow64)
? !isWow64
: throw new Win32Exception();
protected virtual void CalculateOffset()
{
// Find CORE_RDRAM export from mupen if present
- Win32SymbolInfo symbol = Win32SymbolInfo.Create();
- if (SymInitialize(_process.Handle, null, true))
+ if (PInvoke.SymInitialize(_process.SafeHandle, null, true))
{
try
{
- if (SymFromName(_process.Handle, "CORE_RDRAM", ref symbol))
+ if (NativeMethodWrappers.GetSymbolAddress(_process.SafeHandle, "CORE_RDRAM", out var address))
{
bool is64Bit = Is64Bit(_process);
byte[]? buffer = new byte[is64Bit ? 8 : 4];
- ReadAbsolute((UIntPtr)symbol.Address, buffer, EndiannessType.Little);
+ ReadAbsolute((UIntPtr)address, buffer, EndiannessType.Little);
_baseOffset = (UIntPtr)(is64Bit ? BitConverter.ToUInt64(buffer, 0) : (ulong)BitConverter.ToUInt32(buffer, 0));
return;
}
}
finally
{
- if (!SymCleanup(_process.Handle))
+ if (!PInvoke.SymCleanup(_process.SafeHandle))
throw new Win32Exception();
}
}
@@ -122,7 +123,7 @@ protected virtual void CalculateOffset()
{
// documentation doesn't say what to do when SymInitialize returns false, so just call this and don't care for its result for good (or bad) measure :shrug:
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize
- SymCleanup(_process.Handle);
+ PInvoke.SymCleanup(_process.SafeHandle);
}
// Find DLL offset if needed
@@ -243,7 +244,7 @@ protected virtual void Dispose(bool disposing)
}
// Close old process
- CloseProcess(_processHandle);
+ PInvoke.CloseHandle((HANDLE)_processHandle);
disposedValue = true;
}
diff --git a/STROOP.Core/Kernal32NativeMethods.cs b/STROOP.Core/Kernal32NativeMethods.cs
deleted file mode 100644
index 21d2f7da4..000000000
--- a/STROOP.Core/Kernal32NativeMethods.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace STROOP.Core;
-
-public static class Kernal32NativeMethods
-{
- [Flags]
- public enum ThreadAccess : int
- {
- 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,
- }
-
- [Flags]
- public enum ProcessAccess : int
- {
- VM_OPERATION = 0x0008,
- VM_READ = 0x0010,
- VM_WRITE = 0x0020,
- PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
- SUSPEND_RESUME = 0x0800,
- }
-
- [Flags]
- public enum MemoryType : uint
- {
- MEM_IMAGE = 0x1000000,
- MEM_MAPPED = 0x40000,
- MEM_PRIVATE = 0x20000,
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct MemoryBasicInformation
- {
- public UIntPtr BaseAddress;
- public IntPtr AllocationBase;
- public uint AllocationProtect;
- public IntPtr RegionSize;
- public uint State;
- public uint Protect;
- public MemoryType Type;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct PsapiWorkingSetExInformation
- {
- public IntPtr VirtualAddress;
- public ulong VirtualAttributes;
- }
-
- ///
- /// C# representation of SYMBOL_INFO in dbghelp.h.
- /// https://learn.microsoft.com/de-de/windows/win32/api/dbghelp/ns-dbghelp-symbol_info
- ///
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct Win32SymbolInfo
- {
- private const int MaxSymbolLen = 2000;
-
- public static Win32SymbolInfo Create()
- => new Win32SymbolInfo
- {
- MaxNameLen = MaxSymbolLen,
- SizeOfStruct = 88,
- };
-
- public int SizeOfStruct;
- public int TypeIndex;
- private readonly ulong Reserved1, Reserved2;
- public int Index;
- public int Size;
- public ulong ModuleBase;
- public uint Flags;
- public long Value;
- public ulong Address;
- public uint Register;
- public uint Scope;
- public uint Tag;
- public uint NameLen;
- public int MaxNameLen;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxSymbolLen)]
- public string Name;
- }
-
- #region DLL Import
-
- [DllImport("kernel32.dll")]
- private static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
-
- [DllImport("kernel32.dll")]
- private static extern uint SuspendThread(IntPtr hThread);
-
- [DllImport("kernel32.dll")]
- private static extern int ResumeThread(IntPtr hThread);
-
- [DllImport("kernel32.dll")]
- private static extern bool CloseHandle(IntPtr hObject);
-
- [DllImport("kernel32.dll")]
- private static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId);
-
- [DllImport("kernel32.dll")]
- private static extern bool ReadProcessMemory(IntPtr hProcess,
- UIntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesRead);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress,
- byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesWritten);
-
- [DllImport("kernel32.dll")]
- private static extern IntPtr VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength);
-
- [DllImport("psapi", SetLastError = true)]
- private static extern bool QueryWorkingSetEx(IntPtr hProcess, out PsapiWorkingSetExInformation pv, uint cb);
-
- [DllImport("dbghelp", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SymInitializeW", ExactSpelling = true)]
- public static extern bool SymInitialize(IntPtr hProcess, string searchPath, bool invadeProcess);
-
- [DllImport("dbghelp", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SymCleanup", ExactSpelling = true)]
- public static extern bool SymCleanup(IntPtr hProcess);
-
- [DllImport("dbghelp", SetLastError = true)]
- public static extern bool SymFromName(IntPtr hProcess, string name, ref Win32SymbolInfo win32Symbol);
-
- [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process);
-
- #endregion
-
- public static IntPtr ProcessGetHandleFromId(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId) => OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
-
- public static bool CloseProcess(IntPtr processHandle) => CloseHandle(processHandle);
-
- public static bool ProcessReadMemory(IntPtr hProcess,
- UIntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesRead) => ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, dwSize, ref lpNumberOfBytesRead);
-
- public static bool ProcessWriteMemory(IntPtr hProcess, UIntPtr lpBaseAddress,
- byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesWritten) => WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, dwSize, ref lpNumberOfBytesWritten);
-
- public static void ResumeProcess(Process process)
- {
- // Resume all threads
- foreach (ProcessThread pT in process.Threads)
- {
- IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
-
- if (pOpenThread == IntPtr.Zero)
- continue;
-
- int suspendCount = 0;
- do
- {
- suspendCount = ResumeThread(pOpenThread);
- } while (suspendCount > 0);
-
- CloseHandle(pOpenThread);
- }
- }
-
- public static void SuspendProcess(Process process)
- {
- // Pause all threads
- foreach (ProcessThread pT in process.Threads)
- {
- IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
-
- if (pOpenThread == IntPtr.Zero)
- continue;
-
- SuspendThread(pOpenThread);
- CloseHandle(pOpenThread);
- }
- }
-
- public static IntPtr VQueryEx(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength) => VirtualQueryEx(hProcess, lpAddress, out lpBuffer, dwLength);
-
- public static bool QWorkingSetEx(IntPtr hProcess, out PsapiWorkingSetExInformation pv, uint cb) => QueryWorkingSetEx(hProcess, out pv, cb);
-}
diff --git a/STROOP.Core/ProcessHelper.cs b/STROOP.Core/ProcessHelper.cs
new file mode 100644
index 000000000..5c64268ef
--- /dev/null
+++ b/STROOP.Core/ProcessHelper.cs
@@ -0,0 +1,45 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.Threading;
+
+namespace STROOP.Core;
+
+public static class ProcessHelper
+{
+ public static void ResumeProcess(Process process)
+ {
+ // Resume all threads
+ foreach (ProcessThread pT in process.Threads)
+ {
+ HANDLE pOpenThread = PInvoke.OpenThread(THREAD_ACCESS_RIGHTS.THREAD_SUSPEND_RESUME, false, (uint)pT.Id);
+
+ if (pOpenThread == IntPtr.Zero)
+ continue;
+
+ uint suspendCount = 0;
+ do
+ {
+ suspendCount = PInvoke.ResumeThread(pOpenThread);
+ } while (suspendCount > 0);
+
+ PInvoke.CloseHandle(pOpenThread);
+ }
+ }
+
+ public static void SuspendProcess(Process process)
+ {
+ // Pause all threads
+ foreach (ProcessThread pT in process.Threads)
+ {
+ HANDLE pOpenThread = PInvoke.OpenThread(THREAD_ACCESS_RIGHTS.THREAD_SUSPEND_RESUME, false, (uint)pT.Id);
+
+ if (pOpenThread == IntPtr.Zero)
+ continue;
+
+ PInvoke.SuspendThread(pOpenThread);
+ PInvoke.CloseHandle(pOpenThread);
+ }
+ }
+}
diff --git a/STROOP.Core/STROOP.Core.csproj b/STROOP.Core/STROOP.Core.csproj
index 229200006..86bbab216 100644
--- a/STROOP.Core/STROOP.Core.csproj
+++ b/STROOP.Core/STROOP.Core.csproj
@@ -6,4 +6,7 @@
disable
+
+
+
diff --git a/STROOP.Win32/NativeMethodWrappers.cs b/STROOP.Win32/NativeMethodWrappers.cs
new file mode 100644
index 000000000..b33c004c0
--- /dev/null
+++ b/STROOP.Win32/NativeMethodWrappers.cs
@@ -0,0 +1,71 @@
+using System.Runtime.InteropServices;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.Diagnostics.Debug;
+using Windows.Win32.System.ProcessStatus;
+
+namespace STROOP.Win32;
+
+public static class NativeMethodWrappers
+{
+ public static unsafe bool ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] buffer)
+ {
+ var gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ UIntPtr lpNumberOfBytesRead;
+ try
+ {
+ return PInvoke.ReadProcessMemory(
+ (HANDLE)hProcess,
+ (void*)lpBaseAddress,
+ (void*)Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0),
+ (uint)buffer.Length,
+ &lpNumberOfBytesRead
+ );
+ }
+ finally
+ {
+ gcHandle.Free();
+ }
+ }
+
+ public static unsafe bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] buffer)
+ {
+ UIntPtr numOfBytes = 0;
+ var gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ try
+ {
+ return PInvoke.WriteProcessMemory(
+ (HANDLE)hProcess,
+ (void*)lpBaseAddress,
+ (void*)Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0),
+ (UIntPtr)buffer.Length,
+ &numOfBytes);
+ }
+ finally
+ {
+ gcHandle.Free();
+ }
+ }
+
+ public static unsafe bool QueryWorkingSetEx(IntPtr hProcess, UIntPtr lpBaseAddress, out PSAPI_WORKING_SET_EX_INFORMATION wsInfo)
+ {
+ PSAPI_WORKING_SET_EX_INFORMATION tmp;
+ tmp.VirtualAddress = (HANDLE)lpBaseAddress;
+ uint setInfoSize = (uint)Marshal.SizeOf(typeof(PSAPI_WORKING_SET_EX_INFORMATION));
+ var result = PInvoke.QueryWorkingSetEx((HANDLE)hProcess, &tmp, setInfoSize);
+ wsInfo = tmp;
+ return result;
+ }
+
+ public static unsafe bool GetSymbolAddress(SafeHandle hProcess, string name, out ulong address)
+ {
+ var symbol = new SYMBOL_INFO
+ {
+ MaxNameLen = 2000,
+ SizeOfStruct = 88,
+ };
+ var result = PInvoke.SymFromName(hProcess, name, &symbol);
+ address = symbol.Address;
+ return result;
+ }
+}
diff --git a/STROOP.Win32/NativeMethods.json b/STROOP.Win32/NativeMethods.json
new file mode 100644
index 000000000..d1b171f72
--- /dev/null
+++ b/STROOP.Win32/NativeMethods.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "https://aka.ms/CsWin32.schema.json",
+ "public": true
+}
diff --git a/STROOP.Win32/NativeMethods.txt b/STROOP.Win32/NativeMethods.txt
new file mode 100644
index 000000000..7087d42e1
--- /dev/null
+++ b/STROOP.Win32/NativeMethods.txt
@@ -0,0 +1,26 @@
+OpenThread
+SuspendThread
+ResumeThread
+CloseHandle
+OpenProcess
+ReadProcessMemory
+WriteProcessMemory
+QueryWorkingSetEx
+SymInitialize
+SymCleanup
+SymFromName
+IsWow64Process
+
+PSAPI_WORKING_SET_EX_INFORMATION
+MEMORY_BASIC_INFORMATION
+
+CHARFORMAT2A
+CFE_EFFECTS
+CFM_MASK
+SCF_*
+EM_*
+SendMessage
+
+GetAsyncKeyState
+GetSystemMetrics
+SYSTEM_METRICS_INDEX
diff --git a/STROOP.Win32/STROOP.Win32.csproj b/STROOP.Win32/STROOP.Win32.csproj
new file mode 100644
index 000000000..73254d5aa
--- /dev/null
+++ b/STROOP.Win32/STROOP.Win32.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net8.0
+ enable
+ enable
+ STROOP.Win32
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/STROOP.Win32/VirtualQueryEx.cs b/STROOP.Win32/VirtualQueryEx.cs
new file mode 100644
index 000000000..82fb0eb7f
--- /dev/null
+++ b/STROOP.Win32/VirtualQueryEx.cs
@@ -0,0 +1,34 @@
+using System.Runtime.InteropServices;
+
+namespace STROOP.Win32;
+
+///
+/// The VirtualQueryEx method cannot be generated via CsWin32 unless the C# project itself is compiled for a specific platform.
+/// Invoking it may thus cause a runtime exception on certain platforms, but as this is only used for the Dolphin IO, I'll accept this for now.
+/// See https://github.com/microsoft/CsWin32/issues/722 for details.
+///
+public static class VirtualQueryEx
+{
+ [Flags]
+ public enum MemoryType : uint
+ {
+ MEM_IMAGE = 0x1000000,
+ MEM_MAPPED = 0x40000,
+ MEM_PRIVATE = 0x20000,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MemoryBasicInformation
+ {
+ public UIntPtr BaseAddress;
+ public IntPtr AllocationBase;
+ public uint AllocationProtect;
+ public IntPtr RegionSize;
+ public uint State;
+ public uint Protect;
+ public MemoryType Type;
+ }
+
+ [DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")]
+ public static extern IntPtr Invoke(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength);
+}
diff --git a/STROOP.sln b/STROOP.sln
index 514915ea7..aafba4587 100644
--- a/STROOP.sln
+++ b/STROOP.sln
@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP.Variables", "STROOP.Variables\STROOP.Variables.csproj", "{D5CB8378-E26B-4808-839B-200083A13E3C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP.Win32", "STROOP.Win32\STROOP.Win32.csproj", "{590625A1-EC10-4656-8BD3-65BB7AAE004F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -60,6 +62,18 @@ Global
{D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x64.Build.0 = Release|Any CPU
{D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x86.ActiveCfg = Release|Any CPU
{D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x86.Build.0 = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x64.Build.0 = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x86.Build.0 = Debug|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x64.ActiveCfg = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x64.Build.0 = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x86.ActiveCfg = Release|Any CPU
+ {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/STROOP/Controls/CarretlessTextBox.cs b/STROOP/Controls/CarretlessTextBox.cs
deleted file mode 100644
index 4b5c69fda..000000000
--- a/STROOP/Controls/CarretlessTextBox.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Windows.Forms;
-using System.Runtime.InteropServices;
-
-namespace STROOP
-{
- public class CarretlessTextBox : TextBox
- {
- [DllImport("user32.dll")]
- static extern bool HideCaret(IntPtr hWnd);
-
- [DllImport("user32.dll")]
- static extern bool ShowCaret(IntPtr hWnd);
-
- public CarretlessTextBox()
- {
- }
-
- public void HideTheCaret()
- {
- HideCaret(Handle);
- }
-
- public void ShowTheCaret()
- {
- ShowCaret(Handle);
- }
- }
-}
diff --git a/STROOP/Controls/RichTextBoxEx.cs b/STROOP/Controls/RichTextBoxEx.cs
index c2bbac1aa..2d371c1fd 100644
--- a/STROOP/Controls/RichTextBoxEx.cs
+++ b/STROOP/Controls/RichTextBoxEx.cs
@@ -3,115 +3,14 @@
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.UI.Controls.RichEdit;
namespace STROOP.Controls
{
public class RichTextBoxEx : RichTextBox
{
- #region Interop-Defines
-
- [StructLayout(LayoutKind.Sequential)]
- private struct CHARFORMAT2_STRUCT
- {
- public UInt32 cbSize;
- public UInt32 dwMask;
- public UInt32 dwEffects;
- public Int32 yHeight;
- public Int32 yOffset;
- public Int32 crTextColor;
- public byte bCharSet;
- public byte bPitchAndFamily;
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- public char[] szFaceName;
-
- public UInt16 wWeight;
- public UInt16 sSpacing;
- public int crBackColor; // Color.ToArgb() -> int
- public int lcid;
- public int dwReserved;
- public Int16 sStyle;
- public Int16 wKerning;
- public byte bUnderlineType;
- public byte bAnimation;
- public byte bRevAuthor;
- public byte bReserved1;
- }
-
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
-
- private const int WM_USER = 0x0400;
- private const int EM_GETCHARFORMAT = WM_USER + 58;
- private const int EM_SETCHARFORMAT = WM_USER + 68;
-
- private const int SCF_SELECTION = 0x0001;
- private const int SCF_WORD = 0x0002;
- private const int SCF_ALL = 0x0004;
-
- #region CHARFORMAT2 Flags
-
- private const UInt32 CFE_BOLD = 0x0001;
- private const UInt32 CFE_ITALIC = 0x0002;
- private const UInt32 CFE_UNDERLINE = 0x0004;
- private const UInt32 CFE_STRIKEOUT = 0x0008;
- private const UInt32 CFE_PROTECTED = 0x0010;
- private const UInt32 CFE_LINK = 0x0020;
- private const UInt32 CFE_AUTOCOLOR = 0x40000000;
- private const UInt32 CFE_SUBSCRIPT = 0x00010000; /* Superscript and subscript are */
- private const UInt32 CFE_SUPERSCRIPT = 0x00020000; /* mutually exclusive */
-
- private const int CFM_SMALLCAPS = 0x0040; /* (*) */
- private const int CFM_ALLCAPS = 0x0080; /* Displayed by 3.0 */
- private const int CFM_HIDDEN = 0x0100; /* Hidden by 3.0 */
- private const int CFM_OUTLINE = 0x0200; /* (*) */
- private const int CFM_SHADOW = 0x0400; /* (*) */
- private const int CFM_EMBOSS = 0x0800; /* (*) */
- private const int CFM_IMPRINT = 0x1000; /* (*) */
- private const int CFM_DISABLED = 0x2000;
- private const int CFM_REVISED = 0x4000;
-
- private const int CFM_BACKCOLOR = 0x04000000;
- private const int CFM_LCID = 0x02000000;
- private const int CFM_UNDERLINETYPE = 0x00800000; /* Many displayed by 3.0 */
- private const int CFM_WEIGHT = 0x00400000;
- private const int CFM_SPACING = 0x00200000; /* Displayed by 3.0 */
- private const int CFM_KERNING = 0x00100000; /* (*) */
- private const int CFM_STYLE = 0x00080000; /* (*) */
- private const int CFM_ANIMATION = 0x00040000; /* (*) */
- private const int CFM_REVAUTHOR = 0x00008000;
-
-
- private const UInt32 CFM_BOLD = 0x00000001;
- private const UInt32 CFM_ITALIC = 0x00000002;
- private const UInt32 CFM_UNDERLINE = 0x00000004;
- private const UInt32 CFM_STRIKEOUT = 0x00000008;
- private const UInt32 CFM_PROTECTED = 0x00000010;
- private const UInt32 CFM_LINK = 0x00000020;
- private const UInt32 CFM_SIZE = 0x80000000;
- private const UInt32 CFM_COLOR = 0x40000000;
- private const UInt32 CFM_FACE = 0x20000000;
- private const UInt32 CFM_OFFSET = 0x10000000;
- private const UInt32 CFM_CHARSET = 0x08000000;
- private const UInt32 CFM_SUBSCRIPT = CFE_SUBSCRIPT | CFE_SUPERSCRIPT;
- private const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT;
-
- private const byte CFU_UNDERLINENONE = 0x00000000;
- private const byte CFU_UNDERLINE = 0x00000001;
- private const byte CFU_UNDERLINEWORD = 0x00000002; /* (*) displayed as ordinary underline */
- private const byte CFU_UNDERLINEDOUBLE = 0x00000003; /* (*) displayed as ordinary underline */
- private const byte CFU_UNDERLINEDOTTED = 0x00000004;
- private const byte CFU_UNDERLINEDASH = 0x00000005;
- private const byte CFU_UNDERLINEDASHDOT = 0x00000006;
- private const byte CFU_UNDERLINEDASHDOTDOT = 0x00000007;
- private const byte CFU_UNDERLINEWAVE = 0x00000008;
- private const byte CFU_UNDERLINETHICK = 0x00000009;
- private const byte CFU_UNDERLINEHAIRLINE = 0x0000000A; /* (*) displayed as ordinary underline */
-
- #endregion
-
- #endregion
-
public RichTextBoxEx()
{
// Otherwise, non-standard links get lost when user starts typing
@@ -193,7 +92,7 @@ public void InsertLink(string text, string hyperlink, int position)
/// true: set link style, false: clear link style
public void SetSelectionLink(bool link)
{
- SetSelectionStyle(CFM_LINK, link ? CFE_LINK : 0);
+ SetSelectionStyle(CFM_MASK.CFM_LINK, link ? CFE_EFFECTS.CFE_LINK : 0);
}
///
@@ -202,39 +101,39 @@ public void SetSelectionLink(bool link)
/// 0: link style not set, 1: link style set, -1: mixed
public int GetSelectionLink()
{
- return GetSelectionStyle(CFM_LINK, CFE_LINK);
+ return GetSelectionStyle(CFM_MASK.CFM_LINK, CFE_EFFECTS.CFE_LINK);
}
- private void SetSelectionStyle(UInt32 mask, UInt32 effect)
+ private void SetSelectionStyle(CFM_MASK mask, CFE_EFFECTS effect)
{
- CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
+ CHARFORMATA cf = new CHARFORMATA();
cf.cbSize = (UInt32)Marshal.SizeOf(cf);
cf.dwMask = mask;
cf.dwEffects = effect;
- IntPtr wpar = new IntPtr(SCF_SELECTION);
- IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
+ WPARAM wpar = new WPARAM(PInvoke.SCF_SELECTION);
+ LPARAM lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
Marshal.StructureToPtr(cf, lpar, false);
- IntPtr res = SendMessage(Handle, EM_SETCHARFORMAT, wpar, lpar);
+ IntPtr res = PInvoke.SendMessage((HWND)Handle, PInvoke.EM_SETCHARFORMAT, wpar, lpar);
Marshal.FreeCoTaskMem(lpar);
}
- private int GetSelectionStyle(UInt32 mask, UInt32 effect)
+ private int GetSelectionStyle(CFM_MASK mask, CFE_EFFECTS effect)
{
- CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
+ CHARFORMATA cf = new CHARFORMATA();
cf.cbSize = (UInt32)Marshal.SizeOf(cf);
- cf.szFaceName = new char[32];
+ cf.szFaceName = new __CHAR_32();
- IntPtr wpar = new IntPtr(SCF_SELECTION);
- IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
+ WPARAM wpar = new WPARAM(PInvoke.SCF_SELECTION);
+ LPARAM lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
Marshal.StructureToPtr(cf, lpar, false);
- IntPtr res = SendMessage(Handle, EM_GETCHARFORMAT, wpar, lpar);
+ IntPtr res = PInvoke.SendMessage((HWND)Handle, PInvoke.EM_GETCHARFORMAT, wpar, lpar);
- cf = (CHARFORMAT2_STRUCT)Marshal.PtrToStructure(lpar, typeof(CHARFORMAT2_STRUCT));
+ cf = (CHARFORMATA)Marshal.PtrToStructure(lpar, typeof(CHARFORMATA));
int state;
// dwMask holds the information which properties are consistent throughout the selection:
diff --git a/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs b/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs
index 77b3b3a7c..458d2defd 100644
--- a/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs
+++ b/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs
@@ -5,7 +5,7 @@
namespace STROOP.Controls.VariablePanel;
-public class VariablePanelValueEditBox : CarretlessTextBox, IValueEditBox
+public class VariablePanelValueEditBox : TextBox, IValueEditBox
{
private readonly EventHandler _handleLostFocus;
private bool killed = false;
diff --git a/STROOP/STROOP.csproj b/STROOP/STROOP.csproj
index fe041d587..76291479a 100644
--- a/STROOP/STROOP.csproj
+++ b/STROOP/STROOP.csproj
@@ -53,9 +53,6 @@
Component
-
- Component
-
Component
diff --git a/STROOP/Utilities/MouseUtility.cs b/STROOP/Utilities/MouseUtility.cs
index 8fc05baa2..a0cb0924b 100644
--- a/STROOP/Utilities/MouseUtility.cs
+++ b/STROOP/Utilities/MouseUtility.cs
@@ -1,27 +1,20 @@
-using System.Runtime.InteropServices;
-using System.Windows.Forms;
+using System.Windows.Forms;
+using Windows.Win32;
+using Windows.Win32.UI.WindowsAndMessaging;
namespace STROOP.Utilities
{
public static class MouseUtility
{
- const int SM_SWAPBUTTON = 23;
-
- [DllImport("user32.dll")]
- static extern short GetAsyncKeyState(Keys vKey);
-
- [DllImport("user32.dll")]
- static extern int GetSystemMetrics(int nIndex);
-
public static bool IsMouseDown(int button)
{
- bool buttonsSwapped = GetSystemMetrics(SM_SWAPBUTTON) != 0;
+ bool buttonsSwapped = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_SWAPBUTTON) != 0;
if (buttonsSwapped)
if (button == 0) button = 1;
else if (button == 1) button = 0;
Keys key = button == 2 ? Keys.MButton : (Keys)(button + 1);
- return (GetAsyncKeyState(key) & 0x8000) != 0;
+ return (PInvoke.GetAsyncKeyState((int)key) & 0x8000) != 0;
}
}
}