我整理了从@Chris Taylor.
获得的系统级键盘快捷键的代码我希望它可以在.NETCoreApp 3.0
中工作,因为根据MS docs,System.Windows.Forms.dll
受支持
我在System.Windows.Forms.dll
处添加了对C:\Windows\Microsoft.NET\Framework64\v4.0.30319
的引用(旧版本也适用)。
在这一点上,构建成功,但运行该应用程序引发异常:Could not load file or assembly System.Drawing.Common
,因此我安装了一个小工具System.Drawing.Common
。由于异常,再次重复了一次,并添加了另一个必需的nuget System.Configuration.ConfigurationManager
。
这是开始发生奇怪的事情的地方:在Debug配置中运行该应用程序后,它崩溃并显示为:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at System.Windows.Forms.NativeWindow.AdjustWndProcFlagsFromConfig(Int32 wndProcFlags)
at System.Windows.Forms.NativeWindow.get_WndProcFlags()
at System.Windows.Forms.NativeWindow.get_WndProcShouldBeDebuggable()
at System.Windows.Forms.NativeWindow.AssignHandle(IntPtr handle, Boolean assignUniqueID)
at System.Windows.Forms.NativeWindow.AssignHandle(IntPtr handle)
at System.Windows.Forms.NativeWindow.WindowClass.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
但是,如果在Release配置中运行,它将正常运行。如果选择»bug«图标与调试器一起运行,则效果相同(与选择Debug configuration不同)。我的IDE是Rider,可能相关。如果使用调试器不再抛出错误,该如何调试呢?
我将在下面发布我的所有代码,但这并不是真正需要的,因为它是直接从上面我链接的Chris Taylor的回答中复制的。谁能告诉我这是怎么回事?为什么发布模式可以正常运行,但调试配置不能正常运行?
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp10
{
public static class HotKeyManager
{
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
public static int RegisterHotKey(Keys key, KeyModifiers modifiers)
{
_windowReadyEvent.WaitOne();
int id = System.Threading.Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
return id;
}
public static void UnregisterHotKey(int id)
{
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
}
delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key)
{
RegisterHotKey(hwnd, id, modifiers, key);
}
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id)
{
UnregisterHotKey(_hwnd, id);
}
private static void OnHotKeyPressed(HotKeyEventArgs e)
{
if (HotKeyManager.HotKeyPressed != null)
{
HotKeyManager.HotKeyPressed(null, e);
}
}
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);
static HotKeyManager()
{
Thread messageLoop = new Thread(delegate()
{
Application.Run(new MessageWindow());
});
messageLoop.Name = "MessageLoopThread";
messageLoop.IsBackground = true;
messageLoop.Start();
}
private class MessageWindow : Form
{
public MessageWindow()
{
_wnd = this;
_hwnd = this.Handle;
_windowReadyEvent.Set();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
HotKeyEventArgs e = new HotKeyEventArgs(m.LParam);
HotKeyManager.OnHotKeyPressed(e);
}
base.WndProc(ref m);
}
protected override void SetVisibleCore(bool value)
{
// Ensure the window never becomes visible
base.SetVisibleCore(false);
}
private const int WM_HOTKEY = 0x312;
}
[DllImport("user32", SetLastError=true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int _id = 0;
}
public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
{
this.Key = key;
this.Modifiers = modifiers;
}
public HotKeyEventArgs(IntPtr hotKeyParam)
{
uint param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
}
}
[Flags]
public enum KeyModifiers
{
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
}
我的主要人员:
using System;
using System.Windows.Forms;
namespace ConsoleApp10 {
class Program {
static void Main(string[] args) {
Console.WriteLine("Hello World!");
HotKeyManager.RegisterHotKey(Keys.A, KeyModifiers.Alt);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
Console.ReadLine();
}
static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
{
Console.WriteLine("Hit me!");
}
}
}
答案 0 :(得分:1)
在Debug配置下运行该应用程序后,它会崩溃[...]但是,如果在Release配置下运行,它可以正常运行而没有错误。
这是一个半猜测,但是也许您得到了无效的代码?
即时编译器和常规编译器优化程序喜欢删掉无效代码。但是,它们在发布和调试模式之间的优化差异很大。通常在“调试”模式下“积极得多”。因此,在“发行版”中可能被剪切为“死代码”的代码可能仍处于“调试”模式。
使事情变得更难的是,您还混入了多线程。众所周知,这种优化会引起问题。确实,这就是诸如Volatile Keyword之类的东西存在的原因。