1. ホーム
  2. .net

[解決済み] Alt-Tabのプログラムスイッチャーからウィンドウを隠す最良の方法?

2022-12-29 14:01:33

質問

私は数年前から.NETの開発者ですが、これはいまだに正しい方法を知らないことの一つです。Windows Forms と WPF の両方で、プロパティを通じてタスクバーからウィンドウを隠すことは簡単ですが、私が知る限り、これは、ウィンドウが Alt + ↹タブ のダイアログを表示します。見たところ 不可視 で表示されるウィンドウを Alt + ↹タブ を保証する最善の方法は何でしょうか? 決して に表示されないことを保証する最善の方法は何でしょうか? Alt + ↹タブ ダイアログを表示します。

更新しました。 以下に私の投稿した解決策をご覧ください。私は自分自身の答えを解決策としてマークすることを許可されていませんが、今のところ、それは動作する唯一のものです。

更新2です。 Franci Penovによる適切なソリューションがあり、それはかなり良さそうですが、自分では試していません。いくつかの Win32 を含みますが、オフスクリーン ウィンドウのお粗末な作成は回避できます。

どのように解決するのですか?

更新しました。

donovan によると、最近の WPF はこれをネイティブにサポートしているそうです。 ShowInTaskbar="False"Visibility="Hidden" をXAMLに追加します。(私はまだこれをテストしていませんが、それでもコメントの可視性を高めることにしました)

オリジナルの回答です。

Win32 APIでタスクスイッチャーからウィンドウを非表示にする方法は2つあります。

  1. を追加する。 WS_EX_TOOLWINDOW 拡張ウィンドウ スタイル - これが正しいアプローチです。
  2. を使用して、他のウィンドウの子ウィンドウにします。

残念ながら、WPFはWin32のようにウィンドウのスタイルを柔軟に制御することをサポートしていませんので、ウィンドウに WindowStyle=ToolWindow で終わってしまい、デフォルトの WS_CAPTIONWS_SYSMENU というスタイルがあり、キャプションと閉じるボタンが表示されます。一方、この2つのスタイルを削除するには WindowStyle=None を設定することで、これら二つのスタイルを取り除くことができますが、その場合 WS_EX_TOOLWINDOW 拡張スタイルが設定されず、ウィンドウはタスク スイッチャーから非表示になりません。

WPFウィンドウに WindowStyle=None を使用して、タスクスイッチャーからも非表示にするには、2 つの方法のいずれかを使用します。

  • 上記のサンプル コードを使用して、ウィンドウを小さな隠しツール ウィンドウの子ウィンドウにする。
  • ウィンドウのスタイルを変更し WS_EX_TOOLWINDOW 拡張スタイルも含めるように修正します。

私は個人的に 2 番目のアプローチを好みます。それから、私は、クライアント領域でガラスを拡張したり、キャプションで WPF 描画を有効にしたりといった高度なことをとにかく行うので、多少の相互運用性は大きな問題ではありません。

Win32相互運用ソリューションのアプローチのサンプルコードを紹介します。まず、XAML部分です。

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300"
    ShowInTaskbar="False" WindowStyle="None"
    Loaded="Window_Loaded" >

ここではあまり派手なことはせず、単にウィンドウを WindowStyle=NoneShowInTaskbar=False . また、Loaded イベントにハンドラを追加して、拡張ウィンドウ スタイルを変更します。その時点ではまだウィンドウ ハンドルがないため、コンストラクタでこの作業を行うことはできません。イベント ハンドラ自体は非常に単純です。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    WindowInteropHelper wndHelper = new WindowInteropHelper(this);

    int exStyle = (int)GetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE);

    exStyle |= (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW;
    SetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
}

そして Win32 interop 宣言。ここのサンプルコードを小さくするために、列挙型から不要なスタイルをすべて削除しています。また、残念ながら SetWindowLongPtr のエントリーポイントは Windows XP の user32.dll には存在しません。 SetWindowLong を通して呼び出すというトリックです。

#region Window styles
[Flags]
public enum ExtendedWindowStyles
{
    // ...
    WS_EX_TOOLWINDOW = 0x00000080,
    // ...
}

public enum GetWindowLongFields
{
    // ...
    GWL_EXSTYLE = (-20),
    // ...
}

[DllImport("user32.dll")]
public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);

public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
    int error = 0;
    IntPtr result = IntPtr.Zero;
    // Win32 SetWindowLong doesn't clear error on success
    SetLastError(0);

    if (IntPtr.Size == 4)
    {
        // use SetWindowLong
        Int32 tempResult = IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong));
        error = Marshal.GetLastWin32Error();
        result = new IntPtr(tempResult);
    }
    else
    {
        // use SetWindowLongPtr
        result = IntSetWindowLongPtr(hWnd, nIndex, dwNewLong);
        error = Marshal.GetLastWin32Error();
    }

    if ((result == IntPtr.Zero) && (error != 0))
    {
        throw new System.ComponentModel.Win32Exception(error);
    }

    return result;
}

[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
private static extern Int32 IntSetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);

private static int IntPtrToInt32(IntPtr intPtr)
{
    return unchecked((int)intPtr.ToInt64());
}

[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(int dwErrorCode);
#endregion