代码在发布模式下工作,但在调试配置中引发错误

时间:2019-11-19 23:09:14

标签: c# .net-core

我整理了从@Chris Taylor.

获得的系统级键盘快捷键的代码

我希望它可以在.NETCoreApp 3.0中工作,因为根据MS docsSystem.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!");
      }
   }
}

1 个答案:

答案 0 :(得分:1)

  

在Debug配置下运行该应用程序后,它会崩溃[...]但是,如果在Release配置下运行,它可以正常运行而没有错误。

这是一个半猜测,但是也许您得到了无效的代码?

即时编译器和常规编译器优化程序喜欢删掉无效代码。但是,它们在发布和调试模式之间的优化差异很大。通常在“调试”模式下“积极得多”。因此,在“发行版”中可能被剪切为“死代码”的代码可能仍处于“调试”模式。

使事情变得更难的是,您还混入了多线程。众所周知,这种优化会引起问题。确实,这就是诸如Volatile Keyword之类的东西存在的原因。