I am trying to use global hooks to detect input events (a mouse click, keyboard keys) and use the detection to trigger another event, such as storing the mouse coordinates. The code I've found does work, but I cannot call on another method in the same form because the hookProc is set to static.
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode.ToString() == "162") //162 is ASCI CTRL
{
MessageBox.Show("CTRL");
Form1 Trigger = new Form1(); // Supposed to allow calls to Form1, specifically textBox1
Trigger.textBox1.Text = "3"; // Will not change the Text value
}
return (IntPtr)1;
}
else
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
I know the code works because the CTRL MessageBox will show. I know textBox1.Text = "3"; because I can use the code elsewhere in an instance without issue. I searched and found I need to create a new instance of form1 in order to call on methods found outside the static hookProc. My code does not give me any build errors but does not do anything in regards to textBox1. Even if I wanted to call on another method when CTRL is detected, I cannot link to anything outside hookProc. Help?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Demo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
SetHook(); // Set the hook
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
UnHook(); // Remove the hook
}
// GLOBAL HOOK
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_KEYBOARD_LL = 13; // Number of global LowLevel- hook on the keyboard
const int WM_KEYDOWN = 0x100; // Messages pressing
private LowLevelKeyboardProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
public void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0);
}
public static void UnHook()
{
UnhookWindowsHookEx(hhook);
}
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode.ToString() == "162") //162 is ASCI CTRL
{
MessageBox.Show("CTRL");
Form1 Trigger = new Form1(); // Allows called to Form1, specifically textBox3
Trigger.TriggeredEvent(); //Visual confirmation of CTRL has been detected
Trigger.textBox1.Text = "3";
}
return (IntPtr)1;
}
else
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
}
}
As you would have guessed, the issue is that you are creating a new instance of Form1 and attempting to update the TextBox Value in the new instance. What you require is the same instance which is currently open.
Assuming you have only a single instance of Form1, you can use Application.OpenForms to get collection of all Open Forms and use Enumerable.OfType to filter the Form1 Type.
For Example
var formInstance = Application.OpenForms.OfType<Form1>().Single();
formInstance.TriggeredEvent();
formInstance.textBox1.Text = "3";
Related
I have a problem that when executing this code in my winform application, it runs normally but when running on the console it gets an error message, it seems that KeyEventHandler is only used in winform, yes What can be replaced in the console application. Here is my hook function:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace Websevice_Core_Console
{
class Y2KeyboardHook
{
#region Win32 API Functions and Constants
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
KeyboardHookDelegate lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x101;
#endregion
private KeyboardHookDelegate _hookProc;
private IntPtr _hookHandle = IntPtr.Zero;
public delegate IntPtr KeyboardHookDelegate(int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardHookStruct
{
public int VirtualKeyCode;
public int ScanCode;
public int Flags;
public int Time;
public int ExtraInfo;
}
#region Keyboard Events
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion
// destructor
~Y2KeyboardHook()
{
Uninstall();
}
public void Install()
{
_hookProc = KeyboardHookProc;
_hookHandle = SetupHook(_hookProc);
if (_hookHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private IntPtr SetupHook(KeyboardHookDelegate hookProc)
{
IntPtr hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
KeyboardHookStruct kbStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (wParam == (IntPtr)WM_KEYDOWN)
{
if (KeyDown != null)
KeyDown(null, new KeyEventArgs((Keys)kbStruct.VirtualKeyCode));
}
else if (wParam == (IntPtr)WM_KEYUP)
{
if (KeyUp != null)
KeyUp(null, new KeyEventArgs((Keys)kbStruct.VirtualKeyCode));
}
}
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
}
public void Uninstall()
{
UnhookWindowsHookEx(_hookHandle);
}
}
}
Here is how I use it:
_y2KeyboardHook.KeyDown += (sender, e) =>// ghi nhan thong tin tu ban phim
{
if (e.KeyCode.ToString() != "")
{
Console.WriteLine("Hello "+KeyCode);
}
}
I got an error message on 2 lines
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
Can anyone help me, thanks a lot!
Given the code you posted and the vague "I got an error message" (which is not an actual question nor a useful problem statement…always be specific), it seems likely you are not referencing System.Windows.Forms.dll. On the other hand, if you aren't referencing the Winforms assembly, it's not clear why you don't also get an error where you use KeyEventArgs, since that's defined in the same assembly.
That said, assuming the error you're getting for your use of KeyEventHandler is simply that it's not defined, you can define the same type for your own use:
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
I.e., just copy the delegate type declaration from the documentation.
Now, all that said, if you aren't referencing the Winforms assembly, and you are getting an error message as expected with the KeyEventArgs type as well, as would be expected, you might want to consider not copying the Winforms implementation of this approach, and just declaring your own event args type with your own event handler. The only thing you're returning is the virtual key code, so you might as well define your own types for that:
class KeyboardHookEventArgs : EventArgs
{
public int VirtualKeyCode { get; }
public KeyboardHookEventArgs(int virtualKeyCode)
{
VirtualKeyCode = virtualKeyCode;
}
}
…then the events:
public event EventHandler<KeyboardHookEventArgs> KeyDown;
public event EventHandler<KeyboardHookEventArgs> KeyUp;
Where you create the args object like new KeyboardHookEventArgs(kbStruct.VirtualKeyCode) instead.
Note that your event-raising implementation is not thread-safe. It would be more safe, and more idiomatic in C#, to use the null-conditional operator, e.g.:
if (wParam == (IntPtr)WM_KEYDOWN)
{
KeyDown?.Invoke(this, new KeyboardHookEventArgs(kbStruct.VirtualKeyCode));
}
You should also pass a correct value for sender, i.e. this as I've shown above. If you want for the event to have no sender, then it (and the rest of the class) should just be static.
It seems like I am missing something fundamental, from my application, upgraded from VB6. All I want to do, is for it to receive SendMessage messages from another application.
The older VB6 application works, however, I found that in the .Net world, overriding the WndProc(ref Message m) method doesn't work. Note, I do see messages, coming from withing the same application, e.g. if I move the mouse inside the window.
I tried mimicking what the VB6 did, i.e. using the SetWindowLong , CallWindowProc, etc... and doesn't work either.
I have sparsely read about DLL injecting (P/Invoking SetWindowLong and CallWindowProc in managed code (compact framework)) but can't seem to move forward on it.
Is this actually possible in .Net? I would hope someone can point me to the right direction.
UPDATE: There is a topic in MSDN about this. Here is the link: https://learn.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy
But this is in C++. I'm wondering if this is possible in .NET
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsAppMessage
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//HandleCreated += Form1_HandleCreated;
}
protected override void WndProc(ref Message m)
{
Console.WriteLine(m.ToString());
// Listen for operating system messages or from other applications
base.WndProc(ref m);
}
/*
private void Form1_HandleCreated(object sender, EventArgs e)
{
_handle = this.Handle;
Attach();
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll")]
public static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
private delegate int WindowProc(IntPtr hWnd, int Msg, int wParam, int lParam);
private const int GWL_WNDPROC = -4;
private IntPtr _handle;
private IntPtr _oldCallback;
private WindowProc _newCallback;
public void Attach()
{
_newCallback = WndProc; // Pins WndProc - will not be garbage collected.
_oldCallback = SetWindowLong(_handle, GWL_WNDPROC,
Marshal.GetFunctionPointerForDelegate(_newCallback));
// Just to be sure...
if (_oldCallback == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public void Detach()
{
if (_newCallback == null || _oldCallback == null)
return;
SetWindowLong(_handle, GWL_WNDPROC, _oldCallback);
_newCallback = null;
}
private int WndProc(IntPtr hWnd, int Msg, int wParam, int lParam)
{
Console.WriteLine(Msg.ToString());
// Forward the message to the original WndProc function.
return CallWindowProc(_oldCallback, hWnd, Msg, wParam, lParam);
}
}
*/
}
Just FYI, I solved this issue. The main thing that I lacked, was programmatically enabling the messages from the "other app" from getting thru.
The topic to search is User Interface Privilege Isolation (UIPI), hence the need to explictly call ChangeWindowMessageFilterEx API.
For example:
ChangeWindowMessageFilterEx(this.Handle, Constants.WM_COPYDATA, ChangeWindowMessageFilterExAction.Allow, ref filterStatus);
I hope that you can help me, I have an application that took every key that I press, like a KeyLogger (yeah, I know, is kind a Malware but I used to another thing, good things, very good things. Not for spy someone). When I press the number keys between the letter key and the F's keys (I mean, the keys above the letters, that ones that you may use if you keyboard doesn't have numeric keypad)it write like this :
0123456789
But when I use the NumericPad (that one on the right side of the keyboard) it show like this:
ABCDEFGHIJ
How can I transform the letter to number?
PS: I research about this and I found that I may need to use UnicodeEncodig.Unicode but I don't know how to use it.
This is the class that capture the keys:
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
// This is the Constructor. This is the code that runs every time you create a new GlobalKeyboardHook object
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
// This starts the hook. You can leave this as comment and you have to start it manually (the thing I do in the tutorial, with the button)
// Or delete the comment mark and your hook will start automatically when your program starts (because a new GlobalKeyboardHook object is created)
// That's why there are duplicates, because you start it twice! I'm sorry, I haven't noticed this...
hook(); <-- Choose!
}
~GlobalKeyboardHook()
{ unhook(); }
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
}
Second Edit, Here is where I use gHook_KeyDown:
GlobalKeyboardHook gHook;
private void Form1_Load(object sender, EventArgs e)
{
gHook = new GlobalKeyboardHook();
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
foreach(Keys key in Enum.GetValues(typeof(Keys)))
ghook.HookedKeys.Add(key);
}
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
textBox1.Text += ((char)e.KeyValue).ToString();
}
I have a block of code like:
IntPtr hWnd = new WindowInteropHelper(this).Handle;
HwndSource source = HwndSource.FromHwnd(hWnd);
source.AddHook(new HwndSourceHook(WndProc));
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_CALL, IntPtr.Zero, IntPtr.Zero);
This was originally in a WPF application. However, I need to replicate the functionality in a WinForms application. Also, NativeMethods.PostMessage just maps to user32.dll PostMessage:
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
Are there a 1 to 1 equivalents of WindowInteropHelper/HwndSource/HwndSourceHook that I can use in my WinForms applications?
The basic point is: you don't need anything except AddHook from your source. Each WinForm has a method GetHandle() which will give you the handle of the Window/Form (and you found PostMessage already by yourself).
Too translate AddHook you either write your own class implementing IMessageFilter (1) or you override WndProc() (2).
(1) will receive messages application-wide, regardless to which form you send them while (2) only receives messages for the specific form overriding the method.
I could'nt find anything regarding WM_CALL, as you have to specify the window message as an integer (usually in hex), so this is up to you.
(1):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
//private const int WM_xxx = 0x0;
//you have to know for which event you wanna register
public Form1()
{
InitializeComponent();
IntPtr hWnd = this.Handle;
Application.AddMessageFilter(new MyMessageFilter());
PostMessage(hWnd, WM_xxx, IntPtr.Zero, IntPtr.Zero);
}
}
class MyMessageFilter : IMessageFilter
{
//private const int WM_xxx = 0x0;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_xxx)
{
//code to handle the message
}
return false;
}
}
(2):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class Form 1 {
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
//private const int WM_xxx = 0x0;
//you have to know for which event you wanna register
public Form1()
{
InitializeComponent();
IntPtr hWnd = this.Handle;
PostMessage(hWnd, WM_xxx, IntPtr.Zero, IntPtr.Zero);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WMK_xxx)
{
//code to handle the message
}
}
}
Am not more of WPF background. but for me it sounds like you're looking for NativeWindow.
I made an application that needs to handle specific keyboard presses even when the window is not active, now I have this and it works great; however the handled keys are still being propagated to windows (not sure if my app is handling them first, so I may be backwards about that).
Is there any way to have it so my app can handle the key presses I want but not have the keys be sent to the current application/windows.
EX) I have my app open in the background monitoring the number pad for presses, every time I press a number key on the number pad I want to add that number to a text box for display purposes. Now I have chrome open and have the cursor in the address bar, I want to be able to press the number keys while having my app handle them but not having them show up in chromes address bar.
Thanks.
This is basically a very simplistic key logger.
EDIT)
Keyboard Hook
#endregion
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
hook();
}
~GlobalKeyboardHook()
{ unhook(); }
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
}
Usage of GlobalKeyboardHook
GlobalKeyboardHook gHook;
private void Form1_Load(object sender, EventArgs e)
{
gHook = new GlobalKeyboardHook(); // Create a new GlobalKeyboardHook
// Declare a KeyDown Event
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
// Add the keys you want to hook to the HookedKeys list
foreach (Keys key in Enum.GetValues(typeof(Keys)))
gHook.HookedKeys.Add(key);
}
// Handle the KeyDown Event
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
textBox1.Text += ((char)e.KeyValue).ToString();
}
private void button1_Click(object sender, EventArgs e)
{
gHook.hook();
}
private void button2_Click(object sender, EventArgs e)
{
gHook.unhook();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
gHook.unhook();
}
In your hookProc, you must not call return CallNextHookEx(Hook, Code, wParam, ref lParam); if you dont want the WM_KEYS to propagate.
If you do call CallNextHookEx, the messages will be propagated.
Btw, you are aware that you are using a Global hook, and not a thread specific hook ? So you are capturing ALL key presses, and not only the ones relative to your app.