すがブロ

sugamasaoのhatenablogだよ

突発的にクリップボード(2)

前回

id:seiunsky:20070404:1175710724

なんということだ

Clipboardクラスを調べればクリップボードの監視もすぐに見つかると思っていたんだけど、どうやら Win32API を使わなくてはいけないらしい。

というわけで

数年ぶり(社会人になってからは触ってない)Win32 API 直書きと C# での unmanaged なソースは初めて書くことになった。

技術メモ

  1. ウィンドウメッセージを取得するには
    protected override void WndProc(ref Message msg) でメソッドをオーバーライドする
  2. WM_DRAWCLIPBOARD イベントがクリップボード動作時のイベントなので、その時にクリップボードの中身を取得する処理を書く
  3. WM_CHANGECBCHAIN イベントで、次のクリップボードチェインにメッセージを送信してやる?(よくわかってない)
  4. Form 終了時に、クリップボードチェインから自身をはずす処理を入れる
    this.closing イベントにデリゲートを登録して、 Win32 の ChangeClipboardChain 関数を呼び出す。

メインソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace クリクリボード
{
    public partial class クリクリボード : Form
    {
        // Win32 API で必要らしい
        private IntPtr NextHandle;
        private const int WM_DRAWCLIPBOARD = 0x0308;
        private const int WM_CHANGECBCHAIN = 0x030D;

        [DllImport("user32")]
        public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32")]
        extern static IntPtr ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

        public クリクリボード()
        {
            InitializeComponent();

            // クリップボードチェインにへ自分のハンドラを追加?
            NextHandle = SetClipboardViewer(this.Handle);

            // クリップボードチェインからはずすためのデリゲート登録
            // Form 終了時に行う
            this.Closing += new CancelEventHandler(Form1_Closing);
        }

        // 終了イベント(デリゲート登録される)
        void Form1_Closing(object sender, CancelEventArgs e)
        {
            ChangeClipboardChain(this.Handle, this.NextHandle);
        }

        protected override void WndProc(ref Message msg)
        {
            switch (msg.Msg)
            {
                // クリップボードにコピーされた
                case WM_DRAWCLIPBOARD:
                    this.textBox1.Text += (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
                    this.textBox1.Text += "\r\n";
                    if ((int)NextHandle != 0)
                    {
                        SendMessage(NextHandle, msg.Msg, msg.WParam, msg.LParam);
                    }
                    break;
                
                // 次のクリップボードチェインにメッセージ送信?
                case WM_CHANGECBCHAIN:
                    if ((IntPtr)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);
        }



    }
}

このソースにヘタれな書き方があれば

ぜひ指摘してくだしあ!

既知の問題

クリップボードに何か文字がコピーされれば反映されているんだけど、なぜかVS2005上のソースコードをコピーすると日本語が化ける。
EUCでも UTF-8 でも、普通のテキストで保存して試してみるときちんとコピーできるのに、 VS2005 上のエディタの文字列をコピーすると日本語が化けてしまう。なぜだろう。