How do I manually toggle the NumLock Key with C# in WPF? - c#

I've been searching for a while and there are mostly results in C++ or other languages, and not C#. Things I've seen:
keybd_event() // A c++ method that theoretically can be included with a DLL import, but hasn't worked in testing
System.Windows.Forms.SendKeys.Send("{NUMLOCK}"}; // Forms namespace doesn't exist in Windows
Currently, I have code that executes every second or so to watch the state of numlock and update a graphic in my form accordingly. If a bool toggle is set, I also want it to force NumLock on:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
private void watcher(object source, ElapsedEventArgs e)
{
bool NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
if (!NumLock && fixers.watchNumL)
{
// Force NumLock back on
// Simulate a key press
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | 0,IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP, IntPtr.Zero);
NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
}
if (NumLock)
{
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_on.png", UriKind.Relative));
StatusBox.Text = "Num Lock ON";
});
}
else {
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_off.png", UriKind.Relative));
StatusBox.Text = "Num Lock OFF";
});
}
}
public MainWindow()
{
// Start the watcher
System.Timers.Timer myTimer = new System.Timers.Timer();
// Tell the timer what to do when it elapses
myTimer.Elapsed += new ElapsedEventHandler(watcher);
// Set it to go off every second
myTimer.Interval = 1000;
// And start it
myTimer.Enabled = true;
}

Here is a class (with a library) that can do this for you. the library does much more, so it's maybe a bit overkill to use just for this. The approach uses the keybd_event function using pinvoke:
// Simulate a key press
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | 0,
IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,
IntPtr.Zero);
Pressing and releasing the button changes the state of the LED. virtualKey is one of the VK_ constants.
Here are the declarations:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}

Related

Keeping numlock off in c#

I would like to use the numlock button for something other than numlock. So basically I would like to turn off numlock when it is pressed and keep it off. I can capture the button press but it still toggles on/off. I want it off, always. Any suggestions?
Not sure WHY anyone would like to know WHY I want this to be done but here is the reason: I have a bluetooth numeric keypad that I want to use to control a machine. Does that justify the question?
After a couple hours of research I came across the following code which did the trick:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class SetNumlockKeyOn
{
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal int type;
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
int dummy1;
int dummy2;
internal int type1;
internal short wVk1;
internal short wScan1;
internal int dwFlags1;
internal int time1;
internal IntPtr dwExtraInfo1;
int dummy3;
int dummy4;
}
[DllImport("user32.dll")]
static extern int SendInput(uint nInputs, IntPtr pInputs, int cbSize);
public static void SetNumlockOn()
{
if (Control.IsKeyLocked(Keys.NumLock)) return;
const int mouseInpSize = 28;//Hardcoded size of the MOUSEINPUT tag !!!
INPUT input = new INPUT();
input.type = 0x01; //INPUT_KEYBOARD
input.wVk = 0x90; //VK_NUMLOCK
input.wScan = 0;
input.dwFlags = 0; //key-down
input.time = 0;
input.dwExtraInfo = IntPtr.Zero;
input.type1 = 0x01;
input.wVk1 = 0x90;
input.wScan1 = 0;
input.dwFlags1 = 2; //key-up
input.time1 = 0;
input.dwExtraInfo1 = IntPtr.Zero;
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize * 2);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize); //Hardcoded size of the MOUSEINPUT tag !!!
//if (result == 0 || Marshal.GetLastWin32Error() != 0)
// Console.WriteLine(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(pI);
}
}
Here's an example:
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}

Turn Display On and Kill Screensaver

Given a Windows 8 (.1) computer with the following power options:
And screensaver configured as:
The goal is to programmatically turn the display on and "kill" the screensaver (so that it will be re-activated after idle time).
(Note, that according to the settings it's possible that only the screensaver is on, or, that the display is off completely after the screensaver was on for about one minute).
What i have tried is:
SendMessage(HWND_Broadcast, WM_SysCommand, SC_MONITORPOWER, (LPARAM) - 1);
in combination with
// From Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
// "How to force a screen saver to close once started
// in Windows NT, Windows 2000, and Windows Server 2003"
public static void KillScreenSaver()
{
IntPtr hDesktop = OpenDesktop("Screen-saver", 0, false, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hDesktop != IntPtr.Zero)
{
if (!EnumDesktopWindows(hDesktop, KillScreenSaverFunc, IntPtr.Zero) || !CloseDesktop(hDesktop))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
TerminateWindow(GetForegroundWindow());
}
}
private static bool KillScreenSaverFunc(IntPtr hWnd, IntPtr lParam)
{
if (IsWindowVisible(hWnd))
{
TerminateWindow(hWnd);
}
return true;
}
private static void TerminateWindow(IntPtr hWnd)
{
if (!PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
And
public static void ActivateScreensaver()
{
SetScreenSaverActive(TRUE);
}
private static void SetScreenSaverActive(uint active)
{
IntPtr nullVar = IntPtr.Zero;
// Ignoring error since ERROR_OPERATION_IN_PROGRESS is expected.
// Methode is called to reset timer and to prevent possible errors as mentioned in Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, active, ref nullVar, SPIF_SENDWININICHANGE);
}
Which worked, partially. However, the display was turned off immediately again (as a matter of fact, most times one couldn't even see that the monitor was turned again apart from the power-led going "steady on" instead of "flashing on off = power safe" for a short time).
So i guess i'm missing a crucial part of the picture like reliably resetting system idle timer to make sure the screen is not immediately being turned off, again.
Edit: According to my investigations SetThreadExecutionState(ES_DISPLAY_REQUIRED) seems to do the trick in regards to resetting the idle-timer. However, i still don't know the correct sequence of calls. I'll self-answer when i figure it out...
The following code will:
interrupt a running screensaver
turn on a turned-off screen ("turn off" as mentioned in power options)
private static readonly ILog Log = LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
public void TurnOnScreenAndInterruptScreensaver()
{
TryTurnOnScreenAndResetDisplayIdleTimer();
TryInterruptScreensaver();
}
/// <summary>
/// Moves the mouse which turns on a turned-off screen and also resets the
/// display idle timer, which is key, because otherwise the
/// screen would be turned off again immediately.
/// </summary>
private static void TryTurnOnScreenAndResetDisplayIdleTimer()
{
var input = new SendInputNativeMethods.Input {
type = SendInputNativeMethods.SendInputEventType.InputMouse, };
try
{
SendInputNativeMethods.SendInput(input);
}
catch (Win32Exception exception)
{
Log.Error("Could not send mouse move input to turn on display", exception);
}
}
private static void TryInterruptScreensaver()
{
try
{
if (ScreensaverNativeMethods.GetScreenSaverRunning())
{
ScreensaverNativeMethods.KillScreenSaver();
}
// activate screen saver again so that after idle-"timeout" it shows again
ScreensaverNativeMethods.ActivateScreensaver();
}
catch (Win32Exception exception)
{
Log.Error("Screensaver could not be deactivated", exception);
}
}
SendInputNativeMethods:
public static class SendInputNativeMethods
{
public static void SendInput(params Input[] inputs)
{
if (SendInput((uint)inputs.Length, inputs, Marshal.SizeOf<Input>())
!= (uint)inputs.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern uint SendInput(
uint nInputs,
[MarshalAs(UnmanagedType.LPArray), In] Input[] pInputs,
int cbSize);
[StructLayout(LayoutKind.Sequential)]
public struct Input
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
public struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
public struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
public enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
public enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}
ScreensaverNativeMethods:
internal static class ScreensaverNativeMethods
{
private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
private const int SPI_SETSCREENSAVEACTIVE = 0x0011;
private const int SPIF_SENDWININICHANGE = 0x0002;
private const uint DESKTOP_WRITEOBJECTS = 0x0080;
private const uint DESKTOP_READOBJECTS = 0x0001;
private const int WM_CLOSE = 0x0010;
private const int TRUE = 1;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
ref IntPtr pvParam,
uint fWinIni);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PostMessage(
IntPtr hWnd,
uint msg,
IntPtr wParam,
IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr OpenDesktop(
string lpszDesktop,
uint dwFlags,
[In, MarshalAs(UnmanagedType.Bool)]bool fInherit,
uint dwDesiredAccess);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseDesktop(IntPtr hDesktop);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumDesktopWindows(
IntPtr hDesktop,
EnumDesktopWindowsProc callback,
IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
private delegate bool EnumDesktopWindowsProc(IntPtr hDesktop, IntPtr lParam);
public static bool GetScreenSaverRunning()
{
IntPtr isRunning = IntPtr.Zero;
if (!SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return isRunning != IntPtr.Zero;
}
public static void ActivateScreensaver()
{
SetScreenSaverActive(TRUE);
}
private static void SetScreenSaverActive(uint active)
{
IntPtr nullVar = IntPtr.Zero;
// Ignoring error since ERROR_OPERATION_IN_PROGRESS is expected.
// Methode is called to reset timer and to prevent possible errors
// as mentioned in Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
SystemParametersInfo(
SPI_SETSCREENSAVEACTIVE,
active,
ref nullVar,
SPIF_SENDWININICHANGE);
}
// From Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
// "How to force a screen saver to close once started
// in Windows NT, Windows 2000, and Windows Server 2003"
public static void KillScreenSaver()
{
IntPtr hDesktop = OpenDesktop(
"Screen-saver",
0,
false,
DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hDesktop != IntPtr.Zero)
{
if (!EnumDesktopWindows(hDesktop, KillScreenSaverFunc, IntPtr.Zero)
|| !CloseDesktop(hDesktop))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
TerminateWindow(GetForegroundWindow());
}
}
private static bool KillScreenSaverFunc(IntPtr hWnd, IntPtr lParam)
{
if (IsWindowVisible(hWnd))
{
TerminateWindow(hWnd);
}
return true;
}
private static void TerminateWindow(IntPtr hWnd)
{
if (!PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}

Process volume and trackbar

I have a trackbar in my form that has a range of 1-100 (for volume). I am looking for a way to set the audio output volume to a value I've entered (e.g. trackbar's value) but ONLY for my application.
Didn't find something in the web.
Regards
private void trackBar1_ValueChanged(object sender, EventArgs e)
{
// Calculate the volume that's being set
double newVolume = ushort.MaxValue * trackBar1.Value/ 10.0;
uint v = ((uint) newVolume) & 0xffff;
uint vAll = v | (v << 16);
// Set the volume
int retVal = NativeMethods.WaveOutSetVolume(IntPtr.Zero, vAll);
bool playRetVal = NativeMethods.PlaySound("tada.wav", IntPtr.Zero, 0x2001);
}
}
static class NativeMethods
{
[DllImport("winmm.dll", EntryPoint = "waveOutSetVolume")]
public static extern int WaveOutSetVolume(IntPtr hwo, uint dwVolume);
[DllImport("winmm.dll", SetLastError = true)]
public static extern bool PlaySound(string pszSound, IntPtr hmod, uint fdwSound);
}
This should simply work. i hope i didnt miss anything.

Any way to bring Unity3d to the foreground?

I have sent my user out to the browser with Application.OpenURL. And now I want to programatically bring unity back to the foreground.
Is there any way to do it without a plugin?
Thanks.
Use GetActiveWindow to get the window's handle before you send the user away, then use SetForegroundWindow using that handle. Before you use SetForegroundWindow, you can try simulating an Alt keypress to bring up a menu to abide by certain limitations of SetForegroundWindow:
private IntPtr unityWindow;
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
const int ALT = 0xA4;
const int EXTENDEDKEY = 0x1;
const int KEYUP = 0x2;
private void SendUser()
{
unityWindow = GetActiveWindow();
Application.OpenURL("http://example.com");
StartCoroutine(RefocusWindow(30f));
}
private IEnumerator RefocusWindow(float waitSeconds) {
// wait for new window to appear
yield return new WaitWhile(() => unityWindow == GetActiveWindow());
yield return new WaitForSeconds(waitSeconds);
// Simulate alt press
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// Simulate alt release
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
SetForegroundWindow(unityWindow);
}
if you are using Unity3D in Windows, try below code after calling Application.OpenURL(...) :
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
var prc = Process.GetProcessesByName("..."); //Get Unity's process, or
var prc = Process.GetCurrentProcess();
if (prc.Length > 0)
SetForegroundWindow(prc[0].MainWindowHandle);
This worked for me on Unity 5.0.1 / Windows 8.1:
using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
public class ForeGrounder : MonoBehaviour {
private const uint LOCK = 1;
private const uint UNLOCK = 2;
private IntPtr window;
void Start() {
LockSetForegroundWindow(LOCK);
window = GetActiveWindow();
StartCoroutine(Checker());
}
IEnumerator Checker() {
while (true) {
yield return new WaitForSeconds(1);
IntPtr newWindow = GetActiveWindow();
if (window != newWindow) {
Debug.Log("Set to foreground");
SwitchToThisWindow(window, true);
}
}
}
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
static extern bool LockSetForegroundWindow(uint uLockCode);
[DllImport("user32.dll")]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
}
For Mac Standalone we can try
public void OpenURLInDefaultBrowser(string URL)
{
#if UNITY_STANDALONE_OSX
Screen.fullScreenMode = FullScreenMode.Windowed;
#endif
Application.OpenURL(URL);
StartCoroutine(ReFocusUnity());
}
private IEnumerator ReFocusUnity()
{
//You can wait for some seconds or wait for any callback you are expecting
yield return new WaitForSeconds(5f);
#if UNITY_STANDALONE_OSX
Screen.fullScreenMode = FullScreenMode.FullScreenWindow;
#endif
}

Automatically a debug process from C# code and read register values

I'm looking for a way to read the edx registry at a certain address like asked in this question: Read eax register
Although my solution needs to be in C# and I tried to make it, what I got at this moment is:
public static IntPtr GetEdx(IntPtr address, Process process)
{
const uint DBG_EXCEPTION_NOT_HANDLED = 0x80010001;
const uint EXCEPTION_SINGLE_STEP = 0x80000004;
const int DBG_CONTINUE = 0x00010002; // Seems to work better than DBG_EXCEPTION_NOT_HANDLED
//DebugSetProcessKillOnExit(0);
DEBUG_EVENT evt = new DEBUG_EVENT();
// Attach to the process we provided the thread as an argument
if (!DebugActiveProcess(process.Id))
throw new Win32Exception();
CONTEXT context = new CONTEXT();
foreach (ProcessThread thread in process.Threads)
{
uint iThreadId = (uint)thread.Id;
IntPtr hThread =
OpenThread(
ThreadAccessFlags.SUSPEND_RESUME | ThreadAccessFlags.SET_CONTEXT |
ThreadAccessFlags.GET_CONTEXT, false, iThreadId);
// Suspent the thread
if (SuspendThread(hThread) == -1) throw new ApplicationException("Cannot suspend thread.");
context = new CONTEXT
{
ContextFlags = (uint)CONTEXT_FLAGS.CONTEXT_DEBUG_REGISTERS |
(uint)CONTEXT_FLAGS.CONTEXT_INTEGER
};
// Get the context
if (!GetThreadContext(hThread, ref context))
throw new Win32Exception();
// Change the context
context.Dr0 = (uint)address;
context.Dr7 = 0x00000001;
// Set the changed context back
if (!SetThreadContext(hThread, ref context))
throw new Win32Exception();
// Check if setting the context give any errors
var error = Marshal.GetLastWin32Error();
if (error != 0)
{
throw new ApplicationException("Error is setting context.");
}
// Resume the thread
if (ResumeThread(hThread) == -1) throw new ApplicationException("Cannot resume thread.");
}
while (true)
{
if (!WaitForDebugEvent(out evt, -1))
throw new Win32Exception();
// Multiple if's for easier debugging at this moment
if (evt.dwDebugEventCode == (uint)DebugEventType.EXCEPTION_DEBUG_EVENT)
{
if (evt.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)
{
if (evt.Exception.ExceptionRecord.ExceptionAddress == address)
{
context = new CONTEXT
{
ContextFlags = (uint)CONTEXT_FLAGS.CONTEXT_DEBUG_REGISTERS |
(uint)CONTEXT_FLAGS.CONTEXT_INTEGER
};
GetThreadContext((IntPtr)evt.dwThreadId, ref context);
return (IntPtr)context.Ebx; // ebx get
}
}
}
ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, DBG_CONTINUE);//DBG_EXCEPTION_NOT_HANDLED);
}
}
With a whole lot of Kernel32 methods:
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenThread(ThreadAccessFlags dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("Kernel32.dll", SetLastError = true)]
static extern bool DebugActiveProcess(int dwProcessId);
[DllImport("Kernel32.dll", SetLastError = true)]
static extern bool WaitForDebugEvent([Out] out DEBUG_EVENT lpDebugEvent, int dwMilliseconds);
[DllImport("Kernel32.dll", SetLastError = true)]
static extern bool ContinueDebugEvent(int dwProcessId, int dwThreadId, uint dwContinueStatus);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool IsDebuggerPresent();
[DllImport("kernel32.dll")]
private static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
[DllImport("kernel32.dll")]
public static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DEBUG_EVENT
{
public readonly uint dwDebugEventCode;
public readonly int dwProcessId;
public readonly int dwThreadId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 86, ArraySubType = UnmanagedType.U1)]
private readonly byte[] debugInfo;
public EXCEPTION_DEBUG_INFO Exception
{
get
{
if (debugInfo == null)
return new EXCEPTION_DEBUG_INFO();
fixed (byte* ptr = debugInfo)
{
return *(EXCEPTION_DEBUG_INFO*)ptr;
}
}
}
public LOAD_DLL_DEBUG_INFO LoadDll
{
get
{
if (debugInfo == null)
return new LOAD_DLL_DEBUG_INFO();
fixed (byte* ptr = debugInfo)
{
return *(LOAD_DLL_DEBUG_INFO*)ptr;
}
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct LOAD_DLL_DEBUG_INFO
{
public readonly IntPtr hFile;
public readonly IntPtr lpBaseOfDll;
public readonly uint dwDebugInfoFileOffset;
public readonly uint nDebugInfoSize;
public readonly IntPtr lpImageName;
public readonly ushort fUnicode;
}
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_DEBUG_INFO
{
public EXCEPTION_RECORD ExceptionRecord;
public readonly uint dwFirstChance;
}
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_RECORD
{
public readonly uint ExceptionCode;
public readonly uint ExceptionFlags;
public readonly IntPtr ExceptionRecord;
public readonly IntPtr ExceptionAddress;
public readonly uint NumberParameters;
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U4)]
//public readonly uint[] ExceptionInformation;
public unsafe fixed uint ExceptionInformation[15];
}
public enum DebugEventType : int
{
CREATE_PROCESS_DEBUG_EVENT = 3, //Reports a create-process debugging event. The value of u.CreateProcessInfo specifies a CREATE_PROCESS_DEBUG_INFO structure.
CREATE_THREAD_DEBUG_EVENT = 2, //Reports a create-thread debugging event. The value of u.CreateThread specifies a CREATE_THREAD_DEBUG_INFO structure.
EXCEPTION_DEBUG_EVENT = 1, //Reports an exception debugging event. The value of u.Exception specifies an EXCEPTION_DEBUG_INFO structure.
EXIT_PROCESS_DEBUG_EVENT = 5, //Reports an exit-process debugging event. The value of u.ExitProcess specifies an EXIT_PROCESS_DEBUG_INFO structure.
EXIT_THREAD_DEBUG_EVENT = 4, //Reports an exit-thread debugging event. The value of u.ExitThread specifies an EXIT_THREAD_DEBUG_INFO structure.
LOAD_DLL_DEBUG_EVENT = 6, //Reports a load-dynamic-link-library (DLL) debugging event. The value of u.LoadDll specifies a LOAD_DLL_DEBUG_INFO structure.
OUTPUT_DEBUG_STRING_EVENT = 8, //Reports an output-debugging-string debugging event. The value of u.DebugString specifies an OUTPUT_DEBUG_STRING_INFO structure.
RIP_EVENT = 9, //Reports a RIP-debugging event (system debugging error). The value of u.RipInfo specifies a RIP_INFO structure.
UNLOAD_DLL_DEBUG_EVENT = 7, //Reports an unload-DLL debugging event. The value of u.UnloadDll specifies an UNLOAD_DLL_DEBUG_INFO structure.
}
[StructLayout(LayoutKind.Sequential)]
public struct CONTEXT
{
public uint ContextFlags;
public uint Dr0;
public uint Dr1;
public uint Dr2;
public uint Dr3;
public uint Dr6;
public uint Dr7;
public FLOATING_SAVE_AREA FloatSave;
public uint SegGs;
public uint SegFs;
public uint SegEs;
public uint SegDs;
public uint Edi;
public uint Esi;
public uint Ebx;
public uint Edx;
public uint Ecx;
public uint Eax;
public uint Ebp;
public uint Eip;
public uint SegCs;
public uint EFlags;
public uint Esp;
public uint SegSs;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] ExtendedRegisters;
}
public enum CONTEXT_FLAGS : uint
{
CONTEXT_i386 = 0x10000,
CONTEXT_i486 = 0x10000,
CONTEXT_CONTROL = CONTEXT_i386 | 0x01,
CONTEXT_INTEGER = CONTEXT_i386 | 0x02,
CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04,
CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08,
CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10,
CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20,
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS,
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS
}
[Flags]
public enum ThreadAccessFlags : 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
}
[StructLayout(LayoutKind.Sequential)]
public struct FLOATING_SAVE_AREA
{
public uint ControlWord;
public uint StatusWord;
public uint TagWord;
public uint ErrorOffset;
public uint ErrorSelector;
public uint DataOffset;
public uint DataSelector;
// missing some stuff
public uint Cr0NpxState;
}
[DllImport("kernel32.dll")]
private static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, int lpBaseAddress, byte[] buffer, int size,
int lpNumberOfBytesRead);
But for some reason it never hits the evt.Exception.ExceptionRecord.ExceptionAddress == address
I'm pretty new to memory reading and have a hard time figuring out what is wrong with the code above.
EDIT: Also if I uncomment the context.Dr7 = 0x00000001; the application that I'm trying to read crashes.
The theory:
You want to attach to a process, put a breakpoint in it, register an event in the debugger application and wait for that event. You need to put the breakpoint at the address you give as parameter, and by reading the context you should be able to see the content of EDX. This seems reasonable, like a human developer would do it.
The implementation:
Looking at your implementation, the method you try to use to put the breakpoint at the address seems suspicious. Reading here I understand that trying to set the context on a running thread might give unpredictable results. You may also lack the sufficient permissions. Assuming you have the permissions, try stopping the threads before setting the context.
The other problem I predict is that the thread you want to stop and debug has a context that needs to be altered as less as possible. I think that you should first stop the thread, read it's context, change the Dr0 flag (assuming that's where you set the breakpoint) and then set the context with all the other register information unaltered.
Without that, I think that you basically change the execution of the program and I have a strong feeling that some of those registers are read only.
These are 2 things you need to consider. Hope it helps.
Debugging:
If that does not work, you need to add a function that uses GetLastError() to see why the functions fail (I'm suspecting SetThreadContext() will be the one causing problems in the first time).
You must also check that the Context structure is defined correctly and all the members have the same order has the ones defined here. The structure has to be aligned by the C# code exactly as in the unmanaged code.
Also please check if you are running on a 64bit OS. The context of a thread in a 64bit OS is different than for 32bit. Registers are extended for 64b and so on. If you use a 64bit OS, the context structure needs to be redefined. Same goes if you use an ARM machine.
Your answer seems to be hiding in one of the comments you transplanted with the other code... The functions to set and get thread context require a handle to a thread (probably opened with OpenThread using appropriate permissions, including at least get/set context). Instead, you're apparently passing a casted process ID. You should consider checking the return value for success, it would've probably helped identify your problem.

Categories

Resources