C# 安装uiAccess=True的桌面WPF应用程序时的注意事项
背景: 我需要在另一个显示器上创建调光效果。我想我通过使用一个WPF窗口解决了这个问题,该窗口占据了整个屏幕的维度,并且C# 安装uiAccess=True的桌面WPF应用程序时的注意事项,c#,.net,wpf,ui-automation,uipi,C#,.net,Wpf,Ui Automation,Uipi,背景: 我需要在另一个显示器上创建调光效果。我想我通过使用一个WPF窗口解决了这个问题,该窗口占据了整个屏幕的维度,并且最顶层和允许透明度=True。它有一个内部的黑色发光效果,并应用了样式WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,允许用户点击它背后的应用程序 我监视Windows中的EVENT\u OBJECT\u REORDER事件,并调用SetWindowPos强制最顶层的状态高于其他最顶层的窗口。到目前为止,它似乎在我的概念验证测试中运行良好 我发现的问题
最顶层
和允许透明度
=True。它有一个内部的黑色发光效果,并应用了样式WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW
,允许用户点击它背后的应用程序
我监视Windows中的EVENT\u OBJECT\u REORDER
事件,并调用SetWindowPos
强制最顶层的状态高于其他最顶层的窗口。到目前为止,它似乎在我的概念验证测试中运行良好
我发现的问题是这个变暗(窗口)会覆盖任务栏,但如果我单击“开始”菜单则不会。我目前正在用Windows10进行测试。如果单击“开始”菜单,则会导致“开始”菜单和任务栏显示在变暗(窗口)上方。我总是希望一切都保持暗淡
我通过在应用程序清单中设置uiAccess
=true,生成自签名证书,并将exe复制到“c:\program files*”来解决这个问题。这允许我强制窗口处于最顶层状态,甚至在“开始”菜单上方
我的问题:
- 是否有一种方法可以将窗口放置在“开始”菜单上,而无需
?或者甚至是另一种不使用窗口(但不依赖于显示器驱动程序或硬件功能)强制屏幕变暗的方法uiAccess
- 如果不是,那么在分发WPF应用程序(通过WiX设置项目或类似项目)时,我需要记住哪些注意事项,即使用
=True绕过UIPI限制?我可以在安装过程中简单地安装我的自签名证书吗?用户是否会遇到其他障碍?作为一名开发人员,我在构建这个过程中会遇到任何额外的障碍吗(除了我已经提到的)uiAccess
谢谢大家! 这不会回答任何关于
uiAccess=true
的问题,但是
调暗屏幕
作为调暗屏幕的另一种方法,您可以尝试使用一次性调暗所有屏幕(如果需要)
例如,以以下帮助器类为例:
/// <summary> Allows changing the gamma of the displays. </summary>
public static class GammaChanger
{
/// <summary>
/// Retrieves the current gamma ramp data so that it can be restored later.
/// </summary>
/// <param name="gamma"> [out] The current gamma. </param>
/// <returns> true if it succeeds, false if it fails. </returns>
public static bool GetCurrentGamma(out GammaRampRgbData gamma)
{
gamma = GammaRampRgbData.Create();
return GetDeviceGammaRamp(GetDC(IntPtr.Zero), ref gamma);
}
public static bool SetGamma(ref GammaRampRgbData gamma)
{
// Now set the value.
return SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref gamma);
}
public static bool SetBrightness(int gamma)
{
GammaRampRgbData data = new GammaRampRgbData
{
Red = new ushort[256],
Green = new ushort[256],
Blue = new ushort[256]
};
int wBrightness = gamma; // reduce the brightness
for (int ik = 0; ik < 256; ik++)
{
int iArrayValue = ik * (wBrightness + 128);
if (iArrayValue > 0xffff)
{
iArrayValue = 0xffff;
}
data.Red[ik] = (ushort)iArrayValue;
data.Green[ik] = (ushort)iArrayValue;
data.Blue[ik] = (ushort)iArrayValue;
}
return SetGamma(ref data);
}
[DllImport("gdi32.dll")]
private static extern bool SetDeviceGammaRamp(IntPtr hdc, ref GammaRampRgbData gammaRgbArray);
[DllImport("gdi32.dll")]
private static extern bool GetDeviceGammaRamp(IntPtr hdc, ref GammaRampRgbData gammaRgbArray);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct GammaRampRgbData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public UInt16[] Red;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public UInt16[] Green;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public UInt16[] Blue;
/// <summary> Creates a new, initialized GammaRampRgbData object. </summary>
/// <returns> A GammaRampRgbData. </returns>
public static GammaRampRgbData Create()
{
return new GammaRampRgbData
{
Red = new ushort[256],
Green = new ushort[256],
Blue = new ushort[256]
};
}
}
}
但请注意,这是在应用
如果你真的这么做了,我建议你真的要确保在退出之前恢复用户的gamma,否则你的应用程序会崩溃,屏幕不会永久变暗
资料来源:
- 讨论,这是大部分算法的来源
- 这是上述解决方案的基础
Osk.exe
。有趣的实验,我预测它会严重闪烁一段时间,但假设它最终会放弃。事实上我不确定,我上次尝试这个是在Vista时间,它不会,请让我们知道
可以肯定的是,您会得出这样的结论:这不是正确的方法,因此uiAccess也是没有意义的。这里需要它来绕过UIPI并使SetWindowPos()工作。UAC的一个方面,它阻止程序试图劫持提升的程序的能力。覆盖开始窗口符合拒绝服务攻击的条件。这里更大的问题是,您的自签名证书不起作用,您必须购买一个真正的证书。每~7年会让你退回几百美元
用软件控制显示器的亮度并不是那么容易做到的。每个人都可以使用SetDeviceGammaRamp(),这也是您应该做的。MSDN文档将为您提供大量FUD,但每个主流视频适配器驱动程序都会实现它。它在游戏中很流行。一个不可避免的限制是,它仅在运行程序的桌面上处于活动状态。因此,不适用于安全桌面(屏幕保护程序和Ctrl+Alt+Del),也不适用于其他登录会话,除非它们也启动了您的程序
<> WMI太小,不能考虑。我不太清楚为什么它会经常出现故障,我想这与视频适配器和显示器之间的I2C互连通常不太理想有关。或者想要通过Fn键控制亮度的笔记本电脑,这项功能总是胜出的。或者是基于环境光自动调整亮度的Windows功能,这总是一种更理想的方式,而且很难遵循
最常见的结果很可能是对您的程序耸耸肩,对笨拙的监视器控件诅咒用户。但他会摆弄它,把它弄明白。抱歉。为什么不使用SetMonitorBrightness?@Simon谢谢,我已经考虑过了,但是支持的非常有限。它似乎仅限于笔记本电脑显示器和其他一些显示器。我可能会在支持它的显示器上提供这个选项,但我需要一些可以在任何显示器上产生更全局性的暗淡效果的东西。我以前用我的时钟应用程序(Win32)使用定时器和设置窗口POS来实现这一点,谢谢你。正如我所提到的,我正在定期调用
SetWindowPos
,这使得我最顶级的应用程序可以超越其他最顶级的应用程序(包括Windows任务栏)。不过,这似乎不会导致它位于Windows 10的“开始”菜单上方(如果显示“开始”菜单,则位于任务栏)。使用uiAccess=true
,它确实在开始菜单上方工作。
GammaChanger.GammaRampRgbData originalGamma;
bool success = GammaChanger.GetCurrentGamma(out originalGamma);
Console.WriteLine($"Originally: {success}");
success = GammaChanger.SetBrightness(44);
Console.WriteLine($"Setting: {success}");
Console.ReadLine();
success = GammaChanger.SetGamma(ref originalGamma);
Console.WriteLine($"Restoring: {success}");
Console.ReadLine();