I've been trying to figure this out for a very long time now; I've searched this several times and read more articles and questions on this than I can recall and I can't seem to figure out exactly what's going wrong. This is a small program that I've been trying to compile to test generating a hotkey to be used by an application.
The source for the test I've been trying to figure out is as follows:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static Form f1 = new Form();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
f1.ShowDialog();
Register(f1);
}
}
}
I have been compiling with csc.exe using C# 4.0. Every time I try and compile this, or similar code, I keep getting this error:
Main.csx(37,27): error CS0115:
'Prg.MainClass.WndProc(System.Windows.Forms.Message)': no suitable method found to override
Every example of using User32.dll to register a hotkey has had the "protected override WndProc" method inside it and everyone has been saying it worked just fine for them, but I can't figure out why it won't work for the life of me. If someone could help me solve this problem it would be greatly appreciated. I'm using Windows 7 Professional 64-bit, and the path to csc.exe is C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe
Thanks :)
Edit
I've gotten it to compile now, However the issue now is that it doesn't seem to be registering and kind of hotkey or at least not picking up the KeyPress at all. Is there an error in my code?
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass : Form
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static Form f1 = new Form();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
f1.ShowDialog();
Register(f1);
}
}
}
I've tried several different solutions but none of them have gotten the Hot Key to work at all. I've even tried re-writing the source to use Application.Run(new MainClass()); but it still didn't detect the Keypress even when the form was focused.
Edit
The Problem is solved thanks to zzxyz for helping get it to compile, and Antoine for helping me fix my mistakes in the code. Thanks guys. This is the code that compiles and works, for anyone who may have had the same problems or just prefers to learn by example. Thanks again.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass : Form
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static MainClass f1 = new MainClass();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
Register(f1);
f1.ShowDialog();
}
}
}
2 mistakes:
you must register the hotkeys before showing your f1. Swap the last 2 lines
currently, you override WndProc for MainClass, not for every form. So your form f1 inherits the base Form.WndProc, not your overriden one. So just declare f1 as MainClass, and it will work.
Related
(I am an novice/beginner when it comes to C# and Winform)
I have a Windows Forms application with 2 forms. The first form is transparent and is just there to show and hide the second form. The second form is an "Overlay" with some buttons. I have a hotkey to open the second form but I can't get it to close the second form with a hotkey. I have tried some different things and googled a lot. The purpose with this application is to open the overlay menu and from that menu you can switch between applications.
Form1.cs
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;
using System.Diagnostics;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
//Click thurgh
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr Hwnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
//
//Hotkey
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
private IntPtr thisWindow;
private Hotkey hotkey;
//
FormOverlay frm = new FormOverlay();
public Form1()
{
InitializeComponent();
this.BackColor = Color.LimeGreen;
this.TransparencyKey = Color.LimeGreen;
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
int initialStyle = GetWindowLong(this.Handle, -20);
SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
}
private void Form1_Load(object sender, EventArgs e)
{
thisWindow = FindWindow(null, "Form1");
hotkey = new Hotkey(thisWindow);
hotkey.RegisterHotKeys();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
hotkey.UnRegisterHotKeys();
}
protected override void WndProc(ref Message keyPressed)
{
Process[] pname = Process.GetProcessesByName("FormOverlay");
if (keyPressed.Msg == 0x0312)
{
if (pname.Length > 0) //my latest try
{
frm.Hide();
MessageBox.Show("1");
}
else
{
frm.Show();
}
}
base.WndProc(ref keyPressed);
}
}
}
Hotkey.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
class Hotkey
{
public enum fsModifiers
{
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Window = 0x0008,
}
private IntPtr _hWnd;
public Hotkey(IntPtr hWnd)
{
this._hWnd = hWnd;
}
public void RegisterHotKeys()
{
RegisterHotKey(_hWnd, 1, (uint)fsModifiers.Control, (uint)Keys.G);
}
public void UnRegisterHotKeys()
{
UnregisterHotKey(_hWnd, 1);
UnregisterHotKey(_hWnd, 2);
}
#region WindowsAPI
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
#endregion
}
}
If you have any documentation, article, video or tutorial that contains your answer please post it, too, so I don't ask too many questions in the comments.
I am trying to make a Windows Forms Application be able to repeatedly show and then hide itself.
The idea is to create a small app that overlays an image on the screen every time a modifier key like Num Lock or Caps lock is pressed. I have the detection of the keyboard keys working flawlessly, but I am not having much luck with creating a form that I can show and then hide repeatedly.
The way I see it, (please correct me if I'm wrong) there are two possible ways to make the form behave like I want it to:
Start the form normally in Program.cs and then hold the logic for hiding and showing the form and displaying the image inside Form1.cs
The form would call this.Hide() and this.Show() to hide and show itself, but whenever I try to do this, I cannot get this.Hide() to hide the form; the form remains visible on top of all of the open windows.
Hold the logic for hiding and showing the form in Program.cs and then just hold the logic to display the image in Form1.cs
I've been toying around with the code from this guide to show and hide the from from Program.cs with a class wrapper for the form, but as it turns out, form.Showdialog() prevents any further code execution until the form is closed.
I've been playing around with the code myself, and neither of the above methods have worked. Am I thinking about this in the wrong way entierly? Can a WFA ever behave in the way I want it to?
The code for this is a bit messy, and I'm not sure what parts are the most relevant here, but I'll do my best to include it here:
Program.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace KeyboardIndicators {
// ApplicationContext wrapper
public abstract class TrayIconApplicationContext : ApplicationContext {
private NotifyIcon lockIcon;
private ContextMenu lockIconContext;
protected TrayIconApplicationContext() {
// Wire up the ApplicationExitHandler to ApplicationExit events
Application.ApplicationExit += this.ApplicationExitHandler;
lockIconContext = new ContextMenu {
};
// Create lockIcon tray icon and make it visible
lockIcon = new NotifyIcon {
ContextMenu = lockIconContext,
Text = Application.ProductName,
Icon = new Icon("icon.ico"),
Visible = true
};
}
protected NotifyIcon LockIcon { get { return lockIcon; } }
protected ContextMenu LockIconContext { get { return lockIconContext; } }
// ApplicationExit event handler
private void ApplicationExitHandler(object sender, EventArgs e) {
this.OnApplicationExit(e);
}
// Performs cleanup to end the application
protected virtual void OnApplicationExit(EventArgs e) {
// TODO(Neil): Add meaningful thread cleanup here soon
if (lockIcon != null) {
lockIcon.Visible = false;
lockIcon.Dispose();
}
if (lockIconContext != null)
LockIconContext.Dispose();
}
}
// TrayIconApplicationContext wrapper for Form1 to control the activation of the form window
class FormApplicationContext : TrayIconApplicationContext {
public FormApplicationContext() {
// Add Exit menu item
MenuItem exit = new MenuItem("E&xit");
this.LockIconContext.MenuItems.Add(exit);
exit.Click += this.ExitContextMenuClickHandler;
//KeyboardIndicators indicators = new KeyboardIndicators();
//indicators.RunListener();
{
using(Form form = new Form1("NumLock", true))
form.ShowDialog();
}
}
private void ExitContextMenuClickHandler(object sender, EventArgs eventArgs) {
this.ExitThread();
}
}
public class KeyboardIndicators {
class LockState {
// Is the numlock key on?
public bool Num;
// Is the capslock key on?
public bool Caps;
// Is the scroll lock key on?
public bool Scroll;
}
public void RunListener() {
try {
// Store the old keyboard lock state
LockState prevState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
while (true) {
// Store the new keyboard lock state
LockState newState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
//TODO(Neil): Handle simultaneous presses better, i.e. queue the balloon tips
if (newState.Num != prevState.Num) {
Form1 form = new Form1("NumLock", newState.Num);
} else if (newState.Caps != prevState.Caps) {
Form1 form = new Form1("CapsLock", newState.Caps);
} else if (newState.Scroll != prevState.Scroll) {
Form1 form = new Form1("ScrollLock", newState.Scroll);
}
// Set the previous lock state to the new one in prep for the next iteration
prevState = newState;
// Sleep for 500ms
Thread.Sleep(500);
}
} catch (ThreadAbortException) { /* No need to do anything, just catch the ThreadAbortException.*/ }
}
}
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1("NumLock", true));
Application.Run(new FormApplicationContext());
}
}
}
Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1(String activatedModifier, bool lockState) {
InitializeComponent();
ShowForm(activatedModifier);
//this.Show();
//this.Hide();
}
public void ShowForm(String activatedModifier) {
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
switch (activatedModifier) {
case "NumLock":
break;
case "CapsLock":
break;
case "ScrollLock":
break;
}
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}
As an example I have created a Winforms Application which displays "NUM" and / or "CAPS" if any of those keys is pressed otherwise the form is hidden.
The detection of the keys is based on the C# Low Level Keyboard Hook.
Program.cs
using System;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs
Note: Add a label named 'label1' to Form1 in Designer.
using System.Collections.Generic;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public partial class Form1 : Form
{
private static bool _caps;
private static bool _num;
public Form1()
{
InitializeComponent();
KeyboardHook kh = new KeyboardHook();
kh.KeysToObserve.AddRange(new List<Keys> { Keys.CapsLock, Keys.NumLock });
kh.InstallHook();
kh.KeyDown = key => ProcessKeyDown(key);
_caps = Control.IsKeyLocked(Keys.CapsLock);
_num = Control.IsKeyLocked(Keys.NumLock);
}
private void ProcessKeyDown(Keys key)
{
if (key == Keys.CapsLock)
{
_caps = !_caps;
}
if (key == Keys.NumLock)
{
_num = !_num;
}
this.ShowState(_num, _caps);
}
internal void ShowState(bool num, bool caps)
{
if (!num && !caps)
{
this.Hide();
return;
}
this.label1.Text = "";
this.label1.Text += num ? "NUM " : "";
this.label1.Text += caps ? "CAPS" : "";
if (!this.Visible)
{
this.Show();
}
}
}
}
KeyboardHook.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public class KeyboardHook
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private IntPtr _hookID = IntPtr.Zero;
public List<Keys> KeysToObserve { get; set; } = new List<Keys>();
public Action<Keys> KeyDown;
public void InstallHook()
{
_hookID = SetHook(HookCallback);
}
~KeyboardHook()
{
UnhookWindowsHookEx(_hookID);
}
public IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
var key = (Keys)vkCode;
Console.WriteLine(key);
KeyDown(key);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
Here is what im trying to do:
There is some game which writes some info about item under mouse cursor into clipboard when i press Ctrl-C. Im trying to grab that info and select some stuff i need from it.
Im doing it like this:
//at form load
RegisterHotKey(this.Handle, 0, 0x002, (int)Keys.C);
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 0)
{
System.Threading.Thread.Sleep(155); //ive thought if i add some delay it would help but it doesnt...
string textFromClipboard = Clipboard.GetText();
if (textFromClipboard.Contains("Itemlevel: "))
{
// do some stuff with data IF it exists in clipboard, doesnt important what i do - i never get here
}
}
}
base.WndProc(ref m);
}
So basically, when i press Ctrl-C in-game without this program on - all works fine, info copied in clipboard. When i turn program on - clipboard stays same as it was before i press Ctrl-C in-game. How do i prevent this? How do i get text from clipboard correctly? Maybe the way i get this text is wrong? Or maybe that registered hotkey interferes with game hotkey so it doesn't work anymore?
update:
Ive figured out some simple solution, but very rough and barbaric. But it works fine.
public static void KeyDown(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0x45, 0x0001 | 0, 0);
}
public static void KeyUp(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0x45, 0x0001 | 0x0002, 0);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 0)
{
ToggleHotkeys(false);
KeyDown(Keys.Control);
KeyDown(Keys.C);
KeyUp(Keys.C);
KeyUp(Keys.Control);
System.Threading.Thread.Sleep(155);
//if i comment this sleep - code executes too fast, making first Ctrl-C press
//capture nothing, second press outputs results for first item
//third press - for second item, ...
string textFromClipboard = Clipboard.GetText();
if (textFromClipboard.Contains("Itemlevel: "))
{
//do stuff with data
}
ToggleHotkeys(true);
}
}
base.WndProc(ref m);
}
Maybe there is more clever way to solve this problem?
I would use a ClipBoard monitor so you can get notified whenever the ClipBoard changes:
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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
private ClipBoardMonitor cbm = null;
public Form1()
{
InitializeComponent();
cbm = new ClipBoardMonitor();
cbm.NewText += cbm_NewText;
}
private void cbm_NewText(string txt)
{
Console.WriteLine(txt);
}
}
public class ClipBoardMonitor : NativeWindow
{
private const int WM_DESTROY = 0x2;
private const int WM_DRAWCLIPBOARD = 0x308;
private const int WM_CHANGECBCHAIN = 0x30d;
[DllImport("user32.dll")]
static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll")]
static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public event NewTextEventHandler NewText;
public delegate void NewTextEventHandler(string txt);
private IntPtr NextClipBoardViewerHandle;
public ClipBoardMonitor()
{
this.CreateHandle(new CreateParams());
NextClipBoardViewerHandle = SetClipboardViewer(this.Handle);
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
if (Clipboard.ContainsText())
{
if (NewText != null)
{
NewText(Clipboard.GetText());
}
}
SendMessage(NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam.Equals(NextClipBoardViewerHandle))
{
NextClipBoardViewerHandle = m.LParam;
}
else if (!NextClipBoardViewerHandle.Equals(IntPtr.Zero))
{
SendMessage(NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);
}
break;
case WM_DESTROY:
ChangeClipboardChain(this.Handle, NextClipBoardViewerHandle);
break;
}
base.WndProc(ref m);
}
}
}
I was looking for a possibility to be notified in a .NET windows application when any window is activated in the OS (Windows XP 32-bit). On CodeProject I have found a solution by using global system hooks.
http://www.codeproject.com/Articles/18638/Using-Window-Messages-to-Implement-Global-System-H .
Here is a short summary of this procedure:
In an unmanaged assembly (written in C++) a method is implemented which installs the WH_CBT hook.
bool InitializeCbtHook(int threadID, HWND destination)
{
if (g_appInstance == NULL)
{
return false;
}
if (GetProp(GetDesktopWindow(), " HOOK_HWND_CBT") != NULL)
{
SendNotifyMessage((HWND)GetProp(GetDesktopWindow(), "HOOK_HWND_CBT"),
RegisterWindowMessage("HOOK_CBT_REPLACED"), 0, 0);
}
SetProp(GetDesktopWindow(), " HOOK_HWND_CBT", destination);
hookCbt = SetWindowsHookEx(WH_CBT, (HOOKPROC)CbtHookCallback, g_appInstance, threadID);
return hookCbt != NULL;
}
In the callback method (filter function) depending on the hook type windows messages are sent to a destination window.
static LRESULT CALLBACK CbtHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code >= 0)
{
UINT msg = 0;
if (code == HCBT_ACTIVATE)
msg = RegisterWindowMessage("HOOK_HCBT_ACTIVATE");
else if (code == HCBT_CREATEWND)
msg = RegisterWindowMessage("HOOK_HCBT_CREATEWND");
else if (code == HCBT_DESTROYWND)
msg = RegisterWindowMessage("HOOK_HCBT_DESTROYWND");
else if (code == HCBT_MINMAX)
msg = RegisterWindowMessage("HOOK_HCBT_MINMAX");
else if (code == HCBT_MOVESIZE)
msg = RegisterWindowMessage("HOOK_HCBT_MOVESIZE");
else if (code == HCBT_SETFOCUS)
msg = RegisterWindowMessage("HOOK_HCBT_SETFOCUS");
else if (code == HCBT_SYSCOMMAND)
msg = RegisterWindowMessage("HOOK_HCBT_SYSCOMMAND");
HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), HOOK_HWND_CBT");
if (msg != 0)
SendNotifyMessage(dstWnd, msg, wparam, lparam);
}
return CallNextHookEx(hookCbt, code, wparam, lparam);
}
To use this assembly in a .NET Windows Application the following method has to be imported:
[DllImport("GlobalCbtHook.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitializeCbtHook (int threadID, IntPtr DestWindow);
[DllImport("GlobalCbtHook.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void UninitializeCbtHook(int hookType);
After calling InitializeCbtHook the messages received from GlobalCbtHook.dll can be processed in:
protected override void WndProc(ref Message msg)
The messages have to be registered in both the assembly and the application by calling
RegisterWindowMessage.
[DllImport("user32.dll")]
private static extern int RegisterWindowMessage(string lpString);
This implementation works fine. But in most cases when I activate Microsoft Office Outlook
my .NET Application receives the activate-event after I minimize Outlook or activate an other window. At first I thought that my .NET wrapper is the cause of the problem. But after I used the sources from the above link I could recognized the same behaviour.
My actually workaround is to use WH_SHELL hook. I know that one difference between WH_CBT and WH_SHELL hook is when using WH_CBT hook it is possible to interrupt the filter function chain by not calling the CallNextHookEx method. Could this play a role in my problem?
Please provide help.
obviously the hooking does not work in cases of outlook - what about other microsoft products (word, power point ...)??
but, why hooking? this little class will work even if outlook is activated
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsMonitor
{
public class ActiveWindowChangedEventArgs : EventArgs
{
public IntPtr CurrentActiveWindow { get; private set; }
public IntPtr LastActiveWindow { get; private set; }
public ActiveWindowChangedEventArgs(IntPtr lastActiveWindow, IntPtr currentActiveWindow)
{
this.LastActiveWindow = lastActiveWindow;
this.CurrentActiveWindow = currentActiveWindow;
}
}
public delegate void ActiveWindowChangedEventHandler(object sender, ActiveWindowChangedEventArgs e);
public class ActiveWindowMonitor
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private Timer monitorTimer;
public IntPtr ActiveWindow { get; private set; }
public event ActiveWindowChangedEventHandler ActiveWindowChanged;
public ActiveWindowMonitor()
{
this.monitorTimer = new Timer();
this.monitorTimer.Tick += new EventHandler(monitorTimer_Tick);
this.monitorTimer.Interval = 10;
this.monitorTimer.Start();
}
private void monitorTimer_Tick(object sender, EventArgs e)
{
CheckActiveWindow();
}
private void CheckActiveWindow()
{
IntPtr currentActiveWindow = GetForegroundWindow();
if (this.ActiveWindow != currentActiveWindow)
{
IntPtr lastActiveWindow = this.ActiveWindow;
this.ActiveWindow = currentActiveWindow;
OnActiveWindowChanged(lastActiveWindow, this.ActiveWindow);
}
}
protected virtual void OnActiveWindowChanged(IntPtr lastActiveWindow, IntPtr currentActiveWindow)
{
ActiveWindowChangedEventHandler temp = ActiveWindowChanged;
if (temp != null)
{
temp.Invoke(this, new ActiveWindowChangedEventArgs(lastActiveWindow, currentActiveWindow));
}
}
}
}
usage
public void InitActiveWindowMonitor()
{
WindowsMonitor.ActiveWindowMonitor monitor = new WindowsMonitor.ActiveWindowMonitor();
monitor.ActiveWindowChanged += new WindowsMonitor.ActiveWindowChangedEventHandler(monitor_ActiveWindowChanged);
}
private void monitor_ActiveWindowChanged(object sender, WindowsMonitor.ActiveWindowChangedEventArgs e)
{
//ouh a window got activated
}
The program is working at background and listening keyboard(like keylogger)
First I select a string on pdf or etc. Then I pressed the ctrl + rbutton the program must be pop up and it can be get my selected string.
For this;
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Int32 vKey);
string key = "";
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Interval = 5;
foreach (System.Int32 i in Enum.GetValues(typeof(Keys)))
{
int x = GetAsyncKeyState(i);
if ((x == 1) || (x == -32767))
{
keyBuffer += Enum.GetName(typeof(Keys), i);
}
}
if (keyBuffer != "")
{
keyBuffer = keyBuffer.ToLower();
if (keyBuffer.Contains("lcontrolkeyrbutton"))
{
// do somethings
keyBuffer = "";
}
}
}
But after first performing, ctrl + rbutton it doesn't work. What's the wrong? And how can i get the selected string into my program?
Sounds like you want a clipboard hook (in addition to your global key hook). Take a look here: Clipboard event C#
If you want to capture the string without the user copying it into the clipboard manually, you could send ctrl+c to the application yourself: http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
You need to SendKeyEvent(Ctrl+C) of MainWindowsHandle First, then Using Clipboard capture your text to your Project.
Here is the program funcional and tested
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;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CtrLetterCopy
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int WM_COMMAND = 0x111;
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public Form1()
{
InitializeComponent();
this.ShowInTaskbar = false;
int id_Ctrl = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id_Ctrl, (int)KeyModifier.Control, Keys.R.GetHashCode());
}
protected override void WndProc(ref Message m)
{
//const int WM_HOTKEY = 0x0312;
if (m.Msg == 0x0312)
{
if (m.WParam.ToInt32() == 0)
{
//do what you want here
SendKeyEvent();
}
}
base.WndProc(ref m);
}
private void SendKeyEvent()
{
SendKeys.SendWait("^c");
Thread.Sleep(500);
string test3 = Clipboard.GetText();
MessageBox.Show(test3);
}
}
}
Download and check out this code here:
http://www.codeproject.com/KB/cs/globalhook.aspx
Pre-tested, well-written and fully functional.
Best of luck!