シングル スレッド アパートメント

クリップボードを使うにはどうすればよいでしょう?

PS> [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
PS> [Windows.Forms.Clipboard]::SetText('Hello World!')
"1" 個の引数を指定して "SetText" を呼び出し中に例外が発生しました: "OLE が呼び出される前に、現在のスレッドが Single Thread Apartment (STA) モードに設定されていなければなりません。Main 関数に STAThreadAttribute が設定されていることを確認してください。" 発生場所 行:1 文字:35 + [Windows.Forms.Clipboard]::SetText( <<<< ‘Hello World!’)

うまくいきません。これは、System.Windows.Forms.Clipboard がシングルスレッドアパートメント(STA)を必要とするのに対し、PowerShell がマルチスレッドアパートメント(MTA)で動いているからです。

したがって、STA のスレッドを新たに開始し、その中でスクリプトを実行することで解決できます。Invoke-StaThread.ps1 は、STA スレッドでスクリプトブロックを実行し、そこに引数や入力を与え、出力を受け取り、主スレッドに出力します。内部で New-Delegate.ps1 を呼び出しますので、こちらも用意してください。

 用例1: クリップボードに「Hello World!」をコピーし、それを貼り付け

PS> [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
PS> Invoke-StaThread {[Windows.Forms.Clipboard]::SetText('Hello World!')}
PS> Invoke-StaThread {[Windows.Forms.Clipboard]::GetText()}
Hello World!

用例2: 引数の使用

PS> [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
PS> Invoke-StaThread {[Windows.Forms.Clipboard]::SetText($args[0])} 'Hello'
PS> Invoke-StaThread {[Windows.Forms.Clipboard]::GetText()}
Hello

用例3: パイプラインの使用

PS> [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
PS> 'World' | Invoke-StaThread {process{[Windows.Forms.Clipboard]::SetText($_)}}
PS> Invoke-StaThread {[Windows.Forms.Clipboard]::GetText()}
World

実装:

Invoke-StaThread は次のような手順で動作します。ハッシュ(連想配列)を用意し、それに引数、パイプラインからの入力を格納します。 New-Delegate を使って新しいスレッドを作成し、STA に設定し、スタートさせます。新スレッド内でハッシュから引数、パイプラインからの入力を取り出し、スクリプトを実行し、その出力をハッシュに格納します。新スレッドが終了するのを待ち、ハッシュ内の出力を取り出します。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です