|  | 
 
| .NET TIPS クリップボードの内容をリアルタイムに取得するには?[C#、VB]デジタルアドバンテージ 岸本 真二郎2009/03/05
 |  | 
 
| 
 | 
 .NET Frameworkによるプログラミングでは、Clipboardクラス(System.Windows名前空間)を用いて、テキストや画像をクリップボードにセットしたり、逆にクリップボードから取得したりできる。クリップボードの標準的なアクセス方法については、「TIPS:クリップボードへデータを送るには?」や「TIPS:クリップボードからデータを受け取るには?」などで解説している。
 しかしながら、クリップボードの変更をリアルタイムに検知して、クリップボードの内容を取得するような処理は、Clipboardクラスだけでは実現できない。これには、Win32 APIに含まれるSetClipboardViewerという関数を呼び出すことにより、アプリケーションをクリップボードのビューアとして登録し、さらにWindowsメッセージを直接処理することで、クリップボードにデータが登録されたことを検知できる。
 ここでは、NativeWindowクラス(System.Windows.Forms名前空間)を用いることにより、極力Windowsメッセージを意識しないで、リアルタイムにクリップボードからテキストを取得する例を示す。クリップボードにデータが登録(コピー)されたら、イベントハンドラを用いてクリップボードの内容を引き渡す。
| 
 
| using System;using System.Windows.Forms;
 using System.Runtime.InteropServices;
 
 namespace ClipboardViewer
 {
 public class ClipboardEventArgs : EventArgs
 {
 private string text;
 
 public string Text
 {
 get { return this.text; }
 }
 
 public ClipboardEventArgs(string str)
 {
 this.text = str;
 }
 }
 
 public delegate void cbEventHandler(
 object sender, ClipboardEventArgs ev);
 
 [System.Security.Permissions.PermissionSet(
 System.Security.Permissions.SecurityAction.Demand,
 Name = "FullTrust")]
 internal class MyClipboardViewer : NativeWindow
 {
 [DllImport("user32")]
 public static extern IntPtr SetClipboardViewer(
 IntPtr hWndNewViewer);
 
 [DllImport("user32")]
 public static extern bool ChangeClipboardChain(
 IntPtr hWndRemove, IntPtr hWndNewNext);
 
 [DllImport("user32")]
 public extern static int SendMessage(
 IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
 
 private const int WM_DRAWCLIPBOARD = 0x0308;
 private const int WM_CHANGECBCHAIN = 0x030D;
 private IntPtr nextHandle;
 
 private Form parent;
 public event cbEventHandler ClipboardHandler;
 
 public MyClipboardViewer(Form f)
 {
 f.HandleCreated
 += new EventHandler(this.OnHandleCreated);
 f.HandleDestroyed
 += new EventHandler(this.OnHandleDestroyed);
 this.parent = f;
 }
 
 internal void OnHandleCreated(object sender, EventArgs e)
 {
 AssignHandle(((Form)sender).Handle);
 // ビューアを登録
 nextHandle = SetClipboardViewer(this.Handle);
 }
 
 internal void OnHandleDestroyed(object sender, EventArgs e)
 {
 // ビューアを解除
 bool sts = ChangeClipboardChain(this.Handle, nextHandle);
 ReleaseHandle();
 }
 
 protected override void WndProc(ref Message msg)
 {
 switch (msg.Msg) {
 
 case WM_DRAWCLIPBOARD:
 if (Clipboard.ContainsText()) {
 // クリップボードの内容がテキストの場合のみ
 if (ClipboardHandler != null) {
 // クリップボードの内容を取得してハンドラを呼び出す
 ClipboardHandler(this,
 new ClipboardEventArgs(Clipboard.GetText()));
 }
 }
 if ((int)nextHandle != 0)
 SendMessage(
 nextHandle, msg.Msg, msg.WParam, msg.LParam);
 break;
 
 // クリップボード・ビューア・チェーンが更新された
 case WM_CHANGECBCHAIN:
 if (msg.WParam == nextHandle) {
 nextHandle = (IntPtr)msg.LParam;
 } else if((int)nextHandle != 0)
 SendMessage(
 nextHandle, msg.Msg, msg.WParam, msg.LParam);
 break;
 }
 base.WndProc(ref msg);
 }
 }
 }
 
 |  
 
| Imports System.Windows.FormsImports System.Runtime.InteropServices
 
 Public Class ClipboardEventArgs
 Inherits EventArgs
 Private m_text As String
 
 Public ReadOnly Property Text() As String
 Get
 Return Me.m_text
 End Get
 End Property
 
 Public Sub New(ByVal str As String)
 Me.m_text = str
 End Sub
 End Class
 
 Public Delegate Sub cbEventHandler(ByVal sender As Object, _
 ByVal ev As ClipboardEventArgs)
 
 <System.Security.Permissions.PermissionSet( _
 System.Security.Permissions.SecurityAction.Demand, _
 Name:="FullTrust")> _
 Friend Class MyClipboardViewer
 Inherits NativeWindow
 
 <DllImport("user32")> _
 Public Shared Function SetClipboardViewer( _
 ByVal hWndNewViewer As IntPtr) As IntPtr
 End Function
 
 <DllImport("user32")> _
 Public Shared Function ChangeClipboardChain( _
 ByVal hWndRemove As IntPtr, _
 ByVal hWndNewNext As IntPtr) As Boolean
 End Function
 
 <DllImport("user32")> _
 Public Shared Function SendMessage( _
 ByVal hWnd As IntPtr, ByVal Msg As Integer, _
 ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
 End Function
 
 Private Const WM_DRAWCLIPBOARD As Integer = &H308
 Private Const WM_CHANGECBCHAIN As Integer = &H30D
 Private nextHandle As IntPtr
 
 Private parent As Form
 Public Event ClipboardHandler As cbEventHandler
 
 Public Sub New(ByVal parent As Form)
 AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
 AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed
 Me.parent = parent
 
 End Sub
 
 Friend Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
 AssignHandle(DirectCast(sender, Form).Handle)
 ' ビューアを登録
 nextHandle = SetClipboardViewer(Me.Handle)
 End Sub
 
 Friend Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
 ' ビューアを解除
 Dim sts As Boolean = ChangeClipboardChain(Me.Handle, nextHandle)
 ReleaseHandle()
 End Sub
 
 Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
 Select msg.Msg
 
 Case WM_DRAWCLIPBOARD
 ' クリップボードの内容がテキストの場合
 If Clipboard.ContainsText() Then
 ' クリップボードの内容を取得してハンドラを呼び出す
 RaiseEvent ClipboardHandler( _
 Me, New ClipboardEventArgs(Clipboard.GetText()))
 End If
 
 If CInt(nextHandle) <> 0 Then
 SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam)
 End If
 Exit Select
 
 ' クリップボード・ビューア・チェーンが更新された
 Case WM_CHANGECBCHAIN
 If msg.WParam = nextHandle Then
 nextHandle = DirectCast(msg.LParam, IntPtr)
 ElseIf CInt(nextHandle) <> 0 Then
 SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam)
 End If
 Exit Select
 
 End Select
 MyBase.WndProc(msg)
 End Sub
 End Class
 
 |  | 
| リアルタイムにクリップボードの内容を通知する処理(上:C#、下:VB) | 
| クリップボード・ビューア・チェーンとは、本プログラムのようなクリップボードを監視するアプリケーションが登録されているリストで、Windowsにより管理されている。 | 
 この処理では、まずClipboardEventArgsクラスを定義して、イベントハンドラの引数として使用するクラスを定義する。この中のTextプロパティを使って、クリップボードのテキストを取得する。
 MyClipboardViewerクラスは、NativeWindowの派生クラスとして宣言する。これにより、このクラスを“サブクラス化”できる。サブクラス化することで、元のウィンドウに送られてくるWindowsメッセージをサブクラス(ここではMyClipboardViewer)側で先に受け取ることができ、元のウィンドウのメッセージ処理には手を加えずに、Windowsメッセージ(ここで利用するのはクリップボード関連のメッセージ)を処理できるようになる。
 このMyClipboardViewerクラスでは、Win32 APIのSetClipboardViewer関数を用いて、クリップボードのビューアを登録する。そして、Windowsメッセージ・ハンドラ(WndProcメソッド)でクリップボードにデータが登録された際(WM_DRAWCLIPBOARDメッセージが送られたとき)に、クリップボードからテキストを取り出して、イベントハンドラを使って文字列を渡すようにしている。
 このクラスを利用する側は、MyClipboardViewerオブジェクトの作成と、そのClipboardHandlerイベントのイベントハンドラの設定を行っておけば、クリップボードにテキストがコピーされるたびにイベントハンドラが呼び出されるようになる。
| 
 
| using System;using System.Windows.Forms;
 
 namespace ClipboardViewer
 {
 public partial class Form1 : Form
 {
 private MyClipboardViewer viewer;
 
 public Form1()
 {
 viewer = new MyClipboardViewer(this);
 
 // イベントハンドラを登録
 viewer.ClipboardHandler += this.OnClipBoardChanged;
 InitializeComponent();
 }
 
 // クリップボードにテキストがコピーされると呼び出される
 private void OnClipBoardChanged(object sender, ClipboardEventArgs args)
 {
 this.textBox1.Text = args.Text;
 }
 }
 }
 
 |  
 
| Public Class Form1Private viewer As MyClipboardViewer
 
 Public Sub New()
 viewer = New MyClipboardViewer(Me)
 ' イベントハンドラを登録
 AddHandler viewer.ClipboardHandler, AddressOf OnClipBoardChanged
 
 ' この呼び出しは、Windows フォーム デザイナで必要です。
 InitializeComponent()
 End Sub
 
 ' クリップボードにテキストがコピーされると呼び出される
 Private Sub OnClipBoardChanged(ByVal sender As Object, ByVal args As ClipboardEventArgs)
 TextBox1.Text = args.Text
 End Sub
 
 End Class
 
 |  | 
| MyClipboardViewerクラスを利用したWindowsフォーム・アプリケーションの例(上:C#、下:VB) | 
 ここではまず、フォームのコンストラクタでMyClipboardViewerクラスのインスタンスを生成し、次にイベントハンドラを登録する。例として、上記のイベントハンドラでは、フォームに配置したテキストボックスに、取得したクリップボードの内容をセットしている。
 この例では、クリップボードにテキストがコピーされた場合だけ処理しているが、ほかにも画像がクリップボードにコピーされた場合の処理を追加するには、ClipboardEventArgsクラスに画像を保持するメンバを追加し、WndProcメソッド内で画像を取得するようにすればよい。
 
| カテゴリ:Windowsフォーム 処理対象:クリップボード カテゴリ:クラス・ライブラリ 処理対象:Win32 API
 使用ライブラリ:Clipboardクラス(System.Windows名前空間)
 使用ライブラリ:NativeWindowクラス(System.Windows.Forms名前空間)
 関連TIPS:クリップボードへデータを送るには?
 関連TIPS:クリップボードからデータを受け取るには?
 | 
| 
 
|  | generated by |  | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間