I am trying to write a C# script that runs in background in tray and when triggered by a global hotkey it does some job but I cannot get around setting a hotkey.
The problem is RegisterHotKey returns false and fails no matter what hotkey combination I choose. I tried getting the error code using GetLastWin32Error and it returned 0x000003EC which is ERROR_INVALID_FLAGS but I don't know what flag is actually invalid.
The script:
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyScript
{
public static class Program
{
[DllImport("user32.dll"), SetLastError = true]
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);
private const int HOTKEY_ID = 1;
public static void Main()
{
ToolStripMenuItem exitMenuItem = new("Exit", null, (sender, e) => { Application.Exit(); });
using NotifyIcon notifyIcon = new()
{
Visible = true,
Icon = SystemIcons.Application,
ContextMenuStrip = new ContextMenuStrip()
{
Items = { exitMenuItem },
},
};
using Form form = new()
{
ShowInTaskbar = false,
WindowState = FormWindowState.Minimized,
};
form.Load += (sender, e) => { form.Visible = false; };
var formHandle = form.Handle;
var hotkeyModifiers = (uint)(Keys.Control | Keys.Alt);
var hotkeyKey = (uint)Keys.Z;
if (RegisterHotKey(formHandle, HOTKEY_ID, hotkeyModifiers, hotkeyKey))
{
form.FormClosing += (sender, e) => { UnregisterHotKey(formHandle, HOTKEY_ID); };
Application.AddMessageFilter(new HotkeyMessageFilter(formHandle, async () => await Run()));
}
else
{
MessageBox.Show($"Could not register hotkey. error code: {Marshal.GetLastWin32Error()}");
}
Application.Run(form);
}
private static async Task Run()
{
// do the job
}
private class HotkeyMessageFilter : IMessageFilter
{
private const int WM_HOTKEY = 0x0312;
private readonly IntPtr _formHandle;
private readonly Action _hotkeyAction;
public HotkeyMessageFilter(IntPtr formHandle, Action hotkeyAction)
{
_formHandle = formHandle;
_hotkeyAction = hotkeyAction;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == HOTKEY_ID && m.HWnd == _formHandle)
{
_hotkeyAction();
return true;
}
return false;
}
}
}
}
I would greatly appreciate your help.