ちょっと不便だと感じたので、PowerShell関数を任意のデリゲートにキャストするコマンドレットを作成しました。
【 0. 目次 】
1. Download
2. 解説
3. 使用例
【 1. Download 】
このコマンドレットは、YokoKen.PowerShell.Utilityというスナップインに含まれています。このスナップインは以下の記事にて公開しています。
YokoKen.PowerShell.Utility
【 2. 解説 】
[ 2.1 コマンド名 ]
このコマンドレットには、ConvertTo-Delegateという名前が付けられています。
[ 2.2 概要 ]
ConvertTo-Delegateコマンドレットは、指定したPowerShell関数 ( = ScriptBlockオブジェクト ) を、指定したデリゲートにキャストします。指定できるデリゲートに制限はありません。
[ 2.3 構文 ]
ConvertTo-Delegateコマンドレットの構文は以下のようになっています。
ConvertTo-Delegate [-Target] <System.Management.Automation.ScriptBlock> [-DelegateType] <System.Type> [[-ErrorNotifiedByDialog] <System.Boolean>]
[ パラメータ ]
・Target <System.Management.Automation.ScriptBlock>
デリゲートにキャストするPowerShell関数を指定します。Targetパラメータに指定できるPowerShell関数に制限はありません。PowerShell関数の戻り値が、DelegateTypeパラメータに指定したデリゲートに定義されている戻り値の型と異なる場合でも、問題なく実行できます。
必須 : true
位置 : 1
既定値 : -
パイプライン入力を許可する : true (ByValue)
ワイルドカード文字を許可する : false
Nullを許可する : false
・DelegateType <System.Type>
PowerShell関数をキャストするデリゲートを指定します。DelegateTypeパラメータには、デリゲート ( = MulticastDelegate派生型 ) を指定してください。それ以外では例外が発生します。
必須 : true
位置 : 2
既定値 : -
パイプライン入力を許可する : false
ワイルドカード文字を許可する : false
Nullを許可する : false
・ErrorNotifiedByDialog <System.Boolean>
デリゲートオブジェクトとして実行されたPowerShell関数が、実行中に例外をスローした時、例外の情報をダイアログで通知するかどうかを指定します。falseを指定した場合は、PowerShellのホストアプリケーションから、通常通りに通知されます。規定値はfalseです。
必須 : false
位置 : 3
既定値 : false
パイプライン入力を許可する : false
ワイルドカード文字を許可する : false
Nullを許可する : false
[ 2.4 詳細 ]
・デリゲートオブジェクトとして呼び出されたPowerShell関数の引数
デリゲートオブジェクトとして呼び出されたPowerShell関数で、引数を受け取ることができます。ただし、$Args変数から取得する以外の手段で引数を取得することはできません。例えば、以下の例では引数を取得できず、例外が発生します。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form1 = New-Object "System.Windows.Forms.Form";
function form1_Click([object] $sender, [EventArgs] $e)
{
# デリゲートオブジェクトとして呼び出されると、$senderにはNullが入っています。
([System.Windows.Forms.Form]$sender).Text = "Hoge";
}
$clickHandler = ConvertTo-Delegate $Function:form1_Click System.EventHandler;
$form1.Add_Click($clickHandler);
[System.Windows.Forms.Application]::Run($form1);
正しく動作させるには、以下のように記述します。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form1 = New-Object "System.Windows.Forms.Form";
function form1_Click
{
# デリゲートオブジェクトとして呼び出されても、$Argsの各要素には適切な値が入っています。
([System.Windows.Forms.Form]$Args[0]).Text = "Hoge";
}
$clickHandler = ConvertTo-Delegate $Function:form1_Click System.EventHandler;
$form1.Add_Click($clickHandler);
[System.Windows.Forms.Application]::Run($form1);
・デリゲートオブジェクトとして呼び出されたPowerShell関数の戻り値
デリゲートオブジェクトとして呼び出されたPowerShell関数は、以下の条件を満たすことで、戻り値を返すことができます。
条件 : PowerShell関数の戻り値が、キャストしたデリゲートに定義されている戻り値の型にキャストできること。
条件を満たさない場合でも問題なく実行できますが、戻り値はNullとなります。 ( キャストしたデリゲートに定義されている戻り値の型がVoid型の場合は、何も返しません。 )
例えば、以下の例では戻り値はNullとなります。 ( ResolveEventHandlerデリゲートの戻り値の型は、System.Reflection.Assemblyクラスです。 )
# ResolveEventHandlerにキャストして呼び出されたとき、戻り値はNullとなります。
$func1 = ConvertTo-Delegate {"test";} ResolveEventHandler;
$func1.Invoke($(), $());
以下の例のように、PowerShell関数の戻り値が、デリゲートに定義されている戻り値の型にキャストできる場合は、戻り値が返されます。
# ResolveEventHandlerにキャストして呼び出されたとき、戻り値は適切な値となります。
$func1 = ConvertTo-Delegate {[System.Reflection.Assembly]::GetExecutingAssembly();} ResolveEventHandler;
$func1.Invoke($(), $());
【 3. 使用例 】
・イベントハンドラ
以下のコードは、フォームが閉じられる際に、終了確認ダイアログを表示し、「いいえ」が選択された場合に終了をキャンセルさせる例です。 ( コード中で使用しているRun-Formコマンドレットについては、こちらの記事を参照してください。 )
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form = New-Object "System.Windows.Forms.Form";
$formClosingHandlScript =
{
$sender = [System.Windows.Forms.Form]$Args[0];
$e = [System.Windows.Forms.FormClosingEventArgs]$Args[1];
$messageBoxButton = [System.Windows.Forms.MessageBoxButtons]::YesNo;
$messageBoxIcon = [System.Windows.Forms.MessageBoxIcon]::Question;
$dialogResult = [System.Windows.Forms.MessageBox]::Show($sender, "終了しますか?", "確認", $messageBoxButton, $messageBoxIcon);
if ($dialogResult -ne [System.Windows.Forms.DialogResult]::Yes)
{
$e.Cancel = $True;
}
};
$formClosingHandler = ConvertTo-Delegate $formClosingHandlScript System.Windows.Forms.FormClosingEventHandler;
$form.Add_FormClosing($formClosingHandler);
Run-Form $form;
・Threadクラスによるマルチスレッド
以下の例のように、Threadクラスを用いることで、ThreadStartデリゲートにキャストしたPowerShell関数を別スレッド上で実行させることができます。
ただし、別スレッドでの実行を目的にPowerShell関数をデリゲートにキャストする場合、ErrorNotifiedByDialogパラメータには必ず Trueを指定してください。Trueを指定しないと、別スレッド上でのPowerShell関数の実行中に例外が発生した場合に、例外が適切に処理されないため PowerShellが強制終了してしまいます。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$messageBoxClass = [System.Windows.Forms.MessageBox];
$process = ConvertTo-Delegate {[void] $messageBoxClass::Show("test");} System.Threading.ThreadStart $True;
$newThread = New-Object System.Threading.Thread $process;
$newThread.Start();
トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/66-38746b90