PInvoking RegisterHotKey()
でウィンドウを表示するグローバルホットキーを作成します。しかし、これを行うには、ウィンドウが読み込まれるまで存在しない、つまり初めて表示されるウィンドウのHWND
が必要です。しかし、ホットキーを設定する前にウィンドウを表示したくありません。ユーザーには見えないそのウィンドウのHWND
を作成する方法はありますか?
.NET 4.0をターゲットにしている場合は、EnsureHandle
で利用可能な新しいWindowInteropHelper
メソッドを利用できます。
public void InitHwnd()
{
var helper = new WindowInteropHelper(this);
helper.EnsureHandle();
}
( これを指摘してくれたThomas Levesqueに感謝します。 )
古いバージョンの.NET Frameworkをターゲットにしている場合、最も簡単な方法は、いくつかのプロパティを設定しながらウィンドウを表示してHWNDにアクセスし、ウィンドウが非表示になり、フォーカスが奪われないようにすることです。
var window = new Window() //make sure the window is invisible
{
Width = 0,
Height = 0,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false,
ShowActivated = false
};
window.Show();
実際のウィンドウを表示したい場合は、コンテンツ、サイズを設定し、スタイルを通常のウィンドウに戻すことができます。
ウィンドウをいわゆるメッセージ専用ウィンドウに変更することもできます。このウィンドウタイプはグラフィック要素をサポートしていないため、表示されることはありません。基本的にそれは呼び出すことになります:
SetParent(hwnd, (IntPtr)HWND_MESSAGE);
常に非表示になる専用のメッセージウィンドウを作成するか、実際のGUIウィンドウを使用して、表示するときに通常のウィンドウに戻します。より完全な例については、以下のコードを参照してください。
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hwnd, IntPtr hwndNewParent);
private const int HWND_MESSAGE = -3;
private IntPtr hwnd;
private IntPtr oldParent;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
hwnd = hwndSource.Handle;
oldParent = SetParent(hwnd, (IntPtr)HWND_MESSAGE);
Visibility = Visibility.Hidden;
}
}
private void OpenWindowMenuItem_Click(object sender, RoutedEventArgs e)
{
SetParent(hwnd, oldParent);
Show();
Activate();
}
私にとって、幅、高さをゼロに設定し、スタイルをなしに設定するという解決策はうまくいきませんでした。それでも、0x0ウィンドウの周りの境界のように見えるのに迷惑な影が付いた小さなウィンドウが表示されたためです(Windows 7でテスト済み) )。したがって、私はこの代替オプションを提供しています。
これは汚いハックですが、動作するはずであり、不透明度を変更することの欠点はありません。
WindowStartupLocation
をManual
に設定しますTop
およびLeft
プロパティを画面外のどこかに設定しますShowInTaskbar
をfalseに設定して、ユーザーが新しいウィンドウがあることに気付かないようにしますShow
およびHide
ウィンドウこれで、HWNDを取得できるはずです。
編集:別のオプション、おそらくより良い:ShowInTaskBar
をfalseに設定し、WindowState
をMinimized
に設定して、それを表示する:まったく表示されない
その質問への回答は既に投稿していましたが、より良い解決策を見つけました。
実際にウィンドウを表示せずにHWNDが作成されていることを確認するだけの場合は、次のようにできます。
public void InitHwnd()
{
var helper = new WindowInteropHelper(this);
helper.EnsureHandle();
}
(実際にはEnsureHandle
メソッドは、質問の投稿時には利用できませんでした。NET4.0で導入されました)
私はあなたがしていることをやろうとしたことはありませんが、HWNDを取得するためにウィンドウを表示する必要があるが、showを使用したくない場合は、ウィンドウの不透明度を0に設定します。また、ヒットテストの発生を防ぎます。次に、ウィンドウにパブリックメソッドを設定して、表示させたいときに不透明度を100に変更できます。
私はWPFについてまったく何も知りませんが、WM_HOTKEYメッセージを受信するために他の手段(たとえば、PInvoke)を使用して メッセージのみのウィンドウ を作成できますか?はいの場合、WM_HOTKEYを受け取ったら、そこからWPFウィンドウを起動できます。
ウィンドウが初期化されているときに最後に起こることは、通常と異なる場合のWindowState
の変更であることに気付きました。したがって、実際にそれを利用することができます:
public void InitializeWindow(Window window) {
window.Top = Int32.MinValue;
window.Left = Int32.MinValue;
window.Width = 0;
window.Height = 0;
window.ShowActivated = false;
window.ShowInTaskbar = false;
window.Opacity = 0;
window.StateChanged += OnBackgroundStateChanged;
window.WindowStyle = WindowStyle.None;
}
public void ShowWindow(Window window) {
window.Show();
window.WindowState = WindowState.Maximized;
}
protected bool isStateChangeFirst = true;
protected void OnBackgroundStateChanged(object sender, EventArgs e) {
if (isStateChangeFirst) {
isStateChangeFirst = false;
window.Top = 300;
window.Left = 200;
window.Width = 760;
window.Height = 400;
window.WindowState = WindowState.Normal;
window.ShowInTaskbar = true;
window.Opacity = 1;
window.Activate();
}
}
それは私には十分にうまくいきます。また、ハンドルなどを操作する必要はなく、さらに重要なことに、ウィンドウのカスタムクラスを用意する必要もありません。これは、動的に読み込まれるXAMLに最適です。また、フルスクリーンアプリを作成する場合にも最適です。状態を通常に戻したり、適切な幅と高さを設定したりする必要さえありません。ただ行く
protected bool isStateChangeFirst = true;
protected void OnBackgroundStateChanged(object sender, EventArgs e) {
if (isStateChangeFirst) {
isStateChangeFirst = false;
window.ShowInTaskbar = true;
window.Opacity = 1;
window.Activate();
}
}
これで完了です。
そして、ウィンドウのロード時に状態の変更が最後に行われるという私の推測が間違っていても、他のイベントに変更することができますが、それは実際には重要ではありません。
ウィンドウのサイズを0 x 0ピクセルにし、ShowInTaskBarをfalseに設定して表示し、必要に応じてサイズを変更します。
WindowInteropHelperクラスを使用すると、WPFウィンドウのHWNDを取得できます。
MyWindow win = new MyWindow();
WindowInteropHelper helper = new WindowInteropHelper(win);
IntPtr hwnd = helper.Handle;
不透明度を0に設定するのと同様の別のオプションは、サイズを0に設定し、位置を画面の外に設定することです。これには、AllowsTransparency = Trueは必要ありません。
また、一度表示したら、非表示にしてもhwndを取得できることを忘れないでください。
非表示のウィンドウを表示するための拡張メソッドを作成しました。次のShow
呼び出しは問題なく動作します。
public static class WindowHelper
{
public static void ShowInvisible(this Window window)
{
// saving original settings
bool needToShowInTaskbar = window.ShowInTaskbar;
WindowState initialWindowState = window.WindowState;
// making window invisible
window.ShowInTaskbar = false;
window.WindowState = WindowState.Minimized;
// showing and hiding window
window.Show();
window.Hide();
// restoring original settings
window.ShowInTaskbar = needToShowInTaskbar;
window.WindowState = initialWindowState;
}
}