- ねらい:VBAでクリップボードを自在に操り、貼り付け・共有をスマートにする
- 文字列のコピー&取得:最短はMSForms.DataObject、厳密はWin32 API
- UnicodeテキストをWin32 APIで扱う:CF_UNICODETEXTを直接操作
- 範囲のコピーをUIなしで扱う:Copyで入れて、Textで取り出す
- HTMLを貼り付ける:CF_HTML仕様の最小テンプレ
- 画像のコピーと保存:Range.CopyPictureと貼付先活用
- 共通運用枠:開始・終了で必ず戻し、UIを固めない
- 例題の通し方と確認ポイント
- 落とし穴と対策(深掘り)
- まとめ:用途別に「Text/HTML/画像」を選び、簡易はDataObject、厳密はAPIで
ねらい:VBAでクリップボードを自在に操り、貼り付け・共有をスマートにする
クリップボード操作は「選択範囲をコピーして他アプリへ」「文字列やHTMLを生成して貼り付け」「画像を取り込んで保存」など、現場の効率化に直結します。Excel標準のCopy/Pasteに頼るとUIが固まりがちなので、DataObject(MSForms)やWin32 API(Unicode対応、64ビット対応)を併用し、対話を挟まず確実にやり取りできる“枠+テンプレ”で解説します。
重要ポイントの深掘り
クリップボードは「形式ごとの箱」を持っています。文字列はUnicodeテキスト(CF_UNICODETEXT)、HTMLはCF_HTML仕様、画像はビットマップやPNGなどのハンドル形式です。VBAでは用途に応じて「簡単に済むDataObject」「細かく制御するWin32 API」を使い分けるのがコツです。開始・終了の共通枠を徹底し、失敗時でもExcelが確実に元に戻る構造で扱います。
文字列のコピー&取得:最短はMSForms.DataObject、厳密はWin32 API
DataObjectで「簡単に」テキストを置く・取る
' 参照設定なし(Late Binding)でも可
' ModClipboardText.bas
Option Explicit
Public Sub ClipboardSetText(ByVal s As String)
Dim dobj As Object
Set dobj = CreateObject("Forms.DataObject")
dobj.SetText s
dobj.PutInClipboard
End Sub
Public Function ClipboardGetText() As String
Dim dobj As Object
Set dobj = CreateObject("Forms.DataObject")
On Error Resume Next
dobj.GetFromClipboard
ClipboardGetText = dobj.GetText
On Error GoTo 0
End Function
Sub Demo_Text()
ClipboardSetText "こんにちは、Excel。"
MsgBox ClipboardGetText
End Sub
VB重要ポイントの深掘り
DataObjectは「文字列専用の最短ルート」。Unicodeも扱え、参照設定不要のLate Bindingで安全です。大量呼び出しでもUIを固めず、MsgBoxなしのヘッドレス処理に向きます。ただし、HTMLや画像の形式制御はできないため、そこはAPIへ任せます。
UnicodeテキストをWin32 APIで扱う:CF_UNICODETEXTを直接操作
64ビット対応の宣言と安全ラッパ
' ModWinClipboard.bas
Option Explicit
#If VBA7 Then
Public Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWndNewOwner As LongPtr) As Long
Public Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Public Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Public Declare PtrSafe Function SetClipboardData Lib "user32" (ByVal uFormat As Long, ByVal hMem As LongPtr) As LongPtr
Public Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal uFormat As Long) As LongPtr
Public Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal dwBytes As LongPtr) As LongPtr
Public Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Public Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Public Declare PtrSafe Function lstrcpyW Lib "kernel32" (ByVal lpStrDest As LongPtr, ByVal lpStrSrc As LongPtr) As LongPtr
#Else
' 32bit用宣言(省略可:現代は64bit前提推奨)
#End If
Public Const CF_UNICODETEXT As Long = 13
Public Const GMEM_MOVEABLE As Long = &H2
Public Sub ClipboardSetUnicodeText(ByVal s As String)
If OpenClipboard(0) = 0 Then Exit Sub
EmptyClipboard
Dim bytes As LongPtr
bytes = (Len(s) + 1) * 2 ' 末尾NUL含むUTF-16LEバイト数
Dim hMem As LongPtr: hMem = GlobalAlloc(GMEM_MOVEABLE, bytes)
If hMem <> 0 Then
Dim p As LongPtr: p = GlobalLock(hMem)
If p <> 0 Then
lstrcpyW p, StrPtr(s)
GlobalUnlock hMem
SetClipboardData CF_UNICODETEXT, hMem
End If
End If
CloseClipboard
End Sub
Public Function ClipboardGetUnicodeText() As String
If OpenClipboard(0) = 0 Then Exit Function
Dim hMem As LongPtr: hMem = GetClipboardData(CF_UNICODETEXT)
If hMem <> 0 Then
Dim p As LongPtr: p = GlobalLock(hMem)
If p <> 0 Then
ClipboardGetUnicodeText = PtrToStringW(p)
GlobalUnlock hMem
End If
End If
CloseClipboard
End Function
Private Function PtrToStringW(ByVal p As LongPtr) As String
' NUL終端まで読み込む簡易版
Dim buf As String: buf = String$(1024, vbNullChar)
Dim tmp As String
tmp = Left$(buf, InStr(buf, vbNullChar) - 1)
PtrToStringW = tmp ' 簡易。厳密に可変長を扱う場合は再読込ロジックに拡張
End Function
VB重要ポイントの深掘り
APIは「形式を明示し、メモリを自分で用意する」作法です。CF_UNICODETEXTを使えば、Excel外でも確実に文字化けなく貼れます。OpenClipboard→Empty→GlobalAlloc→SetClipboardData→CloseClipboardの手順を崩さないこと、64ビットではPtrSafeとLongPtrを厳守することが安定の鍵です。
範囲のコピーをUIなしで扱う:Copyで入れて、Textで取り出す
選択範囲をコピーしてクリップボードからテキストを取り出す
' ModRangeToClipboard.bas
Option Explicit
Public Function SelectedRangeText() As String
Dim rng As Range: Set rng = Selection
If rng Is Nothing Then Exit Function
rng.Copy
Application.Wait Now + TimeValue("0:00:01") ' 少し待つと安定
SelectedRangeText = ClipboardGetText() ' DataObject利用
End Function
Sub Demo_SelectedRangeText()
Dim t As String: t = SelectedRangeText()
Debug.Print t
End Sub
VB重要ポイントの深掘り
ExcelのCopyは「複数形式」をクリップボードへ置きます。Text形式はDataObjectのGetTextでも取得可能。巨大範囲は配列I/Oで自分でCSVテキストを組む方が速く、クリップボードを経由しない作戦も有効です。
HTMLを貼り付ける:CF_HTML仕様の最小テンプレ
HTMLフラグメントをクリップボードへ置く
' ModHtmlClipboard.bas
Option Explicit
Public Sub ClipboardSetHtml(ByVal html As String)
Dim header As String
Dim startHTML As Long, endHTML As Long
startHTML = 97 ' 固定でも可。厳密には計算して位置指定
endHTML = startHTML + Len(html)
header = "Version:0.9" & vbCrLf & _
"StartHTML:" & Format(startHTML, "00000000") & vbCrLf & _
"EndHTML:" & Format(endHTML, "00000000") & vbCrLf & _
"StartFragment:" & Format(startHTML, "00000000") & vbCrLf & _
"EndFragment:" & Format(endHTML, "00000000") & vbCrLf
Dim payload As String
payload = header & html
ClipboardSetText payload ' DataObjectでテキストとして置く(貼付先がCF_HTMLを解釈する場合に有効)
End Sub
Sub Demo_Html()
Dim html As String
html = "<html><body><b>太字</b>と<i>斜体</i></body></html>"
ClipboardSetHtml html
End Sub
VB重要ポイントの深掘り
CF_HTMLは「ヘッダーでHTMLの開始・終了位置を教える」仕様です。厳密運用ではCF_HTMLの専用フォーマットとして登録する必要がありますが、多くの編集先がテキストCF_HTMLも解釈します。Office間で装飾を保ちたい場合は、範囲コピーの方が安定することもあります。
画像のコピーと保存:Range.CopyPictureと貼付先活用
Rangeを画像としてコピーし、ファイルへ保存する
' ModImageClipboard.bas
Option Explicit
Public Sub CopySelectionAsImageAndSave(ByVal outPath As String)
Dim rng As Range: Set rng = Selection
If rng Is Nothing Then Exit Sub
rng.CopyPicture xlScreen, xlPicture
Dim chartObj As ChartObject
Set chartObj = Worksheets("Temp").ChartObjects.Add(Left:=10, Top:=10, Width:=rng.Width, Height:=rng.Height)
chartObj.Chart.Paste
chartObj.Chart.Export Filename:=outPath, FilterName:="PNG"
chartObj.Delete
MsgBox "画像保存: " & outPath
End Sub
VB重要ポイントの深掘り
画像は「クリップボード経由で他形式を扱うより、Excel側で貼り付け→Export」が堅牢です。CopyPictureは図形化の安定手段。APIでビットマップハンドルを直接扱うのはVBAでは難度が高いため、実務はこのルートを推奨します。
共通運用枠:開始・終了で必ず戻し、UIを固めない
枠のテンプレ(全処理で使い回す)
' ModApp.bas
Option Explicit
Public Sub AppEnter(Optional ByVal status As String = "")
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
If Len(status) > 0 Then Application.StatusBar = status
End Sub
Public Sub AppLeave()
Application.StatusBar = False
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VB重要ポイントの深掘り
クリップボード操作は「待ち」が絡み、イベント発火や描画と競合しがちです。開始・終了枠で揺らぎを減らし、短いWaitを要所で入れると安定します。失敗時でもAppLeaveが必ず到達する構造にして、現場を固めないことが最優先です。
例題の通し方と確認ポイント
文字列・範囲・HTML・画像の一通りを試す
最初にClipboardSetText/ClipboardGetTextで日本語の往復が正しく動くかを確認します。次にSelectedRangeTextで選択範囲のテキスト化、ClipboardSetHtmlで装飾貼り付けの可否、CopySelectionAsImageAndSaveでPNG保存の動作を確かめます。必要に応じてClipboardSetUnicodeTextに切り替え、CF_UNICODETEXTで他アプリへの貼り付けの互換を取ります。
現場の貼付先で挙動を検証する
Teams、Outlook、Word、ブラウザなど、貼付先ごとに受け取る形式が異なります。Textしか受けないか、HTMLを解釈するか、画像が必要かを見極め、テンプレのルート(Text/HTML/画像)を使い分けると、壊れにくい連携が作れます。
落とし穴と対策(深掘り)
64ビット非対応の宣言でクラッシュする
Win32 APIは必ずPtrSafe+LongPtrで宣言します。古いサンプルをそのまま貼らないこと。
クリップボードが他プロセスにロックされている
OpenClipboardが失敗する場合があります。短時間のリトライや、Excel標準のCopyを先に落ち着かせるWaitが有効です。
HTML仕様のズレ
CF_HTMLはヘッダーの位置番号が厳密です。簡易ヘッダーで済む先もありますが、重要な現場では正確に算出・設定してください。装飾を確実に保つならOffice間は範囲コピーが王道です。
画像の直接API操作は難度が高い
ビットマップハンドルやDIBをVBAで扱うのは複雑です。ExcelのChart.Exportや、PowerShell/外部ツールに委譲するルートを選ぶと保守が楽になります。
まとめ:用途別に「Text/HTML/画像」を選び、簡易はDataObject、厳密はAPIで
テキストはDataObjectが最短、互換を最大化するならCF_UNICODETEXTをAPIで。HTMLはCF_HTMLの枠で、画像はCopyPicture→Exportで。開始・終了枠、短いWait、64ビット・Unicode対応の基本を守れば、貼り付け・共有・保存の一連が安定します。
