クリップボードとドラッグ&ドロップの仕組み ── OLEデータ転送を業務アプリで正しく扱う

· 更新日: · · Windows, クリップボード, ドラッグアンドドロップ, OLE, COM, Windows開発, WinForms, WPF

更新履歴(6件・最終更新 2026年09月06日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

技術的な主張・コード・注意事項を維持し、形式の選択と提供、データの検証と寿命、監視・管理ポリシー、OLEドラッグ&ドロップの条件を小見出しと比較表で読みやすく整理した。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの「クリップボード履歴ポリシーはクリップボードを防ぐ」という関係を、「履歴・デバイス間同期への取り込みを防ぐ」に改めました。通常の貼り付けは引き続き機能するためです。本文の説明は変えていません。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.22054275)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「クリップボードとドラッグ&ドロップの仕組み ── OLEデータ転送を業務アプリで正しく扱う」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22054275 https://comcomponent.com/blog/windows-clipboard-drag-drop-ole-data-transfer/

DOI(最新版)
10.5281/zenodo.22054275
DOI(この版)
10.5281/zenodo.22453250

「Excelの表を貼ると書式が崩れる」「自社アプリでコピーした内容をWordに貼ると、意図した形にならない」「ファイルをドラッグ&ドロップで取り込めるようにしたい」── 業務アプリの改修では、こうした相談がよくあります。

どれも身近な操作ですが、クリップボードを「1つのデータを入れる箱」と考えると、仕組みを見誤ります。実際には、同じ内容を複数の形式で同時に置き、貼り付け側が理解できる形式を選ぶ仕組みです。同じコピーでも、貼り付け先によって結果が変わるのはこのためです。

コピー元を閉じると貼れなくなる問題には、必要になってからデータを作る「遅延レンダリング」が関わります。そしてOLEドラッグ&ドロップ(D&D)も、OLEクリップボードと同じデータ表現である IDataObject を、COMのインターフェース越しに受け渡します。コピペとD&Dは、データの形式を共通にして運び方を変えた、つながりのある機能です。

この記事は、中小企業の情シス担当者とWindowsアプリ開発者に向けた解説です。まず形式の仕組みを押さえ、貼り付け側・コピー側・監視側の実装を見てから、履歴・同期・RDPの管理とOLE D&Dの注意点へ進みます。

1. まず結論

押さえる軸は、次の3つです。

  1. コピー側は複数形式を提供し、貼り付け側はその中から選びます。 テキストは CF_UNICODETEXT、ファイルのパス一覧は CF_HDROP、書式付きテキストは登録形式の「HTML Format」が基本です。1234
  2. データの形式だけでなく、検証と寿命まで設計します。 貼り付けデータは信用できない外部入力として検証します。遅延レンダリングを使うコピー側は、終了時の確定処理まで実装します。監視は AddClipboardFormatListener と WM_CLIPBOARDUPDATE を使い、読み取りの競合にはリトライで備えます。5678
  3. データが渡る範囲と、渡した結果を明確にします。 履歴・クラウド同期・RDPリダイレクトは管理対象です。OLE D&Dには OleInitialize によるSTA初期化が必要で、通常権限から昇格先へのドロップはUIPIに阻まれます。また、Move は元データが消える契約です。910111213

目的に合わせて読む場合は、次の章から進めてください。

困りごと・目的 最初に確認すること 読む章
Excelの表を貼ると崩れる コピー側が提供する形式と、貼り付け側が選ぶ形式 2〜4章
自社アプリのコピーを他アプリでも使いたい 複数形式の提供と、終了後に残す処理 5章
コピーを検知して自動取り込みしたい リスナー登録と読み取りのリトライ 6章
機密を履歴・同期・RDP経由で残したくない アプリ側の除外形式と組織のポリシー 6.3節・7章
D&Dを実装したい、昇格時だけ動かない OLE初期化、権限境界、効果とパスの検証 8〜9章

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全20件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. クリップボードの正体 ── 「1つのデータ」ではなく「同じ内容の複数形式」

クリップボードは、アプリ間でデータを共有する仕組みです。同じデスクトップのアプリから利用できますが、正確な共有単位はウィンドウステーションです。別のユーザーセッションやRDPセッションは、それぞれ別のクリップボードを持ちます。RDPでコピペが通るのは、リダイレクト機能が両者を橋渡ししているからです(7章)。

利用はユーザー主導が大原則です。ユーザーの知らないところで勝手にデータを出し入れしない、というのが公式の設計方針です。1

コピー側はクリップボードを空にした後、同じ内容を複数の形式で、表現力の高いものから順に置きます。6 表計算ソフトで表をコピーする場面を、概念的に並べると次のようになります。

優先順 形式 内容
1 アプリ独自形式 数式・書式まで完全な内部表現(同じアプリへの貼り付け用)
2 HTML Format 表の構造と書式を保ったHTML断片
3 CSV セル区切りのテキスト
4 CF_UNICODETEXT タブ区切りのプレーンテキスト
5 画像形式 表の見た目のビットマップ

貼り付け側が取り出すのは、この一覧のうち自分の理解できる形式です。Wordで書式付きの表になり、メモ帳でタブ区切りテキストになるのは、両者が選んだ形式が違うためです。

つまり「貼り付け先によって結果が違う」こと自体は、バグではありません。コピー側の提供と貼り付け側の選択を、組み合わせて見る必要があります。

同じコピーが貼り付け先によって違う結果になる仕組みコピー側は同じ内容を複数の形式でクリップボードに置き、貼り付け側が自分の理解できる形式を選ぶため、Wordは書式付きの表になりメモ帳はタブ区切りテキストになるWordが選ぶメモ帳が選ぶコピー側: 表計算ソフトクリップボード(同じ内容の複数形式)アプリ独自形式HTML FormatCSVCF_UNICODETEXT書式付きの表タブ区切りテキスト

逆に言えば、冒頭の「書式が崩れる」「変なものが貼られる」という相談は、ほぼすべてどちらかの側の形式の選び方・提供の仕方の問題に還元できます。貼り付け側の話を4章、コピー側の話を5章で扱います。

3. 標準形式と登録形式 ── CF_UNICODETEXT・CF_HDROP・HTML Format

3.1. 標準形式 ── テキストはUnicode側を使う

OSがあらかじめ定義している形式を標準形式と呼びます。業務アプリで頻出するのは次の顔ぶれです。2

形式 値 内容
CF_TEXT 1 ANSIテキスト(コードページ依存)
CF_UNICODETEXT 13 Unicodeテキスト。テキストの正はこちら
CF_HDROP 15 ファイルパスの一覧(HDROPハンドル)
CF_DIB 8 デバイス独立ビットマップ
CF_LOCALE 16 テキストに関連付くロケール識別子

CF_TEXT と CF_UNICODETEXT は、システムが暗黙に相互変換する「合成形式」です。変換には CF_LOCALE に関連付いたコードページが使われます。2

ただし、ANSI側で表現できない文字は変換で失われます。Unicode固有の記号や結合文字などを扱う場合、変換任せでは文字化けにつながります。アプリの読み書きは CF_UNICODETEXT、.NETでは DataFormats.UnicodeText に統一するのが原則です。

CF_UNICODETEXTとCF_TEXTの暗黙変換アプリはCF_UNICODETEXTだけを読み書きし、CF_TEXTはシステムがCF_LOCALEのコードページで暗黙変換して合成する。ANSI側で表現できない文字はこの変換で落ちるシステムが暗黙変換(CF_LOCALEのコードページ)アプリの読み書きCF_UNICODETEXT(正)CF_TEXT(ANSI・コードページ依存)表現できない文字は変換で落ちる(文字化けの温床)

3.2. CF_HDROP ── ファイルは「パスの一覧」で渡る

エクスプローラーでのファイルコピーやD&Dに使われるのが CF_HDROP です。まず覚えたいのは、渡るのはファイル本体ではなく、フルパスの一覧という点です。

メモリブロックの先頭には DROPFILES 構造体があり、その後ろにNUL文字で区切ったパス文字列が並びます。最後に空文字列を置くため、終端は「二重NUL」になります。ヘッダーの pFiles はパスリストの開始オフセット、fWide は文字列がUnicodeかどうかを示します。3

[DROPFILESヘッダー: pFiles=パスリストの開始オフセット, fWide=1(Unicode)]
C:\data\a.txt(NUL)C:\data\b.txt(NUL)(NUL)

ネイティブコードではDragQueryFileで1件ずつ取り出し、.NETではDataFormats.FileDropとしてstring[]で受け取れます。「渡るのはパスだけで、ファイル本体ではない」という点は、8〜9章のD&Dでも効いてきます。

CF_HDROPのメモリブロック構造グローバルメモリの先頭にDROPFILES構造体があり、pFilesがパスリストの開始オフセットを、fWideがUnicodeかどうかを示す。続いてNUL区切りのフルパスが並び、最後は空文字列による二重NUL終端で終わる。渡るのはパスだけでファイル本体ではないDROPFILES構造体(pFiles = リスト開始オフセット / fWide = 1)C:\\data\\a.txt + NULC:\\data\\b.txt + NUL終端の空文字列(二重NUL)渡るのはパスだけで、ファイル本体ではない

3.3. 登録形式 ── RegisterClipboardFormatと「HTML Format」

標準形式で表現できないデータは、名前を決めて登録形式として共有できます。RegisterClipboardFormat に名前を渡すと形式IDが返ります。同じ名前で登録すれば、別のアプリでも同じIDを取得できるため、アプリ間で名前を合意しておくことが接点になります。1

自社アプリ群で構造化データを受け渡す場合は、KomuraSoft.Report.RowData のように衝突しない名前を付けます。

HTML Formatは「ヘッダー付きのUTF-8」

登録形式の代表が、RTFと並ぶ書式付きテキスト形式の「HTML Format」です。中身はUTF-8テキストですが、先頭にバイトオフセットを列挙するヘッダーが付いています。4

Version:0.9
StartHTML:<HTML全体の開始バイト位置>
EndHTML:<HTML全体の終了バイト位置>
StartFragment:<断片の開始バイト位置>
EndFragment:<断片の終了バイト位置>
<html><body>
<!--StartFragment--><b>太字の</b>断片テキスト<!--EndFragment-->
</body></html>

各オフセットの基準は、ヘッダー自身を含むデータの先頭です。StartHTML / EndHTML はHTML全体、StartFragment / EndFragment はユーザーが選択した断片の開始・終了を指します。単位は文字数ではなく、バイト数です。

生成するときは、次の順序で組み立てます。

  1. オフセット欄を固定桁(例: 10桁)で確保する。
  2. HTML本文を組み立て、UTF-8にエンコードする。
  3. エンコード後のバイト位置を実測し、ヘッダーへ書き戻す。

日本語を含むUTF-8では、文字数とバイト数が一致しません。ここを取り違えると、他アプリへの貼り付け時に先頭や末尾が欠けます。4

HTML Formatのヘッダーとオフセットの関係ヘッダーのStartHTMLとEndHTMLがHTML全体を、StartFragmentとEndFragmentがユーザーが選択した断片を、いずれもデータ先頭からのバイト位置で指す。UTF-8では文字数とバイト数がずれるため、エンコード後に実測したバイト位置で埋めるヘッダー(Version / StartHTML / EndHTML / StartFragment / EndFragment)HTML全体(StartHTML〜EndHTML)選択された断片(StartFragment〜EndFragment)各オフセット = データ先頭からのバイト位置(UTF-8エンコード後に実測して書き戻す)

このほか表形式データにはCSV(.NETのDataFormats.CommaSeparatedValue)もよく使われます。Excelとの相互運用では、HTML Format(書式付き)とCSV(値のみ)とCF_UNICODETEXT(タブ区切り)を併せて提供すると、貼り付け先を選びません。

4. 貼り付ける側の作法 ── 形式の優先順位と検証

4.1. リッチな形式から順に探す

貼り付け側は、自分が扱える形式のうち、最も情報量の多いものから探します。コピー側が表現力の高い順に置いた形式の並びを使う方法と、自分で優先順位を指定する方法があります。6

Win32 API 選び方
EnumClipboardFormats コピー側が置いた順に列挙し、最初に認識できた形式を使う
GetPriorityClipboardFormat 貼り付け側が渡した優先順リストから、利用できる形式を選ぶ

.NETなら次のような分岐になります。

// 表の貼り付け: リッチ→プレーンの順に探す
var data = Clipboard.GetDataObject();
if (data is null) return;

// 形式をうたっていても実体がstringとは限らない。型まで確認できたときだけ
// この枝を使い、ダメなら次の候補へ落とす
if (data.GetDataPresent(DataFormats.Html)
    && data.GetData(DataFormats.Html) is string html)
{
    // HTML Formatヘッダーを検証してから表として取り込む
}
else if (data.GetDataPresent(DataFormats.CommaSeparatedValue))
{
    // CSVとして取り込む
}
else if (data.GetDataPresent(DataFormats.UnicodeText))
{
    // タブ区切りテキストとして取り込む
}

「Excelの表を貼ると崩れる」という冒頭の相談への回答がこれです。プレーンテキストしか読まないアプリに表の構造は渡りません。どの形式まで受けるかは、貼り付け側の設計判断です。

リッチから順に探す貼り付けの分岐HTML Formatがあり実体も文字列なら表として取り込み、なければCSV、それもなければタブ区切りのテキストへと、表現力の高い形式から順に落としていく。どの候補もなければ受け入れないはいいいえはいいいえはいいいえ貼り付け開始HTML Formatがあり実体もstring?ヘッダーを検証して表として取り込むCSVがある?CSVとして取り込むUnicodeTextがある?タブ区切りテキストとして取り込む受け入れない

4.2. 貼り付けデータは外部入力である

見落とされがちですが、クリップボードの中身はどのアプリが置いたか分からない外部由来のデータです。MicrosoftもOLEクリップボードのドキュメントで「クリップボードのデータは信頼できない。アプリで使う前に注意深くパースせよ」と警告しています。5

形式が存在することだけでは、取り込み可能とは判断できません。実体の型も確認し、次の検証を通します。

検証するもの 確認内容
HTML Formatのヘッダー オフセットが範囲外を指していないか。壊れたヘッダーを出すアプリもある
数値・日付・コードなどの値 画面入力と同じバリデーションを通るか
データの大きさ 数百MBの画像や数百万行のテキストなど、受け入れ上限を超えていないか

サイズを調べる前に、実体化が始まる点に注意する

巨大データへの対策では、どの段階の負荷を防げるのかを区別します。.NETの GetData は呼び出し時に遅延レンダリングも起動し、テキストならマネージド文字列まで実体化します。取得後にサイズを確認するだけでは、その実体化の負荷を防げません。

Win32の GetClipboardData が返す HGLOBAL を GlobalSize で調べれば、巨大データをマネージド文字列への変換・解析へ進めないための防御はできます。ただし、遅延レンダリング形式では GetClipboardData 自体がレンダリングを起動します。コピー元でデータを実体化することそのものまでは防げません。

UIを固めないためには、取得処理をUIスレッドの外へ出し、上限を超えたデータは断ります。その場合も.NETの Clipboard はSTAが必須です。Task.Run のスレッドプール(MTA)ではなく、STAに設定した専用スレッドを使います(5.1節)。

「外部から入ってくる値は、経路がなんであれ検証してから使う」という考え方は「QRコードの読み取り値をそのまま使ってはいけない」で整理したものと同じです。貼り付けはユーザー操作なので安全、という思い込みが事故のもとになります。

貼り付けデータを検証してから使う流れクリップボードから取り出すデータは、形式の存在確認、実体の型の確認、サイズ上限、内容の検証を順に通し、どこかで不合格なら断るか次の候補形式へ落とす型が違う大きすぎる不正形式の存在を確認(GetDataPresent)実体の型を確認(is string / string[])サイズ上限を確認内容を検証(ヘッダー・パス・値)取り込む断る / 次の候補形式へ

5. コピーする側の作法 ── 複数形式の同時提供と遅延レンダリング

5.1. 複数形式を同時に置く

コピー側の作法は4.1の裏返しで、リッチな形式とプレーンな形式を同時に提供することです。WinForms/WPFのDataObjectを使えば数行で書けます。14

// WinForms(System.Windows.Forms)。WPFもSystem.WindowsのDataObject/Clipboardで同型
var data = new DataObject();
data.SetData(DataFormats.Html, htmlFormatText);       // ヘッダー付きHTML Format文字列
data.SetData(DataFormats.CommaSeparatedValue, csv);   // CSV
data.SetData(DataFormats.UnicodeText, plainText);     // プレーンテキスト
Clipboard.SetDataObject(data, copy: true);            // copy:true=アプリ終了後も残す

ここでは、スレッドと終了後の寿命を分けて確認します。

スレッドの条件: .NETの Clipboard クラスはSTAスレッドからしか使えません。14 WinForms/WPFのUIスレッドは [STAThread] でSTAになっているため通常は問題ありませんが、STAでないバックグラウンドスレッドからは使えません。背景は「COM STA/MTA の基礎知識」で説明しています。

終了後の寿命: copy: true は「アプリを終了した後も残す」指定です。次の遅延レンダリングと合わせて理解すると、なぜこの指定が必要なのかが分かります。

5.2. 遅延レンダリング ── 「閉じたら貼れない」の正体

多数の形式をコピーのたびにすべて生成すると、使われない形式のためにも処理が必要になります。それを避ける仕組みが遅延レンダリング(delayed rendering)です。6

コピー時には SetClipboardData のデータハンドルに NULL を渡し、データ本体ではなく「要求されたら作る」という約束を登録します。その形式が要求されると、コピー元へ WM_RENDERFORMAT が届き、そこで初めてデータを生成します。

終了時には「約束」をデータに変える

コピー元が未レンダリングの形式を残したまま終了すると、貼り付け側はそのデータを受け取れなくなります。これが「コピー元を閉じたら貼れない」問題です。

コピー元は終了前の WM_RENDERALLFORMATS に応答して、未レンダリングの全形式を実体化する責務があります。確定しなかった形式は、コピー元の終了とともに失われます。6

遅延レンダリングの流れと「閉じたら貼れない」コピー元はNULLハンドルで約束だけを置き、要求が来たらWM_RENDERFORMATで実体化する。終了時はWM_RENDERALLFORMATSで全形式を実体化する責務があり、怠るとその形式は失われるWM_RENDERALLFORMATSで実体化実体化を怠るコピー元: SetClipboardData(format, NULL)で「約束」だけ登録貼り付け側がその形式を要求WM_RENDERFORMAT → その場でデータ生成コピー元が終了しようとする終了後も貼り付け可能その形式は失われる(「閉じたら貼れない」)

OLEクリップボードでは、IDataObject を OleSetClipboard で置きます。この時点でクリップボードが保持するのは、データオブジェクトへのポインターです。

終了時に OleFlushClipboard を呼ぶと、データがクリップボード上に実体化され、終了後も貼り付けられます。7 .NETの Clipboard.SetDataObject(data, copy: true) は、この「終了後も残す」動きを指定します。

Excelで大きな範囲をコピーして終了するときに「クリップボードに大きな情報があります。保持しますか?」と聞かれるのは、この確定処理(フラッシュ)を行うかどうかの確認です。自作アプリでも、遅延レンダリングと終了時の確定処理をセットで設計します。

遅延させればUIが固まらない、とは限らない

遅延レンダリングは性能最適化ですが、要求されたデータの生成はメッセージ処理中に同期的に走ります。生成に時間がかかるとUIが固まる、というトレードオフがあります。6

6. クリップボード監視の作法 ── リスナー・リトライ・履歴除外

6.1. AddClipboardFormatListenerを使う

「バーコードリーダーの値や基幹システムからのコピーを検知して自動で取り込みたい」といった要件では、クリップボードの変更監視が必要になります。方法は歴史的に3つありますが、現在の正解は1つです。8

方法 評価
タイマーで定期的に読む(ポーリング) 無駄が多く検知漏れもある。使わない
SetClipboardViewer(ビューアーチェーン) チェーン内の1アプリの不具合が全体を壊す。後方互換のためだけに残存
AddClipboardFormatListener 推奨。登録したウィンドウにWM_CLIPBOARDUPDATEが届く
クリップボード監視の流れハンドル作成時にAddClipboardFormatListenerで登録すると、どのアプリがコピーしてもWM_CLIPBOARDUPDATEが届く。読み取りはリトライつきで行い、ハンドル破棄時にRemoveClipboardFormatListenerで対称に解除する対称に解除OnHandleCreated: AddClipboardFormatListener待機どのアプリかがコピーWM_CLIPBOARDUPDATEが届くリトライつきで読み取り(6.2節)OnHandleDestroyed: RemoveClipboardFormatListener
// WinFormsでの最小実装
public partial class MainForm : Form
{
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool AddClipboardFormatListener(IntPtr hwnd);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
    const int WM_CLIPBOARDUPDATE = 0x031D;

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        AddClipboardFormatListener(Handle);
    }

    protected override void OnHandleDestroyed(EventArgs e)
    {
        // ハンドルの破棄・再作成に合わせて対称に解除する
        RemoveClipboardFormatListener(Handle);
        base.OnHandleDestroyed(e);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_CLIPBOARDUPDATE)
        {
            // ここでClipboard.GetDataObject()を読み、必要な形式なら取り込む
        }
        base.WndProc(ref m);
    }
}

6.2. 開けないときはリトライする

クリップボードを開けるのは一度に1つのウィンドウだけです。他のプロセスが開いている間は OpenClipboard が失敗します。6

WM_CLIPBOARDUPDATE の直後も、コピー元や別の監視アプリが操作中かもしれません。一時的に読み取れないことは正常事象として扱い、数十ミリ秒ほどの短い待機を挟んで、数回リトライする処理を入れます。

.NETで注意したいのは、リトライ回数・間隔を指定できるオーバーロードが書き込み側の SetDataObject だけにあることです。読み取り側の GetDataObject などにはありません。

読み取り側 競合時の対応
WinForms ExternalException をcatchし、待機・再試行する
WPF COMException をcatchし、待機・再試行する

読み取りの待機・再試行は、アプリ側で実装します。

クリップボード読み取りリトライの流れクリップボードを開けるのは一度に1つのウィンドウだけなので、変更通知直後の読み取りは他プロセスと競合して失敗し得る。例外を受けたら数十ミリ秒待って再試行し、上限に達したら今回は諦めて次の更新で拾う成功失敗(他ウィンドウが使用中)数回まで再試行上限到達WM_CLIPBOARDUPDATE読み取りを試行取り込みへ(4章の検証)数十ミリ秒待機今回は諦める(次の更新で拾う)

6.3. 履歴・同期に載せない ── 機密を扱うコピー機能の配慮

Windowsにはクリップボード履歴(Win+V)とデバイス間同期(クラウドクリップボード)があり、アプリが置いたデータは既定でその対象になります。パスワードや口座番号のような機密をコピー機能に載せるアプリは、履歴・同期から除外するための登録形式を一緒に置きます。1

登録形式 抑止する対象
ExcludeClipboardContentFromMonitorProcessing そのコピー内容全体を履歴・デバイス間同期の両方から除外
CanIncludeInClipboardHistory (DWORD 0) 履歴のみ
CanUploadToCloudClipboard (DWORD 0) デバイス間同期のみ

パスワードマネージャーがコピーしたパスワードをWin+Vに残さないのは、この仕組みによるものです。名前をRegisterClipboardFormatに渡して形式IDを取得し、通常のデータと並べてセットするだけなので、機密を扱う業務アプリでは実装しておく価値があります。

7. 情シス視点のクリップボード ── 履歴・クラウド同期・RDPの制御

アプリ側がコピー内容を制御する話と、組織全体で許可する範囲の話は分けて考えます。管理者が見る対象は、履歴・クラウド同期・RDPリダイレクトの3つです。

クリップボード履歴は直近のコピー内容を蓄積します。クラウドクリップボードは、同じMicrosoftアカウント/Microsoft Entraアカウントでサインインしたデバイス間で同期します。10

便利な半面、基幹システムからコピーした個人情報が履歴に残る、業務PCのコピー内容が私物PCへ同期される、といった残留・越境が起きます。

7.1. 履歴とデバイス間同期を制御する

組織で制御するポリシーは次の2つです。

制御対象 GPO(コンピューターの構成 > 管理用テンプレート > システム > OSポリシー) Policy CSP(Intune) 既定
クリップボード履歴 クリップボードの履歴を許可する Experience/AllowClipboardHistory 許可
デバイス間同期 デバイス間でのクリップボードの同期を許可する Privacy/AllowCrossDeviceClipboard 許可

いずれもWindows 10 バージョン1809以降で利用でき、無効化すると設定アプリの該当項目がグレーアウトし、ポリシーは即時反映されます。910

7.2. RDPのセッション間転送を制御する

RDP(リモートデスクトップ)のクリップボードリダイレクトは、ローカルPCとリモートセッションの間を橋渡しします。既定ではコピペが通るため、サーバー上の機密を持ち出す経路にもなります。

双方向とも遮断する設定は、「クリップボードのリダイレクトを許可しない」ポリシー(レジストリ値 fDisableClip)です。11

近年のWindows Server/Windows 11には、サーバーからクライアントへの方向だけをテキストに限定するなど、より細かい制御のポリシーも追加されています。全面禁止にするか、方向や形式を段階的に制限するかは、運用とセキュリティのバランスで決めます。

クリップボードの内容が広がる経路と制御ポイントコピーした内容は既定で履歴とクラウド同期の対象になり、RDPではリダイレクトで別セッションへ渡る。それぞれポリシーで制御でき、アプリ側は除外形式で履歴と同期から外せるクリップボード履歴(Win+V)クラウド同期 → 別デバイスRDPリダイレクト → 別セッション制御: AllowClipboardHistory制御: AllowCrossDeviceClipboard制御: fDisableClipアプリ側: ExcludeClipboardContentFromMonitorProcessing等で除外(6.3節)

8. ドラッグ&ドロップの正体はCOM ── IDataObject+IDropSource+IDropTarget

8.1. クリップボードと同じデータ、違う運び方

OLEドラッグ&ドロップは、次の三者で動きます。15

役割 実装者 仕事
IDataObject ドラッグ元 運ばれるデータ本体。クリップボードと同じ複数形式のデータオブジェクト
IDropSource ドラッグ元 ドラッグ継続/中止の判断とカーソルフィードバック
IDropTarget ドロップ先 DragEnter/DragOver/DragLeave/Dropで受け入れ可否の表明と受け取り

操作の流れは次のとおりです。

  1. ドラッグ元が DoDragDrop を呼び、ドラッグのループを開始する。
  2. マウスがドロップ先ウィンドウに入ると、IDropTarget へ通知が届く。
  3. ドロップ先が受け入れ可否を表明し、ドロップ時に IDataObject から必要な形式を取り出す。

公式ドキュメントも、D&Dはクリップボードのコピー&ペーストと同じ機能を提供し、コピペ実装済みのアプリなら追加はわずかだと説明しています。15 2〜5章で用意した複数形式のDataObjectが、D&Dでも運ぶデータになるということです。

OLEドラッグ&ドロップの流れドラッグ元がIDataObjectを荷物にDoDragDropを呼んでドラッグのループが始まり、ドロップ先のIDropTargetがDragEnterとDragOverで受け入れ可否を表明し、DropでIDataObjectから形式を選んで取り出すDoDragDropマウスがウィンドウに入るボタンを離すドラッグ元: IDataObject + IDropSourceドラッグのループIDropTarget.DragEnter/DragOver(Effectを毎回表明)IDropTarget.DropIDataObjectから形式を選んで取り出す

8.2. OleInitialize(STA)が必須

ドロップ先ウィンドウは RegisterDragDrop で登録します。その前提として、OLEの初期化とメッセージ処理の2点を確認してください。

初期化には OleInitialize を使います。 CoInitialize / CoInitializeEx を代わりに使っただけでは、RegisterDragDrop は E_OUTOFMEMORY で失敗します。OleInitialize はCOMをSTAとして初期化します。12

登録したスレッドはメッセージポンプを回す必要があります。 OLE D&Dはウィンドウとメッセージ処理に根差した機能で、これを怠るとドラッグ中の他アプリがハングします。12 背景は「COM STA/MTA の基礎知識」のスレッドモデルと同じです。

WinForms/WPFではイベントで受け取る

WinForms/WPFでは、フレームワークがOLE初期化とインターフェース実装を肩代わりします。開発者は、受け入れ可否の表明と実際の取り込みをイベントに書きます。

// WinForms: ファイルのドロップを受け取る
listView1.AllowDrop = true;
listView1.DragEnter += (s, e) =>
{
    // ソース側がCopyを許可していることも確認する(Move/Linkしか許さないソースもある)
    e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
            && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy
        ? DragDropEffects.Copy      // 受け入れ可: コピーとして受ける
        : DragDropEffects.None;     // 受け入れ不可
};
listView1.DragDrop += (s, e) =>
{
    // ドラッグデータも外部入力。FileDropをうたっていても実体がnullや
    // 別の型のことがあり、取得自体が失敗することもある
    object data;
    try { data = e.Data.GetData(DataFormats.FileDrop); }
    catch (COMException) { return; }
    if (data is not string[] paths) return;
    foreach (var path in paths)
    {
        // パスを検証してから取り込む(9.3節)
    }
};

WPFでも構図は同じです。要素の AllowDrop="True" と DragOver / Drop イベントで受け、e.Data.GetData(DataFormats.FileDrop) でパス配列を取り出します。

DragEnter / DragOver で受け入れ可否(Effect)を毎回表明するのが IDropTarget の流儀です。ここを省くと、カーソルが「禁止」のまま変わりません。形式の有無だけでなく、コード例のようにドラッグ元が Copy を許可しているかも確認します。

9. D&Dの落とし穴 ── 昇格・Move・パスの検証

9.1. 管理者昇格したアプリにはドロップできない

「管理者として実行」したアプリに、エクスプローラーからファイルをドロップしても反応しない ── これは実装ミスではなくOSの仕様です。UIPI(User Interface Privilege Isolation)が、低い整合性レベルのプロセスから高い整合性レベルのウィンドウへのメッセージを既定で遮断するためで、通常権限(中整合性)のエクスプローラーから昇格アプリへはドロップの通知が届きません。13

昇格アプリへのドロップがUIPIに遮断される仕組み中整合性のエクスプローラーから高整合性の昇格アプリへのドロップ通知はUIPIが既定で遮断するため届かない。UIを通常権限に保ち特権処理を分離すればドロップは届くドロップ通知遮断(既定)通過特権処理だけ依頼エクスプローラー(中整合性)UIPI昇格アプリ(高整合性): 無反応通常権限のUI: ドロップが届く昇格が必要な処理を分離した別プロセス

ChangeWindowMessageFilterEx で WM_DROPFILES などを個別に許可する回避策もあります。13 ただし、これは旧式の WM_DROPFILES によるドロップ通知への対策で、OLE D&D全体を解決するものではありません。

根本的な指針は、アプリを常時昇格で動かさないことです。昇格が必要な処理だけを別プロセスへ分離すれば、UI本体は通常権限のままD&Dを受けられます。分離の設計は「Windowsアプリの管理者権限とブローカープロセス」で詳述しています。

9.2. DragDropEffectsの意味 ── Moveは「元が消える」契約

DragDropEffects の Copy / Move / Link は、カーソルの飾りではなく、ドラッグ元とドロップ先の契約です。

ドラッグ元が DoDragDrop で許可する効果の集合を宣言し、ドロップ先が実際の効果を選びます。Move が成立すると、ドラッグ元がデータ(ファイル)を削除するのが規約です。

受け側が考えずに Move を返すと、「ドロップしたら元のファイルが消えた」という事故になります。業務アプリの取り込みでは、受け側は Copy を明示するのを安全側の既定にします。

DragDropEffectsの契約 ── Moveでは元が消えるドラッグ元がDoDragDropで許可する効果の集合を宣言し、ドロップ先が実際の効果を選ぶ。Moveが成立するとドラッグ元がファイルを削除する規約のため、取り込み用途の受け側はCopyを明示するのが安全CopyMoveドラッグ元: 許可する効果を宣言(Copy | Move | Link)ドロップ先: 実際の効果を選ぶ元ファイルは残る(取り込み用途の安全側)ドラッグ元がファイルを削除 ──「元が消えた」事故のもと

9.3. ドロップされたパスの検証

CF_HDROP/FileDropで渡るのはパスだけです(3.2節)。取り込む前に、貼り付けと同じく外部入力としての検証を通します。

  • ファイルかフォルダーか: フォルダーごとドロップされるケースを仕様として決めておく(再帰で取り込むのか、断るのか)。
  • OneDriveのプレースホルダー: パスは存在してもファイル本体がローカルにない「オンデマンドファイル」の場合、開いた瞬間にダウンロードが走り、オフラインなら失敗します。挙動と対策は「OneDrive「ファイル オンデマンド」と業務アプリ」を参照してください。
  • 長いパス・特殊なパス: MAX_PATH超のパス、ネットワーク(UNC)パス、リムーバブルメディア上のパスは、後続処理が対応できるかを確認してから受け入れます。
  • 件数と合計サイズ: 数千ファイルのドロップでUIが固まらないよう、取り込みは非同期化し、上限や進捗表示を設けます。

10. まとめ

  • クリップボードは同じデスクトップ(ウィンドウステーション)内で共有される1つの領域に、同じ内容を複数の形式で同時に置く仕組みです。貼り付け先が形式を選ぶため、同じコピーでも結果が変わります。
  • テキストはCF_UNICODETEXT、ファイルはCF_HDROP、書式付きテキストは登録形式のHTML Format(バイトオフセットヘッダー+UTF-8)です。
  • 貼り付ける側はリッチ→プレーンの順に形式を探し、中身は外部入力として検証します。コピーする側は複数形式を同時に提供し、遅延レンダリングを使うなら終了時の確定(WM_RENDERALLFORMATS/OleFlushClipboard)までを実装します。
  • 監視はAddClipboardFormatListener+WM_CLIPBOARDUPDATE。OpenClipboardの競合にはリトライで備え、機密はExcludeClipboardContentFromMonitorProcessing等で履歴・同期から除外します。
  • 情シスはクリップボード履歴・クラウド同期・RDPリダイレクトをGPO/Intuneで制御できます。既定はすべて許可なので、機密を扱う環境では意識的に判断してください。
  • D&Dの正体はCOMで、クリップボードと同じIDataObjectをIDropSource/IDropTargetが受け渡します。RegisterDragDropはOleInitialize(STA)が必須です。
  • 昇格アプリへのドロップはUIPIで遮断されます。DragDropEffectsのMoveは「元が消える」契約、ドロップされたパスは検証してから取り込みます。

コピペとD&Dは、ユーザーにとっては空気のような機能です。だからこそ、「貼れない」「崩れる」「消えた」が起きたときの体験の悪化は大きく、逆に複数形式の提供とドロップ対応が行き届いたアプリは、それだけで日々の操作が滑らかになります。改修の優先順位を考える際の判断材料になれば幸いです。

関連記事

関連する相談領域

合同会社小村ソフトでは、業務アプリへのコピー&ペースト・ドラッグ&ドロップ対応の設計と実装(複数形式の提供、Excel連携、ファイルドロップ取り込み)、「貼り付けると崩れる」「コピーが消える」といった不具合の原因調査、クリップボード監視を使った入力自動化、機密情報の履歴・同期対策の実装を扱っています。COMやOLEの低レイヤーが絡む案件も、現象の切り分けからで構いません。

参考リンク

  1. Microsoft Learn, Clipboard Formats. ウィンドウが同じ情報を複数のクリップボード形式で置けること、RegisterClipboardFormatによる登録形式(同名の登録は同じ値を返しアプリ間で共有できる)、合成形式、ExcludeClipboardContentFromMonitorProcessing・CanIncludeInClipboardHistory・CanUploadToCloudClipboardによるクリップボード履歴/クラウド同期からの除外について。 ↩ ↩2 ↩3 ↩4

  2. Microsoft Learn, Standard Clipboard Formats. CF_TEXT(ANSI)・CF_UNICODETEXT・CF_HDROP・CF_DIB・CF_LOCALEなど標準形式の定義と、CF_LOCALEに関連付いたコードページを使ってCF_TEXTとCF_UNICODETEXTがシステムにより暗黙変換されることについて。 ↩ ↩2 ↩3

  3. Microsoft Learn, Shell Clipboard Formats. CF_HDROPがDROPFILES構造体と二重NUL終端のフルパス文字列配列で構成されること、DragQueryFileによる個別パスの取り出し、CFSTR_系のシェル形式がRegisterClipboardFormatによる登録を要することについて。 ↩ ↩2

  4. Microsoft Learn, HTML Clipboard Format. 登録名が「HTML Format」であること、Version・StartHTML・EndHTML・StartFragment・EndFragmentなどのオフセット(バイト単位)を持つヘッダー構造、エンコーディングが常にUTF-8であること、StartFragment/EndFragmentコメントの規約について。 ↩ ↩2 ↩3

  5. Microsoft Learn, OleGetClipboard function (ole2.h). クリップボードからIDataObjectを取得する方法と、「クリップボードのデータは信頼できないため、アプリで使う前に注意深くパースすべき」という警告について。 ↩ ↩2

  6. Microsoft Learn, Clipboard Operations. クリップボードを開けるのは一度に1ウィンドウだけであること、コピー時に表現力の高い形式から順に置くこと、貼り付け時のEnumClipboardFormats/GetPriorityClipboardFormatによる形式選択、SetClipboardDataにNULLを渡す遅延レンダリングとWM_RENDERFORMAT/WM_RENDERALLFORMATSの責務、遅延レンダリングのトレードオフについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  7. Microsoft Learn, OleFlushClipboard function (ole2.h). OleSetClipboardではクリップボードがデータオブジェクトへのポインターのみを保持すること、OleFlushClipboardがデータをクリップボード上に実体化してアプリ終了後の貼り付けを可能にすること、終了時に残す必要がなければOleSetClipboard(NULL)で空にすべきことについて。 ↩ ↩2

  8. Microsoft Learn, Using the clipboard. クリップボード監視の3方式(ビューアーウィンドウ・シーケンス番号・フォーマットリスナー)の比較、新規プログラムはAddClipboardFormatListenerによるリスナーを使うべきこと、ビューアーチェーンがチェーン維持の不備に脆弱なこと、シーケンス番号をポーリングに使うべきでないことについて。 ↩ ↩2

  9. Microsoft Learn, Policy CSP - Experience. Experience/AllowClipboardHistoryポリシーによるクリップボード履歴の許可/禁止、Windows 10 バージョン1809以降で利用可能なこと、既定が許可であること、GPOでは「システム > OSポリシー」配下にマップされ変更が即時反映されることについて。 ↩ ↩2

  10. Microsoft Learn, Policy CSP - Privacy. Privacy/AllowCrossDeviceClipboardポリシーによるデバイス間クリップボード同期の許可/禁止、同期が同一のMicrosoftアカウント/Microsoft Entraアカウントでサインインしたデバイス間で行われること、既定が許可であることについて。 ↩ ↩2 ↩3

  11. Microsoft Learn, Policy CSP - ADMX_TerminalServer. TS_CLIENT_CLIPBOARD(「クリップボードのリダイレクトを許可しない」、レジストリ値fDisableClip)により、リモートデスクトップセッションでのローカル/リモート間のクリップボード共有を禁止できること、既定ではリダイレクトが許可されることについて。 ↩ ↩2

  12. Microsoft Learn, RegisterDragDrop function (ole2.h). ドロップ先ウィンドウとIDropTargetの登録方法、COMをCoInitialize/CoInitializeExで初期化した場合は常にE_OUTOFMEMORYで失敗しOleInitializeが必要なこと、呼び出しスレッドがメッセージポンプを回していないとドラッグ元アプリがハングすることについて。 ↩ ↩2 ↩3

  13. Microsoft Learn, ChangeWindowMessageFilterEx function (winuser.h). UIPIが低い整合性レベルの送信元からのメッセージ受信を既定で遮断するセキュリティ機構であること、ウィンドウ単位のメッセージフィルターで特定メッセージを許可(MSGFLT_ALLOW)できることについて。 ↩ ↩2 ↩3

  14. Microsoft Learn, How to add data to the Clipboard (Windows Forms). DataObjectとClipboard.SetDataObjectで複数形式のデータを同時に置く方法、他アプリが認識できるよう複数形式で追加すべきこと、ClipboardクラスがSTAスレッドからのみ使用でき[STAThread]が必要なことについて。 ↩ ↩2

  15. Microsoft Learn, Drag and Drop (COM). OLEドラッグ&ドロップがIDropSource(ドラッグ元)・IDropTarget(ドロップ先)・DoDragDrop(OLE提供のループ)の三者で動くこと、クリップボードのコピー&ペーストと同一の機能を提供しコピペ実装済みアプリなら追加がわずかであること、フィードバックの種類について。 ↩ ↩2

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

Excelからコピーした表をアプリに貼り付けると書式が崩れるのはなぜですか?
クリップボードには「1つのデータ」ではなく、同じ内容が複数の形式(アプリ独自形式、HTML Format、CSV、Unicodeテキストなど)で同時に置かれており、貼り付け先のアプリが自分の理解できる形式を選んで取り出すからです。書式が崩れる場合、貼り付け先がプレーンテキスト(CF_UNICODETEXT)しか読んでいないのが典型です。表の構造まで受け取りたければ、貼り付け側でHTML FormatやCSV形式を優先して取り出す実装にします。逆に自アプリからのコピーで他アプリに正しく貼らせたい場合は、コピー時にリッチな形式とプレーンな形式を同時に提供します。
コピー元のアプリを閉じると貼り付けられなくなるのはなぜですか?
コピー元が遅延レンダリング(delayed rendering)を使っているためです。大きなデータを扱うアプリは、コピー時にはデータ本体を置かず「要求されたら作る」という約束だけをクリップボードに登録します。この状態でコピー元が、終了時のWM_RENDERALLFORMATSに応答してデータを確定しないまま終了すると、未レンダリングの形式は失われます。OLEクリップボード(IDataObject)を使うアプリなら、終了時にOleFlushClipboardを呼んでデータを実体化しておくことで、終了後も貼り付け可能な状態を維持できます。
自作アプリからクリップボードの変更を監視するにはどうすればよいですか?
AddClipboardFormatListenerで自分のウィンドウをリスナーとして登録し、内容が変わるたびに届くWM_CLIPBOARDUPDATEメッセージを処理するのが現在の推奨方法です。タイマーで定期的に内容を読むポーリングは無駄が多く、SetClipboardViewerによる旧来のビューアーチェーンは、チェーン内の1つのアプリの不具合が全体を壊すため後方互換のためだけに残されています。なお読み取り時のOpenClipboardは他プロセスと競合して失敗し得るので、短い待機を挟んだリトライを実装しておくと安定します。
パスワードなどの機密情報をクリップボード履歴(Win+V)に残さない方法はありますか?
アプリ側とポリシー側の2つの手段があります。アプリ側では、コピー時にExcludeClipboardContentFromMonitorProcessingという登録形式を一緒に置くと、その内容は履歴にもデバイス間同期にも含まれません。CanIncludeInClipboardHistory(履歴のみ)やCanUploadToCloudClipboard(同期のみ)で個別制御もできます。パスワードマネージャーが使っているのはこの仕組みです。組織全体で止めたい場合は、グループポリシーやIntune(Policy CSP)のAllowClipboardHistory・AllowCrossDeviceClipboardで履歴・クラウド同期そのものを無効化できます。
管理者として実行したアプリにファイルをドラッグ&ドロップできないのはなぜですか?
UIPI(User Interface Privilege Isolation)というセキュリティ機構が、低い整合性レベルのプロセスから高い整合性レベルのウィンドウへのメッセージ送信を遮断するためです。エクスプローラーは通常権限(中整合性)で動いているので、昇格したアプリのウィンドウにはドラッグ&ドロップの通知が届きません。ChangeWindowMessageFilterExでWM_DROPFILESなどを個別に許可する回避策も知られていますが、旧式のドロップ通知に限られます。根本的には、アプリを常時昇格で動かす設計をやめ、昇格が必要な処理だけを別プロセスに分離するのが正攻法です。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る