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. :)
Related
Workflow of my app:
Run -> LoginPage -> MainPage(Hotkey registered)
Hotkey logic of MainPage:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(this);
IntPtr handle = new WindowInteropHelper(window).Handle;
RegisterHotKey(handle, 48000, 1, 123);
Debug.WriteLine("Hotkey Registered");
}
Hotkey logic of MainWindow:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
internal IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 786)
{
int key = ((int)lParam >> 16) & 0xFFFF;
int modifierKey = (int)lParam & 0xFFFF;
if ((modifierKey == 1) && (key == 123)) // Pressed Alt+F12
{
// Do something...
}
}
return IntPtr.Zero;
}
I implemented global hotkey in the MainWindow of WPF app using user32.dll. I want to write code displaying a screenshot taken from pressing Alt+PrtScn on the Image control of MainPage when GlobalHotkey is pressed. However, Global hotkey is handled by MainWindow, and I need to modify the source of the Image control. How can I write the proper code(using ViewModel)?
Adding the hook/event handler should be done in the view (window). It's not different from raising any other event in response to for example a key press or a mouse click. It's your application logic that should reside in the view model.
In your hook, you could call a method of the view model, e.g.:
internal IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
var viewModel = DataContext as YourViewModel;
if (viewModel != null)
viewModel.HandleEvent(msg);
return IntPtr.Zero;
}
So in short, the event is raised in the view but your logic to handle the event is defined in the view model.
MVVM is not about eliminating code from the views. It's about separation of concerns.
I am trying to make a taskbar app with WPF and I need to be able to react to windows being created and destroyed. In winforms, one way of doing this is to override the WndProc procedure to be able to receive and process Windows messages and I am trying to do the same in WPF.
After searching around and fiddling with the code for a week, I just can't get the thing to work.
I only get some messages when the app first starts up and I may get some messages only when opening a new explorer window although the message itself is never the "window created" message. Apart from that, the WndProc function is never called no matter how many windows I open, switch to or close.
I tried following the answers from Getting Wndproc events to work with WPF?, from How to handle WndProc messages in WPF? , several other websites from search results as well as the "MVVM-Compliant way" described in this blog post which is also referenced in one of the answers on stackoverflow.
By all accounts, this should work but it just doesn't. I tried it on two different computers, both running Windows 10 and the behavior is the same. WndPorc is just not called.
Here is some of the code I tried to use as well as a link to the zipped VS project:
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
// Or
// private void Window_Loaded(object sender, RoutedEventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
// Or
// HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
// source.AddHook(new HwndSourceHook(WndProc));
// Or
// HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(Application.Current.MainWindow).Handle);
// source.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
System.Diagnostics.Debug.Write(string.Format("{0}; {1}; {2}; {3}; {4}",
hwnd.ToString(), msg, wParam, lParam, handled));
switch (wParam.ToInt32())
{
// For window created
case 1:
System.Diagnostics.Debug.Write(" window created");
break;
}
System.Diagnostics.Debug.WriteLine("");
return IntPtr.Zero;
}
Here is an example of a WPF window that handles external window being created and destroyed:
public partial class MainWindow : Window
{
[DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll")]
public static extern bool RegisterShellHookWindow(IntPtr handle);
private static int _msg;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr handle = new WindowInteropHelper(this).Handle;
_msg = RegisterWindowMessage("SHELLHOOK");
RegisterShellHookWindow(handle);
HwndSource source = HwndSource.FromHwnd(handle);
source.AddHook(new HwndSourceHook(WndProc));
}
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == _msg)
{
switch (wParam.ToInt32())
{
case 1:
//window created
break;
case 2:
//window destroyed
break;
}
}
return IntPtr.Zero;
}
}
The issue was the fact that I ran my tests after killing explorer.exe. I'm not sure why but if you kill that, you no longer receive any messages.
After looking at the source code for Cairo shell, I found this line which calls an undocumented Win32 function SetTaskmanWindow. After calling this function right when initializing my code, I can now receive messages from Windows again. The code would now be:
...
base.OnSourceInitialized(e);
var handle = new WindowInteropHelper(this).Handle;
SetTaskmanWindow(handle);
HwndSource source = HwndSource.FromHwnd(handle);
source.AddHook(new HwndSourceHook(WndProc));
...
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?
I want to add to my WPF application the ability to monitor Clipboard changes.
But also I want to filter only Clipboard changes that happens in my app.
So I wrote the following code in one of the main view models,
this VM inherits from
Conductor<IScreen>
of Caliburn.Micro.
The code:
protected override void OnActivate()
{
base.OnActivate();
ScreenExtensions.TryActivate(ChildWindow);
BuildClipboard();
GotoLogin();
}
private void BuildClipboard()
{
_windowHandle = (new WindowInteropHelper(Application.Current.MainWindow)).EnsureHandle();
_hWndSource = HwndSource.FromHwnd(_windowHandle);
_hWndSource.AddHook(new HwndSourceHook(WndProc));
SetClipboardViewer(_windowHandle);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
try
{
if (_windowHandle == hwnd && msg == WM_DRAWCLIPBOARD)
{
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
/////
}
}
}
catch(Exception
{
///
}
}
protected override void OnDeactivate(bool close)
{
_hWndSource.RemoveHook(new HwndSourceHook(WndProc));
_windowHandle = IntPtr.Zero;
ScreenExtensions.TryDeactivate(ChildWindow, close);
base.OnDeactivate(close);
....
}
I have some problems:
First, the line
if (_windowHandle == hwnd && msg == WM_DRAWCLIPBOARD)
does not help to get the behavior I want. For some reason hwnd always have the same int value, even if I copy things from Word and not from my app.
Second problem, each time I restart my app, when my app starts it gets to WndProc method with the value of a copy I made before I restarted my app. off curse It's not the behavior I want.
I hope you can help me,
Thank you, Anat
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.