I have an MFC application, but in some places we use WPF. In one case I am working on, we have a WPF Window shown modally, but we are trying to display an MFC based specialized edit control inside the WPF window.
I tried to follow the cookbook and derived my class from HwndHost. I am trying to intercept the WM_NOTIFY message of the control because it sends something like a EN_CHANGED notification through WM_NOTIFY.
I have done two things to try and intercept the method.
1) Override WndProc:
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
switch (msg)
{
case WM_COMMAND:
break;
case WM_NOTIFY:
++NOtifyCount;
break;
}
return IntPtr.Zero;
}
2) Tap into the MessageHook event of HwndHost and have a hook procedure like this:
IntPtr SyntaxEditHost_MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
switch (msg)
{
case WM_COMMAND:
break;
case WM_NOTIFY:
++NOtifyCount;
break;
}
return IntPtr.Zero;
}
If I set a breakpoint in either WM_NOTIFY handler, it never gets hit. If I set a breakpoint inside the C++ code before WM_NOTIFY is sent and then set a breakpoint in the above two methods looking for ANY message, no message is received.
If I look at WM_NOTIFY messages in Spy++, I can verify that the HwndHost is receiving the messages. Everytime I press a key in the editor, the WM_NOTIFY message is received by the HwndHost. However, somehow the WM_NOTIFY messages are getting handled before I get a chance to handle them myself in my override of WndProc or my implementation of the message hook.
Anybody have any ideas? Of course I googled for it and got nothing useful at all.
Related
I'm handling WndProc in my WPF application in order to respond to the event where some other application enters fullscreen. At this time, the main window of my application needs to hide. Here is the code I have written:
Hooking:
HwndSource source = HwndSource.FromHwnd(MyMainWindowHandle);
source.AddHook(this.WndProc);
WndProc:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
Debug.Print("In wndproc");
QUERY_USER_NOTIFICATION_STATE state;
SHQueryUserNotificationState(out state);
if (MyMainWindow.Visibility == Visibility.Visible && state == QUERY_USER_NOTIFICATION_STATE.QUNS_BUSY)
{
Debug.Print("hiding");
MyMainWindow.Hide();
}
else if (MyMainWindow.Visibility == Visibility.Hidden && state != QUERY_USER_NOTIFICATION_STATE.QUNS_BUSY)
{
Debug.Print("showing");
MyMainWindow.Show();
}
return IntPtr.Zero;
}
This works as expected with applications like PowerPoint or Skype. However, when a web browser (Chrome) enters full screen while playing a video, the WndProc is not called when the user exits full screen. It is called and behaves as expected after the user does something else, like click the Windows task bar, etc. Does anyone know why / a workaround to this issue?
Here's the problem:
I wrote a WPF application that uses an Hwnd to host a drawing surface. That hwnd is responsible for sending back mouse events that happen. On my computer, everything works normally and I see the 522(0x020A) mouse wheel message without issue.
I installed this same software on another computer, and the event didn't fire. I went as far as logging all event messages to a file to see if 522 fired at all, and it never showed up.
Things I've tried:
-Making sure the Hwnd has focus. Not only did I make a thread that would re-focus it every second, I made sure that on my computer (working) "IsFocused" was true for that hwnd.
-Closing down any other program running. This included things normal to the computer running in the background, in case something was taking focus off.
-Switching the mouse. I used the mouse I'm using on my computer to be sure, and it still did not work on the new computer.
Here's the base code:
public abstract class Win32HwndControl : HwndHost
{
protected IntPtr Hwnd { get; private set; }
protected bool HwndInitialized { get; private set; }
private const string WindowClass = "HwndWrapper";
protected Win32HwndControl()
{
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
var wndClass = new NativeMethods.WndClassEx();
wndClass.cbSize = (uint)Marshal.SizeOf(wndClass);
wndClass.hInstance = NativeMethods.GetModuleHandle(null);
wndClass.lpfnWndProc = NativeMethods.DefaultWindowProc;
wndClass.lpszClassName = WindowClass;
wndClass.hCursor = NativeMethods.LoadCursor(IntPtr.Zero, NativeMethods.IDC_ARROW);
NativeMethods.RegisterClassEx(ref wndClass);
Hwnd = NativeMethods.CreateWindowEx(
0, WindowClass, "", NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE,
0, 0, (int)Width, (int)Height, hwndParent.Handle, IntPtr.Zero, IntPtr.Zero, 0);
return new HandleRef(this, Hwnd);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case NativeMethods.WM_LBUTTONDOWN:
RaiseMouseEvent(MouseButton.Left, Mouse.MouseDownEvent);
break;
case NativeMethods.WM_LBUTTONUP:
RaiseMouseEvent(MouseButton.Left, Mouse.MouseUpEvent);
break;
case NativeMethods.WM_RBUTTONDOWN:
RaiseMouseEvent(MouseButton.Right, Mouse.MouseDownEvent);
break;
case NativeMethods.WM_RBUTTONUP:
RaiseMouseEvent(MouseButton.Right, Mouse.MouseUpEvent);
break;
case NativeMethods.WM_MOUSEWHEEL:
RaiseMouseWheelEvent(wParam.ToInt32(), Mouse.MouseWheelEvent);
break;
}
return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
}
There is more code to this class, but I've confirmed it is not hitting the WndProc method.
Any tips on why this would be happening on one computer and not the other?
Is there a way to stop system from going to sleep/hibernate mode when user presses e.g. laptop's or tablet's power button or chooses sleep/hibernate from Windows' menu? I've been trying to implement this by using WndProc and Windows' power messages but no luck. Here's the code that I've been using. I also tried to return BROADCAST_QUERY_DENY as IntPtr but no luck.
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x218) // WM_POWERBROADCAST.
{
if (wParam.ToInt32() == 0x4) // PBT_APMSUSPEND.
{
handled = true;
}
}
return IntPtr.Zero;
}
I've also tried PowerCreateRequest and PowerSetRequest but no luck there either.
I have managed to prevent Windows from shutting down by using Microsoft.Win32.SystemEvents.SessionEnding and I thought that this handles power management messages too but I was wrong. :)
Why the WndProc get called multiple times, when a device is plug in, for example USB, the WndProc is called four times:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource src = HwndSource.FromHwnd(windowHandle);
src.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle WM_DEVICECHANGE
if (msg == 0x0219)
{
Thank you
yes it does so, however you may notice different wParam & lParam. For every event WndProc will receive message from OS. The other parameter values after msg will let you know the context in which they are raised.
As stated in title, I have a form that doesn't have any control on itself (so I can't focus it!!! damn).
I keep it controlless because I need to show images on background and I need to move it by keeping mouse clicked.
Are there any way to detect the keyup event when this is the foreground window?should I use a global hook (and check which is the foreground image obviusly)?
Any simplier workaround?I tested with an hidden control but it's not working.
The problem of putting a control with opacity = 0 brings the possibility to "miss" the MouseDown and MouseUp events (because they could happen over the control instead of the form, but I can still redirect them)
Any suggestion?
Here is the question where I picked some resources:
Fire Form KeyPress event
Can't you just set the Form's KeyPreview to true and use the Form's KeyUp Event? (or am i missing something?)
I would override OnKeyUp as it seems to be exactly what you are asking for. Here is an example of popping up a Message Box when the Escape key is released.
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
MessageBox.Show("Escape was pressed");
e.Handled = true;
}
base.OnKeyUp(e);
}
It looks that you are seeking for GlobalHook. Please have a look at SetWindowsHookEx Native Api. You can easily write your Pinvoke statements.
Here is an example from pinvoke.net
using System.Windows.Forms;
public class MyClass
{
private HookProc myCallbackDelegate = null;
public MyClass()
{
// initialize our delegate
this.myCallbackDelegate = new HookProc(this.MyCallbackFunction);
// setup a keyboard hook
SetWindowsHookEx(HookType.WH_KEYBOARD, this.myCallbackDelegate, IntPtr.Zero, AppDomain.GetCurrentThreadId());
}
[DllImport("user32.dll")]
protected static extern IntPtr SetWindowsHookEx(HookType code, HookProc func, IntPtr hInstance, int threadID);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
private int MyCallbackFunction(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0) {
//you need to call CallNextHookEx without further processing
//and return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
// we can convert the 2nd parameter (the key code) to a System.Windows.Forms.Keys enum constant
Keys keyPressed = (Keys)wParam.ToInt32();
Console.WriteLine(keyPressed);
//return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
}