PInvokingでウィンドウを表示するグローバルホットキーを作成しますRegisterHotKey()
。しかし、これを行うにはHWND
、ウィンドウがロードされるまで存在しないウィンドウが必要です。これは、初めて表示されることを意味します。ただし、ホットキーを設定する前にウィンドウを表示したくありません。HWND
ユーザーに表示されないそのウィンドウのを作成する方法はありますか?
12 に答える
.NET 4.0をターゲットにしている場合は、:で利用可能な新しいメソッドEnsureHandle
を利用できます。WindowInteropHelper
public void InitHwnd()
{
var helper = new WindowInteropHelper(this);
helper.EnsureHandle();
}
(これを指摘してくれたThomas Levesqueに感謝します。 )
古いバージョンの.NETFrameworkをターゲットにしている場合、最も簡単な方法は、ウィンドウが非表示になり、フォーカスが奪われないようにいくつかのプロパティを設定しながら、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を取得するためにウィンドウを表示する必要があるが、表示したくない場合は、ウィンドウの不透明度を0に設定します。これにより、ヒットテストが発生しなくなります。 。次に、ウィンドウを表示したいときに不透明度を100に変更するパブリックメソッドをウィンドウに設定できます。
WPFについてはまったく知りませんが、他の手段(PInvokeなど)を使用してメッセージ専用ウィンドウを作成し、WM_HOTKEYメッセージを受信できますか?はいの場合、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();
}
}
これで完了です。
また、ウィンドウがロードされているときに状態の変更が最後に行われるという私の仮定が間違っていても、他のイベントに変更することはできますが、実際には問題ではありません。
非表示モードでWpfウィンドウを起動します:
WpfWindow w = new WpfWindow() { Visibility = Visibility.Hidden };
可視モードでWpfウィンドウを起動します:
WpfWindow w = new WpfWindow();
w.Show();
WindowInteropHelperクラスを使用すると、WPFウィンドウのHWNDを取得できます。
MyWindow win = new MyWindow();
WindowInteropHelper helper = new WindowInteropHelper(win);
IntPtr hwnd = helper.Handle;
不透明度を0に設定するのと同様の方法で、サイズを0に設定し、位置を画面外に設定することもできます。これには、AllowsTransparency=Trueは必要ありません。
また、一度表示したら、それを非表示にして、hwndを取得できることも覚えておいてください。
ウィンドウのサイズを0x0 pxにし、ShowInTaskBarをfalseに設定して表示し、必要に応じてサイズを変更します。
非表示のウィンドウを表示するための拡張メソッドを作成しました。次の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;
}
}