はじめに
シェルの実行中でも、ユーザーに注意を促すために GUI のダイアログを表示したい要件はしばしばあります。
PowerShell で実現する方法を調べていたところ、いくつかの方法がありつつ、自分の求めているものとは違っていた部分もあったので、ここに記します。
要件
サポンテが求める要件は以下の二つです。
- PowerShell から GUI のダイアログを表示する。
- 実行中の PowerShell のコンソールウィンドウの手前に表示されること。
特に大切なのは後者です。実際に業務で「ダイアログがウィンドウの後ろ側に回り込んで、ダイアログが表示されていることが分からなかった」「ウィンドウが固まって操作が不能になった」「どのウィンドウで発生しているエラーか分からない」などのクレームをもらうことがあります。「ダイアログをモーダルで表示する」ところで考えが止まってしまって「どのウィンドウで管理されているダイアログなのか」を考慮していないアプリケーションは少なくないようです。ユーザーはとても困ってます。
実際のサンプル
Windows 11 で動作確認しました。Windows 10 だとどうなるかは不明です。
$src=@' using System; using System.Runtime.InteropServices; public static class Win32 { private static int GW_HWNDNEXT = 2; [DllImport("user32.dll")] public extern static int MessageBox(int hWnd, string msg, string caption, int uType); [DllImport("user32")] private extern static int GetParent(int hWnd); [DllImport("user32")] private extern static int GetWindow(int hWnd, int wCmd); [DllImport("user32")] private extern static int FindWindow(string lpClassName, string lpWindowName); [DllImport("user32")] private extern static int GetWindowThreadProcessId(int hWnd, out int lpDwProcessId); [DllImport("user32")] private extern static int IsWindowVisible(int hWnd); // プロセスID(pid)をウィンドウハンドル(hWnd)に変換する public static int GetHwndFromPid(int pid) { int hWnd; hWnd = FindWindow(null, null); while (hWnd != 0) { if (GetParent(hWnd) == 0 && IsWindowVisible(hWnd) != 0 && pid == GetPidFromHwnd(hWnd)) { return hWnd; } hWnd = GetWindow(hWnd, GW_HWNDNEXT); } return hWnd; } // ウィンドウハンドルを(hWnd)をプロセスID(pid)に変換する public static int GetPidFromHwnd(int hWnd) { int pid; GetWindowThreadProcessId(hWnd, out pid); return pid; } } '@ Add-Type -TypeDefinition $src # 自分自身を実行しているターミナルのプロセス ID を取得する $parentPid = 0 Get-WmiObject win32_process -filter processid=$pid | ForEach-Object { $parentPid = $_.parentprocessid; } # 自分自身を実行しているターミナルの Window Handle を取得する $hWnd = [Win32]::GetHwndFromPid($parentPid) # 取得できないなら止むを得ない。無念...。 if ($hWnd -eq 0) { $hWnd = $null; } # メッセージボックスを表示する [Win32]::MessageBox($hWnd, "コンテキスト", "キャプション", 0)
参考にしたサイト様
以下のサイトを参考にしました。ありがとうございます。
PowerShellでメッセージボックスを使う4つの方法 - 適材適所 PIDとHWNDの変換(C#/VB.NET) [サンプルソース] [ヨーキー景吾の逃走]
あと、ターミナルのプロセス ID を取得するところは Yahoo!知恵袋 さんのどこかのアンサーを参考にしたのですが失念してしまいました。