|
.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.Forms
Imports 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 Form1
Private 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 記事ランキング
本日
月間