Excel VBA 逆引き集 | クリップボード操作

Excel VBA
スポンサーリンク
  1. ねらい:VBAでクリップボードを自在に操り、貼り付け・共有をスマートにする
    1. 重要ポイントの深掘り
  2. 文字列のコピー&取得:最短はMSForms.DataObject、厳密はWin32 API
    1. DataObjectで「簡単に」テキストを置く・取る
    2. 重要ポイントの深掘り
  3. UnicodeテキストをWin32 APIで扱う:CF_UNICODETEXTを直接操作
    1. 64ビット対応の宣言と安全ラッパ
    2. 重要ポイントの深掘り
  4. 範囲のコピーをUIなしで扱う:Copyで入れて、Textで取り出す
    1. 選択範囲をコピーしてクリップボードからテキストを取り出す
    2. 重要ポイントの深掘り
  5. HTMLを貼り付ける:CF_HTML仕様の最小テンプレ
    1. HTMLフラグメントをクリップボードへ置く
    2. 重要ポイントの深掘り
  6. 画像のコピーと保存:Range.CopyPictureと貼付先活用
    1. Rangeを画像としてコピーし、ファイルへ保存する
    2. 重要ポイントの深掘り
  7. 共通運用枠:開始・終了で必ず戻し、UIを固めない
    1. 枠のテンプレ(全処理で使い回す)
    2. 重要ポイントの深掘り
  8. 例題の通し方と確認ポイント
    1. 文字列・範囲・HTML・画像の一通りを試す
    2. 現場の貼付先で挙動を検証する
  9. 落とし穴と対策(深掘り)
    1. 64ビット非対応の宣言でクラッシュする
    2. クリップボードが他プロセスにロックされている
    3. HTML仕様のズレ
    4. 画像の直接API操作は難度が高い
  10. まとめ:用途別に「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対応の基本を守れば、貼り付け・共有・保存の一連が安定します。

タイトルとURLをコピーしました