C# Screen.AllScreens错误并将WM_DISPLAYCHANGE发布到单个WinForm应用程序
首先,很抱歉发了这么长的帖子 关于如何限制WM\u DISPLAYCHANGE消息的发布范围,有什么建议吗? 情景:C# Screen.AllScreens错误并将WM_DISPLAYCHANGE发布到单个WinForm应用程序,c#,wmi,pinvoke,C#,Wmi,Pinvoke,首先,很抱歉发了这么长的帖子 关于如何限制WM\u DISPLAYCHANGE消息的发布范围,有什么建议吗? 情景: Screen.AllScreens返回客户端上检测到的所有监视器的坐标和分辨率数组。如果在工作站锁定时启动应用程序(在夜间应用程序重新启动期间),Screen.AllScreens仅返回一个元素,详细说明单个屏幕,所有多个监视器的尺寸为一个 随后,在此场景中,当用户解锁工作站并开始使用应用程序时,由于屏幕,正在使用的Infragistics控件(UltraWinDock)不允许将
Screen.AllScreens
返回客户端上检测到的所有监视器的坐标和分辨率数组。如果在工作站锁定时启动应用程序(在夜间应用程序重新启动期间),Screen.AllScreens
仅返回一个元素,详细说明单个屏幕,所有多个监视器的尺寸为一个
随后,在此场景中,当用户解锁工作站并开始使用应用程序时,由于屏幕,正在使用的Infragistics控件(UltraWinDock)不允许将浮动窗口拖动到主屏幕之外。AllScreens
属性不返回系统的真实监视器配置。Infragistics控件实际上查看Screen.PrimaryScreen.Bounds
,但是Screen.PrimaryScreen
属性反过来调用缓存的Screen.AllScreens
数组,它返回一个巨大的主屏幕
当应用程序正常启动(工作站解锁)时,控制功能正常
我能看到Screen.AllScreens
被重置和刷新的唯一方法是通过引发的SystemEvents.DisplayChanging
事件,
此时内部字段设置为空。(Screen.AllScreens
钩住此事件。)Screen.AllScreens
将在下次调用时重新填充
根据我的判断,SystemEvents.DisplayChanging
事件可以通过WM\u DISPLAYCHANGE
WMI消息引发
我管理解决方案的方法是调用:
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
其参数表示系统上的显示器数量。无论工作站是否锁定,这似乎总是返回存在的监视器的实际数量
然后,我评估Screen.AllScreens
数组的长度是否小于GetSystemMetrics(SM\u CMONITORS)
的结果,如果是,我将连接到
SystemEvents.SessionSwitch
静态事件,并检查SessionSwitchEventArgs.Reason
属性的值SessionUnlock
。
当工作站解锁时,会收到此事件并满足条件,因此我使用P/Invoke方法发布一条消息
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
使用以下参数:
PostMessage(HWND_BROADCAST, WM_DISPLAYCHANGE,UIntPtr.Zero,IntPtr.Zero)
这非常有效,并且达到了预期的效果屏幕。所有屏幕
均已重置,基础设施控制功能正常
在我看来,这就像是一个带有屏幕的模糊bug。当应用程序在锁定的工作站上启动,然后解锁时,所有屏幕都不会重新评估自身
我承认这是一个罕见的问题,但仍然是一个问题
对于消息,lParam和wParam描述为:
wParam
- 显示器的新图像深度,单位为位/像素
lParam
- 低阶字指定屏幕的水平分辨率
- 高阶字指定屏幕的垂直分辨率
我为这些参数发送nullIntPtr.Zero
,因为我不知道发送消息时的实际值是多少
我在这里担心的是,我正在使用空参数在整个系统中广播WM\u DISPLAYCHANGE
消息,并且可能有正在运行的进程使用WM\u DISPLAYMESSAGE
并使用参数。我希望如果发送空参数,任何消费者都会忽略这些参数,但这是一个非常危险的假设
是否有办法只向有问题的应用程序发送或发布消息,并消除影响其他进程的风险
我尝试了以下方法,但没有成功:
PostMessage(IntPtr.Zero, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
PostMessage(this.Handle, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
PostThreadMessage(AppDomain.GetCurrentThreadId(), WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
SendMessage(this.Handle, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
注意事项:
- 我对P/Invoke或WMI没有太多的经验
- 目标框架是.NET3.5
- 我还没有看到播放
WM_DISPLAYCHANGE
方法的PostMessage的任何副作用
- 我已经下载了Infragistics的源代码,并指出了代码中出现的问题,并考虑重新编译控件以集成修复程序,但决定不这样做。我已将此问题告知Infragistics,但我不能等待修复,尤其不能将其视为Infragistics问题,因为它是导致此问题的
Screen.AllScreens
- 应用程序必须在一夜之间重新启动,并且不能更改为等待用户在早上登录
- 我创建了一个测试应用程序,它锁定用户的工作站,重新启动自身(应用程序,而不是工作站),并在应用程序锁定时评估
屏幕。AllScreens
属性,然后在发送WM_DISPLAYCHANGE
方法后创建另一个快照。我想添加一个屏幕截图,但作为一个新的StackOverflow用户,我不允许这样做李>
我只是(!)需要知道如何使用p/Invoke向特定应用程序发送邮件
您需要获取应用程序的hwnd,而不是:
SendMessage(this.Handle...
使用spy++查找应用程序的窗口类,然后使用FindWindow()获取其hwnd
但这里可能有我遗漏的东西——你似乎足够有能力意识到这一点,所以也许我误解了,这就是你在重新编译的Infrastics应用程序中的代码?在这里给出答案可能太晚了,但这里的另一个选择是只调用所有屏幕使用的相同调用。然后您将获得实际值,而不是