Ian*_*oyd 5 .net windows broadcast
我有一个Object(即不是表格)想要收听来自Windows的广播消息,例如:
WM_SETTINGCHANGEWM_DWMCOLORIZATIONCOLORCHANGEDWM_DWMCOMPOSITIONCHANGEDWM_THEMECHANGEDWM_POWERBROADCAST.NET中设置非WinForm窗口的机制是什么,可以监听广播消息?
即有WindowsListener课吗?
在过去,在其他开发环境中,框架提供了一个AllocateHwnd功能:
HWND listener = AllocateHWnd(ListenerWindowProc);
Run Code Online (Sandbox Code Playgroud)
ListenerWindowProc我的窗口程序方法在哪里:
private void ListenerWindowProc(ref Message msg)
{
switch (msg.msg)
{
case WM_SETTINGCHANGE:
{
...
}
break;
case WM_POWERBROADCAST:
{
...
}
break;
case WM_THEMECHANGED:
{
...
}
break;
...
}
DefWindowProc(msg);
}
Run Code Online (Sandbox Code Playgroud)
秘诀是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)));
}
}
Run Code Online (Sandbox Code Playgroud)
与更多的秘密代码相关联UtilWindowClass.
当你完成后,你会DeallocateHwnd:
DeallocateHwnd(listenerWindow);
Run Code Online (Sandbox Code Playgroud)
我知道.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);
}
Run Code Online (Sandbox Code Playgroud)
我假设您给出的示例仅仅是:示例.因为其中许多已经管理了等价物,已经为您包装了所有这些.就像WM_POWERBROADCAST被Microsoft.Win32.SystemEvents.PowerModeChanged事件包裹一样.而且WM_SETTINGCHANGED相当于Microsoft.Win32.SystemEvents.UserPreferenceChanged.
无论如何,像你描述的广播消息被发送到所有顶级窗口,所以你真正需要做的就是创建一个顶级窗口并覆盖它的WndProc方法来处理你感兴趣的通知消息.
使用NativeWindow课程让自己轻松自如.在这种情况下,您不需要Form类提供的所有内容,只需要包装CreateWindowEx并提供窗口过程即可.只需创建没有WS_VISIBLE标志的窗口,因为您不希望它出现在屏幕上.
.NET Framework在内部完成所有这些工作.例如,TimerNativeWindow用于的内部类System.Windows.Forms.Timer.如果您想在Reflector中查看自己的实现,请从那里开始查看.您应该能够搜索常量,但深入到类的层次结构中,您知道必须在内部处理这样的通知消息,这通常是一种更智能的搜索方式.在SystemEvents类(如上所述)也开始寻找执行战略的好地方.
请注意,您不能在此处使用仅限消息的窗口(HWND_MESSAGE),因为它们不会接收广播事件.在TimerNativeWindow我上面提到的没有做到这一点,因为它并不关心广播事件,所以不只是将代码复制并从那里粘贴!