はじめに
PowerShellから画面を表示する場合にOwnerを指定しないので親子関係をもっておらず裏に隠れてしまうのが気になっていました。
この問題について少し調べたのでまとめておきます。
どこからOwnerを取得するか
ぐぐってみたところカレントのProcessを取得してMainWindowHandleプロパティでハンドルを取得してくるのをみつけました。
以下のコードで実験してみたら0が格納されていて有効なハンドルが取得できませんでした。
$process = [Diagnostics.Process]::GetCurrentProcess()
write-host $process.MainWindowHandle
他の方法を調べたらGetConsoleWindowでコマンドプロンプトのウィンドウハンドルを取得できそうです。
以下のコードで実験してウィンドウハンドルが取得できることを確認しました。
Add-Type -Name ConsoleAPI -Namespace Win32Util -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
'
$hwnd = [Win32Util.ConsoleAPI]::GetConsoleWindow()
Write-Host $hwnd
ソースコード
取得したウィンドウハンドルを以下のようにOwnerに設定します。
Add-Type -AssemblyName PresentationFramework
Add-Type -Name ConsoleAPI -Namespace Win32Util -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
'
[xml]$xaml = @'
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test"
Height="200" Width="300" >
</Window>
'@
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$wih = New-Object System.Windows.Interop.WindowInteropHelper($window)
$wih.Owner = [Win32Util.ConsoleAPI]::GetConsoleWindow()
$window.ShowDialog() | Out-Null
これでコンソールの画面が親となった画面を表示することができました。
気になること
VS Codeから実行した場合は、ウィンドウハンドルは取得できますが、VS Codeが親になってませんでした。
理由はよくわからないけど、親になってVS Codeの画面が操作できなくなっても困るので、これで良しとしました。
Ownerを指定しているので親子順は固定されたのですが、親のコンソールの画面をクリックできたり、×ボタンで閉じれたりするのが不満。
親画面のハンドルがあるからEnableWindowしたりとかすればいいんでしょうけど、そこまでこだわらないことにします。
メッセージボックスに応用
メッセージボックス表示についても、親を指定してみました。
Forms.MessageBoxの第一引数にIWin32Windowで親を指定すればよいので、
NativeWindow.AssignHandle()でハンドルを渡して作りました。
不満だった親画面が操作できる問題はメッセージボックスだと発生しないようです。
Add-Type -AssemblyName System.Windows.Forms
Add-Type -Name ConsoleAPI -Namespace Win32Util -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
'
$hwnd = [Win32Util.ConsoleAPI]::GetConsoleWindow()
$nativeWindow = New-Object Windows.Forms.NativeWindow
$nativeWindow.AssignHandle($hwnd)
$result = [System.Windows.Forms.MessageBox]::show($nativeWindow,"message","title","YESNO","Info")
write-host $result
さいごに
子を持つことを想定していないコンソールのウィンドウが子を持つのはそれなりに大変なようです。
私も来週には第一子が生まれる予定です。
里帰り中の妻のデプロイ待ちなのですが、ここまでくると無事にリリースされるのを祈るしかできないのがつらいですね。
子を持つことは不安なことも多く、大変なことだとは思いますが、チームでいろいろ挑戦していきたいです。
(これが言いたかっただけの記事です)
私PowerShellだけど…シリーズ
私PowerShellだけど、君のタスクトレイで暮らしたい
私PowerShellだけど「送る」からファイルを受け取りたい(コンテキストメニュー登録もあるよ)
私powershellだけどタスクトレイの片隅でアイを叫ぶ