7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

私PowerShellだけど子を持つ親になるのはいろいろ大変そう

Last updated at Posted at 2019-01-30

はじめに

PowerShellから画面を表示する場合にOwnerを指定しないので親子関係をもっておらず裏に隠れてしまうのが気になっていました。

この問題について少し調べたのでまとめておきます。

どこからOwnerを取得するか

ぐぐってみたところカレントのProcessを取得してMainWindowHandleプロパティでハンドルを取得してくるのをみつけました。

以下のコードで実験してみたら0が格納されていて有効なハンドルが取得できませんでした。

console_handle_1.ps1

$process = [Diagnostics.Process]::GetCurrentProcess()
write-host $process.MainWindowHandle

他の方法を調べたらGetConsoleWindowでコマンドプロンプトのウィンドウハンドルを取得できそうです。
以下のコードで実験してウィンドウハンドルが取得できることを確認しました。

console_handle_2.ps1

Add-Type -Name ConsoleAPI -Namespace Win32Util -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
'

$hwnd = [Win32Util.ConsoleAPI]::GetConsoleWindow()
Write-Host $hwnd

ソースコード

取得したウィンドウハンドルを以下のようにOwnerに設定します。

show_dialog.ps1

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()でハンドルを渡して作りました。
不満だった親画面が操作できる問題はメッセージボックスだと発生しないようです。

show_messagebox.ps1

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だけどタスクトレイの片隅でアイを叫ぶ

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?