Clipboardクラスを使用するにはMainメソッドにSTAThreadAttribute属性を付け、Single Thread Apartment (STA) モードにする必要があります。さもなくば「OLE が呼び出される前に、現在のスレッドが Single Thread Apartment (STA) モードに設定されていなければなりません。Main 関数に STAThreadAttribute が設定されていることを確認してください。」としてThreadStateExceptionが投げられます。
string text = "TEST"; Clipboard.SetDataObject(text);
クリップボードを消去し、そこへデータを追加できます。
MainメソッドにSTAThreadAttribute属性を付けていないと、「OLE が呼び出される前に、現在のスレッドが Single Thread Apartment (STA) モードに設定されていなければなりません。Main 関数に STAThreadAttribute が設定されていることを確認してください。」としてThreadStateExceptionが投げられます。
public static void SetDataObject (object data, bool copy);SetDataObject(Object, Boolean) - Clipboard.SetDataObject Method (System.Windows.Forms) | Microsoft Learn
アプリケーション終了後もデータを残しておくならば、copyにtrueを指定します。データが文字列などの単純なデータ型ならば、trueとして残すようにします。一方でfalseとするとアプリケーション終了後にデータは消去され、これはこの引数を省略した構文と同じ挙動となります。
「要求されたクリップボード操作に成功しませんでした。(Requested Clipboard operation did not succeed.)」としてExternalException例外によりコピーに失敗するならば、試行回数を指定します。このような失敗は、他のスレッドやアプリケーションによりクリップボードが使用されているときに発生します。
public static void SetDataObject (object data, bool copy, int retryTimes, int retryDelay);
retryTimesで試行回数を、retryDelayでその間隔をミリ秒で指定します。なおこれを省略した場合は、10回、100ミリ秒間隔で試行されます。SetDataObject - Clipboard.cs
失敗の詳細はExternalException.ErrorCodeで確認できます。
| 値 | 定数 | 内容 | 
|---|---|---|
| 0x800401D0 | CLIPBRD_E_CANT_OPEN | OpenClipboard Failed | 
| 0x800401D1 | CLIPBRD_E_CANT_EMPTY | EmptyClipboard Failed | 
| 0x800401D2 | CLIPBRD_E_CANT_SET | SetClipboard Failed | 
| 0x800401D3 | CLIPBRD_E_BAD_DATA | Data on clipboard is invalid | 
| 0x800401D4 | CLIPBRD_E_CANT_CLOSE | CloseClipboard Failed | 
| 0x8007000E | E_OUTOFMEMORY | Ran out of memory | 
DataObjectのインスタンスを作成し、そこにSetData()で異なるフォーマットのデータを追加します。そしてSetDataObject()でそれをクリップボードへ追加します。
DataObject data = new DataObject(); data.SetData(DataFormats.Html, htmlData); data.SetData(DataFormats.Text, textData); Clipboard.SetDataObject(data);
SetData()の構文は次のようになっており、第1引数でフォーマットを指定します。そのときに有効なフォーマットの文字列はDataFormatsクラスで定義されており、DataFormats.Textならば"Text"、DataFormats.Htmlならば"HTML Format"のように取得できます。
public virtual void SetData (string format, object data);SetData(String, Object) - DataObject.SetData Method (System.Windows.Forms) | Microsoft Learn
単純なテキスト形式ならばstring型のオブジェクトを渡すだけで、System.String、UnicodeText、Textの3つのフォーマットで格納されます。
string text = "TEST"; Clipboard.SetDataObject(text, true); IDataObject iData = Clipboard.GetDataObject(); string[] formats = iData.GetFormats(); // formats {string[3]} // [0] "System.String" // [1] "UnicodeText" // [2] "Text"
IDataObject iData = Clipboard.GetDataObject(); // システムのクリップボードにあるデータを表す、IDataObjectを取得
if (iData.GetDataPresent(DataFormats.UnicodeText))
{
    string text = (string)iData.GetData(DataFormats.UnicodeText);
}
		システムのクリップボードにあるデータを表す、IDataObjectを得られます。
MainメソッドにSTAThreadAttribute属性を付けていないと、つねにnullが返されます。
public static System.Windows.Forms.IDataObject GetDataObject ();Clipboard.GetDataObject Method (System.Windows.Forms) | Microsoft Learn
クリップボードにデータがないとnullが返されます。
このインスタンスに格納されたデータが指定の型に関連付けられ、それへ変換可能なときtrueが返されます。
public bool GetDataPresent (Type format);GetDataPresent(Type) - IDataObject.GetDataPresent Method (System.Windows.Forms) | Microsoft Learn
formatは、DataFormatsクラスで定義されている文字列の形式でも指定できます。
指定の型に関連付けられたデータを得られます。
public object GetData (Type format);GetData(Type) - IDataObject.GetData Method (System.Windows.Forms) | Microsoft Learn
指定の書式に関連付けられたデータを得られないとき、GetData()はnullを返します。
public object GetData (string format);
formatは"Text"、またはDataFormatsクラスのフィールドを用いてDataFormats.Textのように指定します。
いずれの構文でも、指定の書式のデータを見つけられないときはその書式への変換が試みられますが、autoConvertを引数に取る構文ではこれをfalseとすることで、この変換を無効にできます。
public object GetData (string format, bool autoConvert);
たとえばクリップボードのデータにANSIテキスト形式に対応しないUnicode文字が含まれているとき、
string text = (string)iData.GetData(DataFormats.Text);
のように取得すると、それらの文字は「?」に置換されます。
このインスタンスに格納されたデータに関連付けられている書式の一覧を得られます。
public string[] GetFormats ();GetFormats() - IDataObject.GetFormats Method (System.Windows.Forms) | Microsoft Learn
IDataObject iData = Clipboard.GetDataObject(); string[] formats = iData.GetFormats(); // [0] "System.String" string // [1] "UnicodeText" string // [2] "Text" string // [3] "Rich Text Format" string
特定の形式のデータを扱うならば、Clipboardクラスにそれ専用の静的メソッドが用意されています。
| 対象 | 追加 | 取得 | 判定 | 
|---|---|---|---|
| 任意のデータ | SetData() | GetData() | ContainsData() | 
| テキスト | SetText() | GetText() | ContainsText() | 
| 画像 | SetImage() | GetImage() | ContainsImage() | 
| 音声 | SetAudio() | GetAudioStream() | ContainsAudio() | 
| ファイル | SetFileDropList() | GetFileDropList() | ContainsFileDropList() | 
SetData()では指定の書式でDataObjectに格納した後、Clipboard.SetDataObject()を呼び出しています。
public static void SetData(string format, object data) {
    //Note: We delegate argument checking to IDataObject.SetData, if it wants to do so.
    IDataObject dataObject = new DataObject();
    dataObject.SetData(format, data);
    Clipboard.SetDataObject(dataObject, true);
}
			SetData - Clipboard.cs
		SetText()ではOSのバージョンによってTextかUnicodeTextをDataObjectに格納し、Clipboard.SetDataObject()を呼び出しています。
public static void SetText(string text) {
    // Pass in Text format for Win98...
    if (Environment.OSVersion.Platform != System.PlatformID.Win32NT ||
        Environment.OSVersion.Version.Major < 5)
    {
        SetText(text, TextDataFormat.Text);
    }
    else {
        SetText(text, TextDataFormat.UnicodeText);
    }
}
public static void SetText(string text, TextDataFormat format) {
    if (String.IsNullOrEmpty(text)) {
        throw new ArgumentNullException("text");
    }
    //valid values are 0x0 to 0x4
    if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue))
    {
        throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat));
    }
    IDataObject dataObject = new DataObject();
    dataObject.SetData(ConvertToDataFormats(format), false, text);
    Clipboard.SetDataObject(dataObject, true);
}
			SetText - Clipboard.cs
		HTMLをクリップボードを介して処理するには、次のような書式に従う必要があります。
Version:1.0 StartHTML:00000097 EndHTML:00000186 StartFragment:00000133 EndFragment:00000150 <HTML> <BODY> <!--StartFragment--> <P>SAMPLE</P> <!--EndFragment--> </BODY> </HTML>Overview of CF_HTML - HTML Clipboard Format (Internet Explorer) | Microsoft Learn
実際の書式は、
IDataObject iData = Clipboard.GetDataObject(); object html = iData.GetData(DataFormats.Html);
のようにして用例を確認できます。
改行文字が含まれる文字列をExcelに貼り付けると、2つのセルに分割されてしまいます。これをセル内で改行されるようにするには、HTMLのstyle要素で
br {mso-data-placement:same-cell;}
			を指定するか、改行文字を"<br style='mso-data-placement:same-cell'>"の文字列に置換します。.net - How to insert programmatically a new line in an Excel cell in C#? - Stack Overflow
SetClipboardViewer()を呼ぶことでウィンドウをクリップボード ビューアー チェーン (clipboard viewer chain) に追加することで、クリップボードの内容が変更されたときにWM_DRAWCLIPBOARDメッセージを受け取れるようになります。Adding a Window to the Clipboard Viewer Chain - Using the Clipboard - Win32 apps | Microsoft Learn
HWND SetClipboardViewer( [in] HWND hWndNewViewer );SetClipboardViewer function (winuser.h) - Win32 apps | Microsoft Learn
internal class ClipboardWatcher : NativeWindow
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
    [DllImport("user32.dll")]
    private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);
    private IntPtr hWndNextViewer;
    public event EventHandler<TextEventArgs> ClipboardChanged;
    public ClipboardWatcher(Control control)
    {
        control.HandleCreated += delegate
        {
            AssignHandle(control.Handle);
            this.hWndNextViewer = SetClipboardViewer(Handle);
        };
        control.HandleDestroyed += delegate
        {
            ChangeClipboardChain(Handle, this.hWndNextViewer);
            ReleaseHandle();
        };
    }
    protected override void WndProc(ref Message m)
    {
        const int WM_DRAWCLIPBOARD = 0x0308;
        const int WM_CHANGECBCHAIN = 0x030D;
        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD: // クリップボードの内容が変更された
                if (Clipboard.ContainsText())
                {
                    if (ClipboardChanged != null) ClipboardChanged(this, new TextEventArgs(Clipboard.GetText()));
                }
                if (this.hWndNextViewer != IntPtr.Zero)
                {
                    // クリップボード ビューアー チェーンにある次のウィンドウへメッセージを渡す
                    SendMessage(new HandleRef(this, this.hWndNextViewer), m.Msg, m.WParam, m.LParam);
                }
                break;
            case WM_CHANGECBCHAIN: // 他のウィンドウが、クリップボード ビューアー チェーンから除去された
                if (m.WParam == this.hWndNextViewer)
                {
                    // 次のウィンドウが閉じているならば、チェーンを訂正する
                    this.hWndNextViewer = m.LParam;
                }
                else if (this.hWndNextViewer != IntPtr.Zero)
                {
                    // さもなくば、次のリンクへメッセージを渡す
                    SendMessage(new HandleRef(this, this.hWndNextViewer), m.Msg, m.WParam, m.LParam);
                }
                break;
        }
        base.WndProc(ref m);
    }
}
public class TextEventArgs : EventArgs
{
    private string text;
    public string Text
    {
        get { return this.text; }
    }
    public TextEventArgs(string text)
    {
        this.text = text;
    }
}