> WM_SETTINGCHANGE
> WM_DWMCOLORIZATIONCOLORCHANGED
> WM_DWMCOMPOSITIONCHANGED
> WM_THEMECHANGED
> WM_POWERBROADCAST
.NET中设置非WinForm窗口的机制是什么,可以监听广播消息?
即是否有WindowsListener类?
奖金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,'',WS_POPUP,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); }
解决方法
Microsoft.Win32.SystemEvents.PowerModeChanged
event包装一样.WM_SETTINGCHANGED相当于
Microsoft.Win32.SystemEvents.UserPreferenceChanged
.
无论如何,像你描述的广播消息被发送到所有顶级窗口,所以你真正需要做的就是创建一个顶级窗口并覆盖其WndProc方法来处理你感兴趣的通知消息.
使用NativeWindow
class让自己轻松自如.在这种情况下,您不需要Form类提供的所有内容,您只需要包装CreateWindowEx并提供窗口过程.只需创建没有WS_VISIBLE标志的窗口,因为您不希望它出现在屏幕上.
.NET Framework在内部完成所有这些工作.例如,用于System.Windows.Forms.Timer的内部TimerNativeWindow类.如果您想在Reflector中查看自己的实现,请从那里开始查看.您应该能够搜索常量,但深入到类的层次结构中,您知道必须在内部处理这样的通知消息,这通常是一种更智能的搜索方式. SystemEvents类(如上所述)也是开始寻找实现策略的好地方.
请注意,你不能在这里使用仅消息窗口(HWND_MESSAGE),因为they won’t receive broadcast events.我上面提到的TimerNativeWindow确实这样做,因为它不关心广播事件,所以不要只复制和粘贴代码从那里!