9

バックグラウンド:

別のモニターで調光効果を作成する必要があります。Topmostand AllowsTransparency= Trueで画面全体のサイズを占める WPF Window を使用して解決したと思います。内側に黒いグロー効果があり、WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW(特に) スタイルが適用されており、ユーザーがクリックしてその背後にあるアプリにアクセスできるようになっています。

EVENT_OBJECT_REORDERWindows のイベントを監視し、呼び出しSetWindowPosて最上位の状態を他の最上位ウィンドウの上に強制します。私の概念実証テストでは、これまでのところうまく機能しているようです。

私が見つけた問題は、この減光 (ウィンドウ) がタスク バーを覆い隠すことでしたが、[スタート] メニューをクリックした場合には覆い隠されませんでした。現在、Windows 10 でテストしています。[スタート] メニューをクリックすると、[スタート] メニューとタスクバーが薄暗い (ウィンドウ) の上に表示されます。私は常にすべてが薄暗いままであることを望みました。

uiAccessアプリ マニフェストで =true を設定し、自己署名証明書を生成し、exe を "c:\program files*" にコピーすることで、この問題を解決しました。これにより、[スタート] メニューの上であっても、ウィンドウを強制的に最上位の状態にすることができます。

私の質問:

  • なしでスタートメニューの上にウィンドウを配置する方法はありますuiAccessか? または、ウィンドウを使用せずに画面を暗くする別の方法もあります (ただし、モニター ドライバーやハードウェア機能に依存しません)。

  • uiAccessそうでない場合、 =Trueで UIPI 制限をバイパスする WPF アプリを (WiX セットアップ プロジェクトなどを介して) 配布するときに、どのような考慮事項に留意する必要がありますか? セットアップ プロセス中に自己署名証明書を簡単にインストールできますか? ユーザーは追加のハードルに遭遇しますか? 私は、開発者として、これを構築する際に追加のハードルに遭遇しますか (既に述べたことは別として)?

ありがとうございました!

4

2 に答える 2

4

EVENT_OBJECT_REORDER イベントを監視します

SetWinEventHook() を使用しています。このシナリオは、古典的な「2 つのプログラムがこれを行うとどうなるか」というブラケットに失敗します。Raymond Chen は、このブログ投稿でこれについて非常によく説明しており、あなたのアプローチを専用の投稿にしています。

これは、あなたが思っているよりもずっと一般的です。すべての Windows マシンには、これを実行するプログラムがあります。たとえば、Osk.exeオンスクリーン キーボード プログラムを実行します。興味深い実験です。しばらくの間、ひどくちらつきますが、最終的にはあきらめると思います。実際にそうかどうかはわかりませんが、前回これを試したのは Vista のときで、そうではありませんでした。お知らせください。

これは正しい方法ではないと結論づけることは間違いないので、uiAccess も意味がありません。ここでは、UIPI をバイパスして SetWindowPos() を機能させるために必要でした。昇格されたプログラムの機能をハイジャックしようとするプログラムをブロックする UAC の側面。スタート ウィンドウを覆うことは、DOS 攻撃と見なされます。ここでのより大きな問題は、自己署名証明書が機能しないことです。本物の証明書を購入する必要があります。~7 年ごとに数百ドルが戻ってきます。

ソフトウェアでモニターの明るさを制御することは、正しく行うのはそれほど簡単ではありません。誰もが SetDeviceGammaRamp() に手を伸ばしており、それはあなたがすべきことでもあります。MSDN のドキュメントには多くの FUD が記載されていますが、主流のすべてのビデオ アダプター ドライバーで FUD が実装されていることがわかります。ゲームで人気だった。避けられない制限の 1 つは、プログラムが実行されているデスクトップに対してのみアクティブになることです。そのため、安全なデスクトップ (スクリーン セーバーと 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]
             };
    }
  }
}

で次と組み合わせると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();

ただし、これはローカルの問題にグローバルなソリューションを適用していることに注意してください

このルートに進む場合は、終了する前にユーザーのガンマを復元していることを確認することをお勧めします。そうしないと、アプリがクラッシュし、画面が永続的に暗くならないという経験が少なくなります。

ソース:

于 2016-03-09T05:20:29.053 に答える