9

背景:

我需要在另一台显示器上创建调光效果。我想我通过使用一个 WPF 窗口解决了这个问题,该窗口使用Topmostand AllowsTransparency= True 占据了整个屏幕尺寸。它具有内部黑色发光效果,并WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW应用了样式(除其他外),以​​允许用户点击进入其背后的应用程序。

我监视EVENT_OBJECT_REORDERWindows 中的事件并调用SetWindowPos强制 Topmost 状态高于其他 Topmost 窗口。到目前为止,它似乎在我的概念验证测试中运行良好。

我发现的问题是这个变暗(窗口)会覆盖任务栏,但如果我单击“开始”菜单则不会。我目前正在使用 Windows 10 进行测试。如果单击“开始”菜单,则会导致“开始”菜单和任务栏出现在变暗(窗口)上方。我希望一切都保持昏暗,永远。

我通过uiAccess在应用程序清单中设置 =true、生成自签名证书并将 exe 复制到“c:\program files*”解决了这个问题。这使我可以强制我的窗口处于最顶层状态,甚至在开始菜单上方。

我的问题:

  • 有没有办法在没有开始菜单的情况下定位一个窗口uiAccess?或者甚至是另一种在不使用窗口的情况下强制使屏幕变暗的方法(但不依赖于显示器驱动程序或硬件功能)?

  • 如果没有,在分发 WPF 应用程序(通过 WiX 设置项目或类似的东西)时,我需要记住哪些注意事项,即使用uiAccess=True 绕过 UIPI 限制?我可以在设置过程中简单地安装我的自签名证书吗?用户会遇到任何额外的障碍吗?作为开发人员,我会在构建它时遇到任何额外的障碍(除了我已经提到的)吗?

谢谢!

4

2 回答 2

4

我监视 EVENT_OBJECT_REORDER 事件

您正在使用 SetWinEventHook()。这种情况不符合经典的“如果两个程序这样做会怎样”括号。Raymond Chen 在这篇博文中很好地讨论了这一点,并专门为你的方法发表了一篇文章。

这比您想象的要普遍得多。每台 Windows 机器都有一个执行此操作的程序,例如,运行Osk.exe屏幕键盘程序。有趣的实验,我预测它会严重闪烁一段时间,但假设它最终会放弃。实际上不确定是否如此,我上次尝试是在 Vista 时间,但它不会,请告诉我们。

相当肯定你会得出结论,这不是正确的方法,所以 uiAccess 也没有实际意义。您需要在这里绕过 UIPI 并使 SetWindowPos() 工作。UAC 的一个方面,它阻止程序尝试劫持提升的程序的功能。覆盖“开始”窗口属于 DOS 攻击。这里更大的问题是您的自签名证书无法正常工作,您必须购买真正的证书。每约 7 年让您退回数百美元。

用软件控制显示器亮度并不容易正确做到。每个人都可以使用 SetDeviceGammaRamp(),这也是你应该做的。MSDN 文档将为您提供大量的 FUD,但每个主流视频适配器驱动程序都实现了它。它在游戏中很受欢迎。一个不可避免的限制是它只对运行程序的桌面有效。因此不适用于安全桌面(屏幕保护程序和 Ctrl+Alt+Del),也不适用于其他登录会话,除非它们也启动您的程序。

WMI 太不稳定,无法考虑。不太清楚为什么它经常失败,我认为这与视频适配器和显示器之间通常不那么出色的 I2C 互连有关。或者想要通过 Fn 按键控制亮度的笔记本电脑,该功能总是胜出。或者基于环境光自动调整亮度的 Windows 功能,总是更理想的方式来做到这一点,而且很难遵循。

最常见的结果可能是对您的程序耸耸肩,以及对笨拙的监视器控件的用户的诅咒。但他会摆弄它并弄清楚。对不起。

于 2016-03-09T06:58:54.250 回答
3

这不会回答任何关于的问题uiAccess=true,但是...

调暗屏幕

作为使屏幕变暗的另一种方法,您可以尝试使用SetDeviceGammaRamp一次使所有屏幕变暗(如果需要)。

例如,采用以下帮助程序类:

/// <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]
             };
    }
  }
}

结合 a 中的以下内容static void Main(),程序将改变亮度,直到用户退出应用程序:

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();

但是请注意,这是将全局解决方案应用于本地问题

如果您确实走这条路,我建议您在退出之前确保您正在恢复用户的 gamma,否则他们的应用程序崩溃并且屏幕不会永久变暗的体验会不那么出色。

资料来源:

于 2016-03-09T05:20:29.053 回答