如何在.NET中监听Windows广播消息?

时间:2012-02-17 15:03:55

标签: .net windows broadcast

我有一个Object(即不是表格)想要收听来自Windows的广播消息,例如:

.NET中设置非WinForm窗口的机制是什么,可以监听广播消息?

即。有WindowsListener班吗?

Bonus Chatter

在过去,在其他开发环境中,框架提供了AllocateHwnd功能:

HWND listener = AllocateHWnd(ListenerWindowProc);

其中ListenerWindowProc是我的窗口过程方法:

private void ListenerWindowProc(ref Message msg)
{
    switch (msg.msg)
    {
       case WM_SETTINGCHANGE: 
       {
          ...
       }
       break;
       case WM_POWERBROADCAST:
       {
          ...
       }
       break;
       case WM_THEMECHANGED: 
       {
          ...
       }
       break;
       ...
   }
   DefWindowProc(msg);
}

秘诀是AllocateHwnd功能:

的伪代码:

public static HWND AllocateHWnd(WndMethod method)
{
   HWND result;
   WNDCLASS tempClass;
   Boolean classRegistered;

   UtilWindowClass.hInstance := HInstance;
   Boolean classRegistered = GetClassInfo(HInstance, UtilWindowClass.lpszClassName, tempClass);
   if (!classRegistered || (tempClass.lpfnWndProc != @DefWindowProc)
   {
      if classRegistered
      {
         UnregisterClass(utilWindowClass.lpszClassName, HInstance);
         RegisterClass(utilWindowClass);
      }
      result = CreateWindowEx(WS_EX_TOOLWINDOW, UtilWindowClass.lpszClassName,
            '', WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, null);
      if (!Method != null)
         SetWindowLong(result, GWL_WNDPROC, UInt32(MakeObjectInstance(Method)));
   }
}

使用与UtilWindowClass相关联的更多密码。

当你完成后,你会DeallocateHwnd

DeallocateHwnd(listenerWindow);

我知道在.NET框架深处,他们将响应WM_SETTINGCHANGE并更新内部.NET数据结构。我会窃取该代码,但Reflector找不到WM_SETTINGCHANGE的引用;大概是因为反编译的代码没有显示常量名称,只是常量 0x001A

更新

注意:此对象应该是自包含的。使用该类的任何人都不应该修改他们的应用程序,以便我的类返回正确的数据。它应该收听来自Windows本身的广播,而不是要求开发人员修改他们的应用程序来为我监听某些消息(即它不应该破坏困难或复杂操作的封装)

例如:

public class FrobbingGrobber: IDisposable
{
    private IntPtr hwnd = IntPtr.Zero;

    public FrobbingGrobber
    {
       _hwnd = AllocateHwnd(listenerWindowProc);
    }

    protected virtual void listenerWindowProc(ref Message msg)
    {
       switch (msg.msg)
       {
          case WM_DwmColorizationColorChanged, WM_DwmCompositionChanged: 
          {
              UpdateColorizationColor();
          }
          break;
       }
       DefWindowProc(msg);
    }

    public void UpdateColorizationColor()
    {
        NativeMethods.DwmGetColorizationColorParameters_UndocumentedExport137(ref _color);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected void Dispose(Boolean safeToDisposeManagedObjects)
    {
       if (_hwnd != 0)
       {
          DeallocateHwnd(_hwnd);      
          _hwnd = 0;
       }

       if (safeToDisposeManagedObjects)
          GC.SuppressFinalize(this);
    }

    public ~FrobbingGrobber
    {
       //If the user forgot to call Dispose i could (correctly) leak a handle, 
       //or i could fix their mistake for them
       Dispose(false);
    }

1 个答案:

答案 0 :(得分:7)

我认为你给出的例子仅仅是:例子。因为其中许多已经管理了等价物,已经为您包装了所有这些。就像WM_POWERBROADCAST包裹WM_SETTINGCHANGED一样。 WndProc相当于Microsoft.Win32.SystemEvents.PowerModeChanged event

无论如何,您描述的广播消息会被发送到所有顶级窗口,所以您真正需要做的就是创建一个顶级窗口并覆盖其Form方法来处理您的通知消息对此感兴趣。

使用Microsoft.Win32.SystemEvents.UserPreferenceChanged让自己轻松自如。在这种情况下,您不需要CreateWindowEx类提供的所有内容,只需要包装WS_VISIBLE并提供窗口过程即可。只需创建没有TimerNativeWindow标志的窗口,因为您不希望它出现在屏幕上。

.NET Framework在内部遍布整个地方。例如,用于System.Windows.Forms.Timer的内部SystemEvents类。如果您想在Reflector中查看自己的实现,请从那里开始查看。您应该能够搜索常量,但深入了解类的层次结构,您知道必须在内部处理这样的通知消息,这通常是一种更智能的搜索方式。 HWND_MESSAGE类(如上所述)也是开始寻找实施策略的好地方。

请注意,您不能在此处使用仅限消息的窗口(TimerNativeWindow),因为NativeWindow class。我上面提到的{{1}} 这样做,因为它不关心广播事件,所以不要只是从那里复制并粘贴代码!